ability to copy phrase selection code

This commit is contained in:
lingdocs 2022-05-30 15:59:44 -05:00
parent dc0cd48015
commit cab6528a6c
4 changed files with 126 additions and 19 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@lingdocs/pashto-inflector",
"version": "2.6.8",
"version": "2.6.9",
"author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com",

View File

@ -13,6 +13,9 @@ import { completeEPSelection } from "../../lib/phrase-building/render-ep";
import { makeEPSBlocks, getSubjectSelection } from "../../lib/phrase-building/blocks-utils";
import APPicker from "../ap-picker/APPicker";
import autoAnimate from "@formkit/auto-animate";
// @ts-ignore
import LZString from "lz-string";
const phraseURLParam = "EPhrase";
const blankEps: T.EPSelectionState = {
blocks: makeEPSBlocks(),
@ -37,10 +40,22 @@ function EPExplorer(props: {
const [mode, setMode] = useStickyState<"charts" | "phrases">("charts", "EPExplorerMode");
const [eps, adjustEps] = useStickyReducer(epsReducer, blankEps, "EPState4", flashMessage);
const [alert, setAlert] = useState<string | undefined>(undefined);
const [showClipped, setShowClipped] = useState<string>("");
const parent = useRef<HTMLDivElement>(null);
useEffect(() => {
parent.current && autoAnimate(parent.current);
}, [parent]);
useEffect(() => {
const EPSFromUrl = getEPSFromUrl();
if (EPSFromUrl) {
setMode("phrases");
adjustEps({
type: "load EPS",
payload: EPSFromUrl,
});
}
// eslint-disable-next-line
}, []);
const subject = getSubjectSelection(eps.blocks).selection;
const king = subject?.type === "pronoun"
? "subject"
@ -53,9 +68,26 @@ function EPExplorer(props: {
setAlert(undefined);
}, 1500);
}
function flashClippedMessage(m: string) {
setShowClipped(m);
setTimeout(() => {
setShowClipped("");
}, 1250);
}
function handleCopyCode() {
const code = getCode(eps);
navigator.clipboard.writeText(code);
flashClippedMessage("Copied phrase code to clipboard");
}
function handleCopyShareLink() {
const shareUrl = getShareUrl(eps);
navigator.clipboard.writeText(shareUrl);
flashClippedMessage("Copied phrase URL to clipboard");
}
const phraseIsComplete = !!completeEPSelection(eps);
return <div>
<div className="mt-2 mb-3 text-center">
<div className="mt-2 mb-3 d-flex flex-row justify-content-between align-items-center">
<div />
<ButtonSelect
value={mode}
options={[
@ -64,6 +96,22 @@ function EPExplorer(props: {
]}
handleChange={setMode}
/>
<div className="d-flex flex-row">
<div
className="clickable mr-4"
onClick={mode === "phrases" ? handleCopyCode : undefined}
style={{ width: "1rem" }}
>
{(mode === "phrases" && phraseIsComplete) ? <i className="fas fa-code" /> : ""}
</div>
<div
className="clickable"
onClick={mode === "phrases" ? handleCopyShareLink : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
</div>
</div>
</div>
{mode === "phrases" && <div className="clickable h5" onClick={() => adjustEps({ type: "insert new AP" })}>+ AP</div>}
<div ref={parent} className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
@ -160,7 +208,39 @@ function EPExplorer(props: {
}}>
{alert}
</div>}
{showClipped && <div className="alert alert-primary text-center" role="alert" style={{
position: "fixed",
top: "30%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 9999999999999,
}}>
{showClipped}
</div>}
</div>;
}
export default EPExplorer;
function getShareUrl(eps: T.EPSelectionState): string {
const code = getCode(eps);
const encoded = LZString.compressToEncodedURIComponent(code);
const url = new URL(window.location.href);
// need to delete or else you could just get a second param written after
// which gets ignored
url.searchParams.delete(phraseURLParam);
url.searchParams.append(phraseURLParam, encoded);
return url.toString();
}
function getCode(eps: T.EPSelectionState): string {
return JSON.stringify(eps);
}
function getEPSFromUrl(): T.EPSelectionState | undefined {
const params = new URLSearchParams(window.location.search);
const fromParams = params.get(phraseURLParam);
if (!fromParams) return;
const decoded = LZString.decompressFromEncodedURIComponent(fromParams);
return JSON.parse(decoded) as T.EPSelectionState;
}

View File

@ -42,7 +42,10 @@ type EpsReducerAction = {
index: number,
direction: "back" | "forward",
},
};
} | {
type: "load EPS",
payload: T.EPSelectionState,
}
export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAction, sendAlert?: (msg: string) => void): T.EPSelectionState {
if (action.type === "set predicate type") {
@ -173,6 +176,9 @@ export default function epsReducer(eps: T.EPSelectionState, action: EpsReducerAc
blocks: shiftBlock(eps.blocks, index, direction),
};
}
if (action.type === "load EPS") {
return action.payload;
}
throw new Error("unknown epsReducer action");
}

