still working on saving files
This commit is contained in:
parent
e363ee1844
commit
c96348e888
6 changed files with 67 additions and 54 deletions
|
@ -11,6 +11,8 @@ export interface FileEntry {
|
|||
id: string;
|
||||
kind: 'file';
|
||||
meta: File;
|
||||
handle: FileSystemFileHandle;
|
||||
directory: FileSystemDirectoryHandle;
|
||||
}
|
||||
|
||||
export interface FolderEntry {
|
||||
|
@ -37,7 +39,7 @@ export async function* walk(directory: FileSystemDirectoryHandle, filters: RegEx
|
|||
const id = await handle.getUniqueId();
|
||||
|
||||
if (handle.kind === 'file') {
|
||||
yield { name: handle.name, id, kind: 'file', meta: await handle.getFile() };
|
||||
yield { name: handle.name, id, kind: 'file', meta: await handle.getFile(), handle, directory };
|
||||
}
|
||||
else {
|
||||
yield { name: handle.name, id, kind: 'folder', entries: await Array.fromAsync(walk(handle, filters, depth + 1)) };
|
||||
|
|
|
@ -247,12 +247,6 @@ export const CommandPalette: Component<{ api?: (api: CommandPaletteApi) => any,
|
|||
}
|
||||
});
|
||||
|
||||
// temp debug code
|
||||
createEffect(() => {
|
||||
search()?.searchFor('c');
|
||||
setOpen(true);
|
||||
});
|
||||
|
||||
const onSubmit = (command: CommandType) => {
|
||||
setOpen(false);
|
||||
props.onSubmit?.(command);
|
||||
|
@ -296,7 +290,7 @@ interface SearchableListProps<T> {
|
|||
function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
||||
const [term, setTerm] = createSignal<string>('');
|
||||
const [input, setInput] = createSignal<HTMLInputElement>();
|
||||
const [selected, setSelected] = createSignal<number>();
|
||||
const [selected, setSelected] = createSignal<number>(0);
|
||||
const id = createUniqueId();
|
||||
|
||||
const results = createMemo(() => {
|
||||
|
@ -309,20 +303,7 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
|||
return props.items.filter(item => props.filter ? props.filter(item, search) : props.keySelector(item).includes(search));
|
||||
});
|
||||
|
||||
const value = createMemo(() => {
|
||||
const index = selected();
|
||||
|
||||
if (index === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return results().at(index);
|
||||
});
|
||||
const inputValue = createMemo(() => {
|
||||
const v = value();
|
||||
|
||||
return v !== undefined ? props.keySelector(v) : term();
|
||||
});
|
||||
const value = createMemo(() => results().at(selected()));
|
||||
|
||||
const ctx = {
|
||||
filter: term,
|
||||
|
@ -333,7 +314,7 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
|||
},
|
||||
clear() {
|
||||
setTerm('');
|
||||
setSelected(undefined);
|
||||
setSelected(0);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -349,13 +330,13 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
|||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'ArrowUp') {
|
||||
setSelected(current => current !== undefined && current > 0 ? current - 1 : undefined);
|
||||
setSelected(current => Math.max(0, current - 1));
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
setSelected(current => current !== undefined ? Math.min(results().length - 1, current + 1) : 0);
|
||||
setSelected(current => Math.min(results().length - 1, current + 1));
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
@ -364,10 +345,6 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
|||
const onSubmit = (e: SubmitEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (selected() === undefined && term() !== '') {
|
||||
setSelected(0);
|
||||
}
|
||||
|
||||
const v = value();
|
||||
|
||||
if (v === undefined) {
|
||||
|
@ -379,7 +356,7 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
|||
};
|
||||
|
||||
return <form method="dialog" class={css.search} onkeydown={onKeyDown} onsubmit={onSubmit}>
|
||||
<input id={`search-${id}`} ref={setInput} value={inputValue()} oninput={(e) => setTerm(e.target.value)} placeholder="start typing for command" autofocus />
|
||||
<input id={`search-${id}`} ref={setInput} value={term()} oninput={(e) => setTerm(e.target.value)} placeholder="start typing for command" autofocus autocomplete="off" />
|
||||
|
||||
<output for={`search-${id}`}>
|
||||
<For each={results()}>{
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Title } from "@solidjs/meta";
|
||||
import { Component, createEffect, createMemo, createSignal, For, ParentProps, Show } from "solid-js";
|
||||
import { createSignal, ParentProps, Show } from "solid-js";
|
||||
import { BsTranslate } from "solid-icons/bs";
|
||||
import { FilesProvider } from "~/features/file";
|
||||
import { CommandPalette, CommandPaletteApi, MenuProvider, asMenuRoot, useMenu } from "~/features/menu";
|
||||
import { CommandPalette, CommandPaletteApi, MenuProvider, asMenuRoot } from "~/features/menu";
|
||||
import { isServer } from "solid-js/web";
|
||||
import { A } from "@solidjs/router";
|
||||
import { createCommand, Modifier } from "~/features/command";
|
||||
import css from "./editor.module.css";
|
||||
|
||||
asMenuRoot // prevents removal of import
|
||||
|
||||
|
@ -22,7 +23,7 @@ export default function Editor(props: ParentProps) {
|
|||
return <MenuProvider commands={commands}>
|
||||
<Title>Translation-Tool</Title>
|
||||
|
||||
<main inert={commandPalette()?.open()}>
|
||||
<main class={css.layout} inert={commandPalette()?.open()}>
|
||||
<nav use:asMenuRoot>
|
||||
<A class="logo" href="/"><BsTranslate /></A>
|
||||
</nav>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { children, createEffect, createMemo, createResource, createSignal, onMount, ParentProps } from "solid-js";
|
||||
import { children, createEffect, createMemo, createResource, createSignal, createUniqueId, onMount, ParentProps } from "solid-js";
|
||||
import { MutarionKind, splitAt } from "~/utilities";
|
||||
import { Sidebar } from "~/components/sidebar";
|
||||
import { emptyFolder, FolderEntry, walk as fileTreeWalk, Tree, FileEntry, Entry } from "~/components/filetree";
|
||||
|
@ -132,7 +132,7 @@ export default function Edit(props: ParentProps) {
|
|||
filesContext.set('root', directory);
|
||||
mutate(directory);
|
||||
}),
|
||||
save: createCommand('save', () => {
|
||||
save: createCommand('save', async () => {
|
||||
const mutations = api()?.mutations() ?? [];
|
||||
|
||||
if (mutations.length === 0) {
|
||||
|
@ -154,8 +154,8 @@ export default function Edit(props: ParentProps) {
|
|||
// 3) When a file has 0 keys, we can remove it.
|
||||
|
||||
for (const mutation of mutations) {
|
||||
const [key, lang] = splitAt(mutation.key, mutation.key.lastIndexOf('.'));
|
||||
const entry = _entries.get(key);
|
||||
const [k, lang] = splitAt(mutation.key, mutation.key.lastIndexOf('.'));
|
||||
const entry = _entries.get(k);
|
||||
const localEntry = entry?.[lang];
|
||||
|
||||
// TODO :: try to resolve to a file
|
||||
|
@ -178,36 +178,62 @@ export default function Edit(props: ParentProps) {
|
|||
throw new Error('invalid edge case???');
|
||||
}
|
||||
|
||||
if (localEntry.id === undefined) {
|
||||
const [, alternativeLocalEntry] = Object.entries(entry).find(([l, e]) => l !== lang && e.id !== undefined) ?? [];
|
||||
const [handle, path = []] = await (async () => {
|
||||
if (localEntry.id === undefined) {
|
||||
const [, alternativeLocalEntry] = Object.entries(entry).find(([l, e]) => l !== lang && e.id !== undefined) ?? [];
|
||||
|
||||
if (alternativeLocalEntry === undefined) {
|
||||
// unable to find alternative. show a picker instead?
|
||||
return;
|
||||
const { directory, path } = alternativeLocalEntry ? findFile(tree(), alternativeLocalEntry.id) ?? {} : {};
|
||||
|
||||
// Short circuit if the mutation type is delete.
|
||||
// Otherwise we would create a new file handle,
|
||||
// and then immediately remove it again.
|
||||
if (mutation.kind === MutarionKind.Delete) {
|
||||
return [undefined, path] as const;
|
||||
}
|
||||
|
||||
const handle = await window.showSaveFilePicker({
|
||||
suggestedName: `${lang}.json`,
|
||||
startIn: directory ?? root(),
|
||||
excludeAcceptAllOption: true,
|
||||
types: [
|
||||
{ accept: { 'application/json': ['.json'] }, description: 'JSON' },
|
||||
]
|
||||
});
|
||||
|
||||
return [handle, path] as const;
|
||||
}
|
||||
|
||||
const file = findFile(tree(), alternativeLocalEntry.id);
|
||||
const { handle, path } = findFile(tree(), localEntry.id) ?? {};
|
||||
|
||||
console.log('alt', file);
|
||||
}
|
||||
return [handle, path] as const;
|
||||
})();
|
||||
|
||||
const file = findFile(tree(), localEntry.id);
|
||||
const fileExists = file !== undefined;
|
||||
console.log(k, path.join('.'));
|
||||
|
||||
console.log(key, file?.path.join('.'));
|
||||
const createNewFile = async (lang: string, directory: FileSystemDirectoryHandle) => {
|
||||
const handle = await window.showSaveFilePicker({
|
||||
suggestedName: `${lang}.json`,
|
||||
startIn: directory,
|
||||
excludeAcceptAllOption: true,
|
||||
types: [
|
||||
{ accept: { 'application/json': ['.json'] }, description: 'JSON' },
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
const fileLocalKey = key.slice(file?.path.join('.'));
|
||||
const key = k.slice(path.join('.').length);
|
||||
const { handle, path } = findFile(tree(), localEntry.id) ?? {};
|
||||
|
||||
const result = match([fileExists, mutation.kind])
|
||||
.with([true, MutarionKind.Create], () => ({ action: MutarionKind.Create, key, value: rows[key][lang], file: file?.meta }))
|
||||
const result = match([handle !== undefined, mutation.kind])
|
||||
.with([true, MutarionKind.Create], () => ({ action: MutarionKind.Create, key, value: rows[key][lang], handle }))
|
||||
.with([false, MutarionKind.Create], () => '2')
|
||||
.with([true, MutarionKind.Update], () => ({ action: MutarionKind.Update, key, value: rows[key][lang], file: file?.meta }))
|
||||
.with([true, MutarionKind.Update], () => ({ action: MutarionKind.Update, key, value: rows[key][lang], handle }))
|
||||
.with([false, MutarionKind.Update], () => '4')
|
||||
.with([true, MutarionKind.Delete], () => ({ action: MutarionKind.Delete, key, file: file?.meta }))
|
||||
.with([true, MutarionKind.Delete], () => ({ action: MutarionKind.Delete, key, handle }))
|
||||
.with([false, MutarionKind.Delete], () => '6')
|
||||
.exhaustive();
|
||||
|
||||
console.log(mutation, key, lang, entry, file, result);
|
||||
console.log(mutation, key, lang, entry, result);
|
||||
}
|
||||
|
||||
// for (const fileId of files) {
|
||||
|
|
7
src/routes/editor.module.css
Normal file
7
src/routes/editor.module.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
.layout {
|
||||
display: grid;
|
||||
grid: auto minmax(0, 1fr) / 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
overflow: clip;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue