ability to copy phrase selection code
This commit is contained in:
parent
dc0cd48015
commit
cab6528a6c
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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,6 +168,14 @@ function VPExplorer(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}
|
||||
|
@ -168,6 +184,7 @@ function VPExplorer(props: {
|
|||
{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")) &&
|
||||
<div className="text-center my-2">
|
||||
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue