diff --git a/src/components/filetree.tsx b/src/components/filetree.tsx index 2d84649..b32583c 100644 --- a/src/components/filetree.tsx +++ b/src/components/filetree.tsx @@ -10,21 +10,22 @@ export interface FileEntry { name: string; id: string; kind: 'file'; - meta: File; handle: FileSystemFileHandle; directory: FileSystemDirectoryHandle; + meta: File; } export interface FolderEntry { name: string; id: string; kind: 'folder'; + handle: FileSystemDirectoryHandle; entries: Entry[]; } export type Entry = FileEntry | FolderEntry; -export const emptyFolder: FolderEntry = { name: '', id: '', kind: 'folder', entries: [] } as const; +export const emptyFolder: FolderEntry = { name: '', id: '', kind: 'folder', entries: [], handle: undefined as unknown as FileSystemDirectoryHandle } as const; export async function* walk(directory: FileSystemDirectoryHandle, filters: RegExp[] = [], depth = 0): AsyncGenerator { if (depth === 10) { @@ -39,10 +40,10 @@ 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(), handle, directory }; + yield { name: handle.name, id, handle, kind: 'file', meta: await handle.getFile(), directory }; } else { - yield { name: handle.name, id, kind: 'folder', entries: await Array.fromAsync(walk(handle, filters, depth + 1)) }; + yield { name: handle.name, id, handle, kind: 'folder', entries: await Array.fromAsync(walk(handle, filters, depth + 1)) }; } } } @@ -53,7 +54,7 @@ interface TreeContextType { const TreeContext = createContext(); -export const Tree: Component<{ entries: Entry[], children: (file: Accessor) => JSX.Element, open?: TreeContextType['open'] }> = (props) => { +export const Tree: Component<{ entries: Entry[], children: readonly [(folder: Accessor) => JSX.Element, (file: Accessor) => JSX.Element], open?: TreeContextType['open'] }> = (props) => { const [selection, setSelection] = createSignal([]); const context = { @@ -67,7 +68,7 @@ export const Tree: Component<{ entries: Entry[], children: (file: Accessor; } -const _Tree: Component<{ entries: Entry[], children: (file: Accessor) => JSX.Element }> = (props) => { +const _Tree: Component<{ entries: Entry[], children: readonly [(folder: Accessor) => JSX.Element, (file: Accessor) => JSX.Element] }> = (props) => { const context = useContext(TreeContext); return { @@ -77,17 +78,17 @@ const _Tree: Component<{ entries: Entry[], children: (file: Accessor) } { - file => context?.open(file().meta)}> {props.children(file)} + file => context?.open(file().meta)}> {props.children[1](file)} } } } -const Folder: Component<{ folder: FolderEntry, children: (file: Accessor) => JSX.Element }> = (props) => { +const Folder: Component<{ folder: FolderEntry, children: readonly [(folder: Accessor) => JSX.Element, (file: Accessor) => JSX.Element] }> = (props) => { const [open, setOpen] = createSignal(true); return
debounce(() => setOpen(o => !o), 1)}> - }> {props.folder.name} + }> {props.children[0](() => props.folder)} <_Tree entries={props.folder.entries} children={props.children} />
; }; diff --git a/src/components/tabs.module.css b/src/components/tabs.module.css index a2f28ed..eb97eb3 100644 --- a/src/components/tabs.module.css +++ b/src/components/tabs.module.css @@ -1,13 +1,41 @@ -.root { +.tabs { + position: relative; display: grid; - grid: auto minmax(0, 1fr) / repeat(var(--tab-count), auto); + grid: auto minmax(0, 1fr) / 100%; justify-content: start; inline-size: 100%; block-size: 100%; + & > header { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + + border-block-end: 1px solid var(--surface-5); + + & > button { + background-color: var(--surface-1); + color: var(--text-2); + padding: var(--padding-m) var(--padding-l); + border: none; + + &.active { + background-color: var(--surface-3); + color: var(--text-1); + } + } + } + .tab { - display: contents; + position: absolute; + grid-area: 2 / 1 / span 1 / span 1; + inline-size: 100%; + block-size: 100%; + + &:not(.active) { + display: none; + } & > summary { grid-row: 1 / 1; diff --git a/src/components/tabs.tsx b/src/components/tabs.tsx index 507bc07..17c6c96 100644 --- a/src/components/tabs.tsx +++ b/src/components/tabs.tsx @@ -1,46 +1,83 @@ -import { Accessor, children, createContext, createMemo, createSignal, createUniqueId, For, JSX, ParentComponent, useContext } from "solid-js"; +import { Accessor, children, createContext, createEffect, createMemo, createRenderEffect, createSignal, createUniqueId, For, JSX, onMount, ParentComponent, Show, useContext } from "solid-js"; import css from "./tabs.module.css"; interface TabsContextType { - activate(id: string): void; - active: Accessor; - isActive(id: string): Accessor; + register(id: string, label: string): Accessor; } const TabsContext = createContext(); +const useTabs = () => { + const context = useContext(TabsContext); + + if (context === undefined) { + throw new Error(' is used outside of a ') + } + + return context!; +} + export const Tabs: ParentComponent = (props) => { const [active, setActive] = createSignal(undefined); - const numberOfTabs = createMemo(() => children(() => props.children).toArray().length); + const [tabs, setTabs] = createSignal<{ id: string, label: string }[]>([]); + // const resolved = children(() => props.children); + // const resolvedArray = createMemo(() => resolved.toArray()); + // const tabs = createMemo(() => resolvedArray().map(t => ({ id: t.id, label: t.dataset?.label ?? '' }))); - return { + // for (const t of resolvedArray()) { + // console.log(t); + // } + // }); - active, + createEffect(() => { + setActive(tabs().at(-1)?.id); + }); + + // createRenderEffect(() => { + // if (isServer) { + // return; + // } + + // for (const t of resolvedArray().filter(t => t instanceof HTMLElement)) { + // if (active() === t.id) { + // t.classList.add(css.active); + // } else { + // t.classList.remove(css.active); + // } + // } + // }); + + const ctx = { + register(id: string, label: string) { + setTabs(tabs => [...tabs, { id, label }]); - isActive(id: string) { return createMemo(() => active() === id); }, - }}> -
+ }; + + createEffect(() => { + console.log(tabs()); + }); + + return +
+
+ { + tab => + } +
+ {props.children}
; } -export const Tab: ParentComponent<{ label: string }> = (props) => { - const id = `tab-${createUniqueId()}`; - const context = useContext(TabsContext); +export const Tab: ParentComponent<{ id: string, label: string }> = (props) => { + const context = useTabs(); - if (!context) { - return undefined; - } + const isActive = context.register(props.id, props.label); + const resolved = children(() => props.children); - return
e.newState === 'open' && context.activate(id)}> - {props.label} - - {props.children} -
+ return {resolved()}; } \ No newline at end of file diff --git a/src/features/command/contextMenu.tsx b/src/features/command/contextMenu.tsx index 752173e..63dfad5 100644 --- a/src/features/command/contextMenu.tsx +++ b/src/features/command/contextMenu.tsx @@ -1,4 +1,4 @@ -import { Accessor, Component, createContext, createEffect, createMemo, createSignal, createUniqueId, For, JSX, ParentComponent, useContext } from "solid-js"; +import { Accessor, Component, createContext, createEffect, createMemo, createSignal, createUniqueId, For, JSX, ParentComponent, splitProps, useContext } from "solid-js"; import { CommandType } from "./index"; import css from "./contextMenu.module.css"; @@ -69,16 +69,19 @@ const Menu: Component<{ children: (command: CommandType) => JSX.Element }> = (pr ; }; -const Handle: ParentComponent = (props) => { - const context = useContext(ContextMenu)!; +const Handle: ParentComponent> = (props) => { + const [local, rest] = splitProps(props, ['children']); - return { + const context = useContext(ContextMenu)!; + const [handle, setHandle] = createSignal(); + + return { e.preventDefault(); - context.show(e.target as HTMLElement); + context.show(handle()!); return false; - }}>{props.children}; + }}>{local.children}; }; export const Context = { Root, Menu, Handle }; \ No newline at end of file diff --git a/src/features/command/index.tsx b/src/features/command/index.tsx index f60e73b..d9b44aa 100644 --- a/src/features/command/index.tsx +++ b/src/features/command/index.tsx @@ -42,7 +42,6 @@ export const noop = Object.defineProperties(createCommand('noop', () => { }), { }, }) as CommandType & { withLabel(label: string): CommandType }; - export const Command: Component<{ command: CommandType }> = (props) => { return <> {props.command.label} diff --git a/src/features/file/grid.tsx b/src/features/file/grid.tsx index cd86102..2323d22 100644 --- a/src/features/file/grid.tsx +++ b/src/features/file/grid.tsx @@ -1,4 +1,4 @@ -import { Accessor, Component, createContext, createEffect, createMemo, createSignal, For, onMount, ParentComponent, Show, useContext } from "solid-js"; +import { Accessor, Component, createContext, createEffect, createMemo, createRenderEffect, createSignal, For, onMount, ParentComponent, Show, useContext } from "solid-js"; import { createStore, unwrap } from "solid-js/store"; import { SelectionProvider, useSelection, selectable } from "../selectable"; import { debounce, deepCopy, deepDiff, Mutation } from "~/utilities"; @@ -160,7 +160,7 @@ const Row: Component<{ entry: Entry, path?: string[] }> = (props) => { return }>
- context.select([k])} /> + context.select([k])} />
@@ -187,16 +187,22 @@ const Group: Component<{ key: string, entry: Entry, path: string[] }> = (props) }; const TextArea: Component<{ key: string, value: string, lang: string, oninput?: (event: InputEvent) => any }> = (props) => { - let element: HTMLTextAreaElement; + const [element, setElement] = createSignal(); const resize = () => { - element.style.height = `1px`; - element.style.height = `${2 + element.scrollHeight}px`; + const el = element(); + + if (!el) { + return; + } + + el.style.height = `1px`; + el.style.height = `${2 + element()!.scrollHeight}px`; }; const mutate = debounce(() => { props.oninput?.(new InputEvent('input', { - data: element.value.trim(), + data: element()?.value.trim(), })) }, 300); @@ -205,12 +211,14 @@ const TextArea: Component<{ key: string, value: string, lang: string, oninput?: mutate(); }; - onMount(() => { + createEffect(() => { + props.value; + resize(); }); return