Skip to content

Commit

Permalink
Add functionality to open and save files with shortcuts
Browse files Browse the repository at this point in the history
  • Loading branch information
graphemecluster committed Oct 3, 2024
1 parent f8d3d3e commit 7d2f5e2
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 69 deletions.
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@types/node": "^22.7.4",
"@types/react": "^18.3.10",
"@types/react-dom": "^18.3.0",
"@types/wicg-file-system-access": "^2023.10.5",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"@vitejs/plugin-react": "^4.3.2",
Expand Down
85 changes: 78 additions & 7 deletions src/Components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,75 @@ function showHelp() {
<>
<h2>使用說明</h2>
<h3>快速鍵</h3>
<p>快速鍵僅在編輯器處於焦點狀態時有效。</p>
<ul>
<li>
<kbd>
<kbd>Alt</kbd>+<kbd>N</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Option</kbd>+<kbd>N</kbd>
</kbd>{" "}
(
<kbd>
<kbd></kbd>
<kbd>N</kbd>
</kbd>
):新增檔案
</li>
<li>
<kbd>
<kbd>Alt</kbd>+<kbd>S</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Option</kbd>+<kbd>S</kbd>
</kbd>{" "}
(
<kbd>
<kbd></kbd>
<kbd>S</kbd>
</kbd>
):刪除檔案
</li>
<li>
<kbd>
<kbd>Ctrl</kbd>+<kbd>O</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Cmd</kbd>+<kbd>O</kbd>
</kbd>{" "}
(
<kbd>
<kbd></kbd>
<kbd>O</kbd>
</kbd>
):從本機開啟檔案
</li>
<li>
<kbd>
<kbd>Ctrl</kbd>+<kbd>S</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Cmd</kbd>+<kbd>S</kbd>
</kbd>{" "}
(
<kbd>
<kbd></kbd>
<kbd>S</kbd>
</kbd>
):儲存檔案至本機
</li>
<li hidden>
<kbd>
<kbd>Ctrl</kbd>+<kbd>`</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Meta</kbd>+<kbd>`</kbd>
<kbd>Cmd</kbd>+<kbd>`</kbd>
</kbd>{" "}
(
<kbd>
Expand All @@ -307,9 +368,18 @@ function showHelp() {
</li>
<li>
<kbd>
<kbd>Alt</kbd>+<kbd>S</kbd>
<kbd>Alt</kbd>+<kbd>R</kbd>
</kbd>{" "}
{" "}
<kbd>
<kbd>Option</kbd>+<kbd>R</kbd>
</kbd>{" "}
(
<kbd>
<kbd></kbd>
<kbd>R</kbd>
</kbd>
) 或{" "}
<kbd>
<kbd>Shift</kbd>+<kbd>Enter</kbd>
</kbd>{" "}
Expand All @@ -318,12 +388,13 @@ function showHelp() {
<kbd></kbd>
<kbd></kbd>
</kbd>
):執行推導,顯示推導結果
):執行推導並顯示推導結果
</li>
<li>
<kbd>Esc</kbd> (<kbd></kbd>):關閉推導結果面板
<kbd>Esc</kbd> (<kbd></kbd>):關閉「新增方案」或「推導結果」面板
</li>
</ul>
<p>此外,檔案亦可透過拖曳載入。</p>
<h3>指定個別字音</h3>
<p>
推導自訂文章時,若某字有多個音,且推導結果不同,則在推導結果介面上,該字會被著色。指標移至其上(或觸控螢幕上點按)會出現選單,可以點選想要的字音。
Expand Down Expand Up @@ -467,7 +538,7 @@ const FontPreload = styled.span`
`;

export default function App() {
const handleRef = useRef(noop);
const evaluateHandlerRef = useRef(noop);
return (
<Container>
<Content>
Expand All @@ -483,7 +554,7 @@ export default function App() {
</a>
</LinkToLegacy>
<Buttons>
<ApplyButton title="適用" onClick={useCallback(() => handleRef.current(), [])}>
<ApplyButton title="適用" onClick={useCallback(() => evaluateHandlerRef.current(), [])}>
<FontAwesomeIcon icon={faCirclePlay} />
</ApplyButton>
<ShowButton title="關於" onClick={showAbout}>
Expand All @@ -496,7 +567,7 @@ export default function App() {
</Title>
</nav>
</header>
<Main handleRef={handleRef} />
<Main evaluateHandlerRef={evaluateHandlerRef} />
</Content>
<FontPreload aria-hidden>結果</FontPreload>
</Container>
Expand Down
11 changes: 5 additions & 6 deletions src/Components/CreateSchemaDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ExplorerFolder from "./ExplorerFolder";
import Spinner from "./Spinner";
import actions from "../actions";
import Swal from "../Classes/SwalReact";
import { newFileTemplate, tshetUinhExamplesURLPrefix, UseMainState } from "../consts";
import { invalidCharsRegex, newFileTemplate, tshetUinhExamplesURLPrefix, UseMainState } from "../consts";
import samples from "../samples";
import { fetchFile, normalizeFileName } from "../utils";

Expand Down Expand Up @@ -174,9 +174,9 @@ const LoadModal = styled.div`
`;

interface CreateSchemaDialogProps extends UseMainState {
getDefaultFileName: (sample: Sample | "") => string;
schemaLoaded: (schema: Omit<SchemaState, "parameters">) => void;
hasSchemaName: (name: string) => boolean;
getDefaultFileName(sample: string): string;
schemaLoaded(schema: Omit<SchemaState, "parameters">): void;
hasSchemaName(name: string): boolean;
}

const CreateSchemaDialog = forwardRef<HTMLDialogElement, CreateSchemaDialogProps>(function CreateSchemaDialog(
Expand All @@ -198,8 +198,7 @@ const CreateSchemaDialog = forwardRef<HTMLDialogElement, CreateSchemaDialogProps
const validation = useMemo(() => {
const name = normalizeFileName(createSchemaName);
if (!name) return "檔案名稱為空";
// eslint-disable-next-line no-control-regex
if (/[\0-\x1f"*/:<>?\\|\x7f-\x9f]/.test(name)) return "檔案名稱含有特殊字元";
if (invalidCharsRegex.test(name)) return "檔案名稱含有特殊字元";
if (hasSchemaName(name + ".js")) return "檔案名稱與現有檔案重複";
return "";
}, [createSchemaName, hasSchemaName]);
Expand Down
26 changes: 4 additions & 22 deletions src/Components/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const Loading = styled.div`

let evaluationResult: ReactNode = [];

export default function Main({ handleRef }: { handleRef: MutableRefObject<() => void> }) {
export default function Main({ evaluateHandlerRef }: { evaluateHandlerRef: MutableRefObject<() => void> }) {
const [state, setState] = useState(initialState);
const { article, option, convertVariant, syncCharPosition } = state;
useEffect(() => {
Expand All @@ -160,7 +160,7 @@ export default function Main({ handleRef }: { handleRef: MutableRefObject<() =>
const [operation, increaseOperation] = useReducer((operation: number) => operation + 1, 0);

const dialogRef = useRef<HTMLDialogElement>(null);
handleRef.current = useCallback(async () => {
evaluateHandlerRef.current = useCallback(async () => {
evaluationResult = [];
dialogRef.current?.showModal();
setLoading(true);
Expand Down Expand Up @@ -194,25 +194,6 @@ export default function Main({ handleRef }: { handleRef: MutableRefObject<() =>
});
}, []);

useEffect(() => {
function keyDown(event: KeyboardEvent) {
if (event.altKey && !event.ctrlKey && !event.metaKey && event.key === "s") {
// TODO Test on macOS.
// AFAIK it might be more appropriate to use something like "⌥⌘" (option+command) instead,
// because "⌥S" on macOS is supposed to behave more like "AltGr+S" on a PC.
event.preventDefault();
handleRef.current();
} else if (!event.ctrlKey && !event.metaKey && event.shiftKey && event.key === "Enter") {
event.preventDefault();
handleRef.current();
}
}
document.addEventListener("keydown", keyDown);
return () => {
document.removeEventListener("keydown", keyDown);
};
}, [handleRef]);

const resetArticle = useCallback(async () => {
if (
!article ||
Expand Down Expand Up @@ -256,7 +237,7 @@ export default function Main({ handleRef }: { handleRef: MutableRefObject<() =>
className="pure-button pure-button-primary"
type="button"
value="適用"
onClick={handleRef.current}
onClick={evaluateHandlerRef.current}
/>
<label hidden={option !== "convertArticle"}>
<input
Expand Down Expand Up @@ -299,6 +280,7 @@ export default function Main({ handleRef }: { handleRef: MutableRefObject<() =>
</p>
</>
}
evaluateHandlerRef={evaluateHandlerRef}
/>
{createPortal(
<OutputContainer ref={dialogRef}>
Expand Down
Loading

0 comments on commit 7d2f5e2

Please sign in to comment.