View File

@ -20,7 +20,7 @@ import APPicker from "../ap-picker/APPicker";
import autoAnimate from "@formkit/auto-animate";
import { getObjectSelection, getSubjectSelection, isNoObject } from "../../lib/phrase-building/blocks-utils";
const phraseURLParam = "VPPhrase";
const phraseURLParam = "VPhrase";
// TODO: Issue with dynamic compounds english making with plurals
// TODO: Issue with "the money were taken"
@ -55,7 +55,7 @@ function VPExplorer(props: {
},
"verbExplorerMode2",
);
const [showShareClipped, setShowShareClipped] = useState<boolean>(false);
const [showClipped, setShowClipped] = useState<string>("");
const [alert, setAlert] = useState<string | undefined>(undefined);
const [showingExplanation, setShowingExplanation] = useState<{ role: "servant" | "king", item: "subject" | "object" } | false>(false);
const parent = useRef<HTMLDivElement>(null);
@ -121,14 +121,22 @@ function VPExplorer(props: {
payload: form,
});
}
function flashClippedMessage(m: string) {
setShowClipped(m);
setTimeout(() => {
setShowClipped("");
}, 1250);
}
// for some crazy reason I can't get the URI share thing to encode and decode properly
function handleCopyShareLink() {
const shareUrl = getShareUrl(vps);
navigator.clipboard.writeText(shareUrl);
setShowShareClipped(true);
setTimeout(() => {
setShowShareClipped(false);
}, 1250);
flashClippedMessage("Copied phrase URL to clipboard");
}
function handleCopyCode() {
const code = getCode(vps);
navigator.clipboard.writeText(code);
flashClippedMessage("Copied phrase code to clipboard");
}
const object = getObjectSelection(vps.blocks).selection;
const subject = getSubjectSelection(vps.blocks).selection;
@ -160,12 +168,21 @@ function VPExplorer(props: {
]}
handleChange={setMode}
/>
<div
className="clickable"
onClick={mode === "phrases" ? handleCopyShareLink : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
<div className="d-flex flex-row">
<div
className="clickable mr-4"
onClick={mode === "phrases" ? handleCopyCode : undefined}
style={{ width: "1rem" }}
>
{(mode === "phrases" && phraseIsComplete) ? <i className="fas fa-code" /> : ""}
</div>
<div
className="clickable"
onClick={mode === "phrases" ? handleCopyShareLink : undefined}
style={{ width: "1rem" }}
>
{mode === "phrases" ? <i className="fas fa-share-alt" /> : ""}
</div>
</div>
</div>
{(vps.verb && (typeof object === "object") && (vps.verb.isCompound !== "dynamic") && (vps.verb.tenseCategory !== "imperative") &&(mode === "phrases")) &&
@ -288,14 +305,14 @@ function VPExplorer(props: {
showing={showingExplanation}
setShowing={setShowingExplanation}
/>
{showShareClipped && <div className="alert alert-primary text-center" role="alert" style={{
{showClipped && <div className="alert alert-primary text-center" role="alert" style={{
position: "fixed",
top: "30%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 9999999999999,
}}>
Phrase URL copied to clipboard
{showClipped}
</div>}
{alert && <div className="alert alert-warning text-center" role="alert" style={{
position: "fixed",
@ -312,8 +329,8 @@ function VPExplorer(props: {
export default VPExplorer;
function getShareUrl(vps: T.VPSelectionState): string {
const stringJSON = JSON.stringify(vps);
const encoded = LZString.compressToEncodedURIComponent(stringJSON);
const code = getCode(vps);
const encoded = LZString.compressToEncodedURIComponent(code);
const url = new URL(window.location.href);
// need to delete or else you could just get a second param written after
// which gets ignored
@ -322,6 +339,10 @@ function getShareUrl(vps: T.VPSelectionState): string {
return url.toString();
}
function getCode(vps: T.VPSelectionState): string {
return JSON.stringify(vps);
}
function getVPSFromUrl(): T.VPSelectionState | undefined {
const params = new URLSearchParams(window.location.search);
const fromParams = params.get(phraseURLParam);