From b23db1d5a88d9236e678851036ddee452f8e04ff Mon Sep 17 00:00:00 2001 From: Chris Kruining Date: Thu, 12 Dec 2024 16:40:13 +0100 Subject: [PATCH] Kaas --- src/components/colorschemepicker.module.css | 1 + src/components/grid.module.css | 128 -------- src/components/grid.tsx | 280 ------------------ src/components/grid/grid.module.css | 0 src/components/grid/grid.tsx | 129 ++++++++ src/components/grid/index.tsx | 4 + src/components/table/index.tsx | 2 +- src/components/table/table.module.css | 155 +++++----- src/components/table/table.tsx | 141 +++++---- src/features/command/index.tsx | 59 ++-- src/features/file/grid.module.css | 128 -------- src/features/file/grid.tsx | 5 +- src/features/menu/index.tsx | 8 +- src/global.d.ts | 8 + src/routes/(editor)/experimental.tsx | 127 +------- .../{ => experimental}/experimental.data.ts | 0 .../grid.module.css} | 0 src/routes/(editor)/experimental/grid.tsx | 67 +++++ .../(editor)/experimental/table.module.css | 36 +++ src/routes/(editor)/experimental/table.tsx | 114 +++++++ src/routes/editor.module.css | 5 - 21 files changed, 579 insertions(+), 818 deletions(-) delete mode 100644 src/components/grid.module.css delete mode 100644 src/components/grid.tsx create mode 100644 src/components/grid/grid.module.css create mode 100644 src/components/grid/grid.tsx create mode 100644 src/components/grid/index.tsx rename src/routes/(editor)/{ => experimental}/experimental.data.ts (100%) rename src/routes/(editor)/{experimental.module.css => experimental/grid.module.css} (100%) create mode 100644 src/routes/(editor)/experimental/grid.tsx create mode 100644 src/routes/(editor)/experimental/table.module.css create mode 100644 src/routes/(editor)/experimental/table.tsx diff --git a/src/components/colorschemepicker.module.css b/src/components/colorschemepicker.module.css index b586f43..af89340 100644 --- a/src/components/colorschemepicker.module.css +++ b/src/components/colorschemepicker.module.css @@ -8,6 +8,7 @@ padding: var(--padding-s); & select { + flex: 1 1 auto; border: none; background-color: inherit; border-radius: var(--radii-m); diff --git a/src/components/grid.module.css b/src/components/grid.module.css deleted file mode 100644 index 05c99e3..0000000 --- a/src/components/grid.module.css +++ /dev/null @@ -1,128 +0,0 @@ -.table { - position: relative; - display: grid; - grid-template-columns: 2em minmax(10em, max-content) repeat(var(--columns), auto); - align-content: start; - padding-inline: 1px; - margin-inline: -1px; - - block-size: 100%; - overflow: clip auto; - - background-color: var(--surface-600); - - & input[type="checkbox"] { - margin: .1em; - } - - & textarea { - resize: vertical; - min-block-size: max(2em, 100%); - max-block-size: 50em; - - background-color: var(--surface-600); - color: var(--text-1); - border-color: var(--text-2); - border-radius: var(--radii-s); - - &:has(::spelling-error, ::grammar-error) { - border-color: var(--fail); - } - - & ::spelling-error { - outline: 1px solid var(--fail); - text-decoration: yellow underline; - } - } - - & .cell { - display: grid; - padding: .5em; - border: 1px solid transparent; - border-radius: var(--radii-m); - - &:has(textarea:focus) { - border-color: var(--info); - } - - & > span { - align-self: center; - } - } - - & :is(.header, .main, .footer) { - grid-column: span calc(2 + var(--columns)); - display: grid; - grid-template-columns: subgrid; - } - - & .header { - position: sticky; - inset-block-start: 0; - background-color: var(--surface-600); - border-block-end: 1px solid var(--surface-300); - } - - & .row { - --bg: var(--text); - --alpha: 0; - grid-column: span calc(2 + var(--columns)); - display: grid; - grid-template-columns: subgrid; - border: 1px solid transparent; - background-color: color(from var(--bg) srgb r g b / var(--alpha)); - - &:has(> .cell > :checked) { - --bg: var(--info); - --alpha: .1; - border-color: var(--bg); - - & span { - font-variation-settings: 'GRAD' 1000; - } - - & + :has(> .cell> :checked) { - border-block-start-color: transparent; - } - - &:has(+ .row > .cell > :checked) { - border-block-end-color: transparent; - } - } - - &:hover { - --alpha: .2 !important; - } - } - - & details { - display: contents; - - &::details-content { - grid-column: span calc(2 + var(--columns)); - display: grid; - grid-template-columns: subgrid; - } - - &:not([open])::details-content { - display: none; - } - - & > summary { - grid-column: 2 / span calc(1 + var(--columns)); - padding: .5em; - padding-inline-start: calc(var(--depth) * 1em + .5em); - - } - - & > .row > .cell > span { - padding-inline-start: calc(var(--depth) * 1em); - } - } -} - -@property --depth { - syntax: ""; - inherits: false; - initial-value: 0; -} \ No newline at end of file diff --git a/src/components/grid.tsx b/src/components/grid.tsx deleted file mode 100644 index c0e0c2a..0000000 --- a/src/components/grid.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import { Accessor, Component, createContext, createEffect, createMemo, createSignal, For, ParentComponent, Show, useContext } from "solid-js"; -import { createStore, produce, unwrap } from "solid-js/store"; -import { SelectionProvider, useSelection, selectable } from "../features/selectable"; -import { debounce, deepCopy, deepDiff, Mutation } from "~/utilities"; -import css from './grid.module.css'; - -selectable // prevents removal of import - -type Rows = Map>; -type SelectionItem = { key: string, value: Accessor>, element: WeakRef }; - -type Insertion = { kind: 'row', key: string } | { kind: 'column', value: string }; - -export interface GridContextType { - readonly rows: Accessor>>; - readonly mutations: Accessor; - readonly selection: Accessor; - mutate(prop: string, lang: string, value: string): void; - remove(props: string[]): void; - insert(insertion: Insertion): void; -} - -export interface GridApi { - readonly selection: Accessor>>; - readonly rows: Accessor>>; - readonly mutations: Accessor; - selectAll(): void; - clear(): void; - remove(keys: string[]): void; - insert(insertion: Insertion): void; -} - -const GridContext = createContext(); - -const useGrid = () => useContext(GridContext)!; - -export const Grid: Component<{ class?: string, columns: string[], rows: Rows, api?: (api: GridApi) => any }> = (props) => { - const [selection, setSelection] = createSignal([]); - const [state, setState] = createStore<{ rows: Record>, columns: string[], snapshot: Rows, numberOfRows: number }>({ - rows: {}, - columns: [], - snapshot: new Map, - numberOfRows: 0, - }); - - const mutations = createMemo(() => { - // enumerate all values to make sure the memo is recalculated on any change - Object.values(state.rows).map(entry => Object.values(entry)); - - return deepDiff(state.snapshot, state.rows).toArray(); - }); - const rows = createMemo(() => Object.fromEntries(Object.entries(state.rows).map(([key, row]) => [key, unwrap(row)] as const))); - const columns = createMemo(() => state.columns); - - createEffect(() => { - setState('rows', Object.fromEntries(deepCopy(props.rows).entries())); - setState('snapshot', props.rows); - }); - - createEffect(() => { - setState('columns', [...props.columns]); - }); - - createEffect(() => { - setState('numberOfRows', Object.keys(state.rows).length); - }); - - const ctx: GridContextType = { - rows, - mutations, - selection, - - mutate(prop: string, lang: string, value: string) { - setState('rows', prop, lang, value); - }, - - remove(props: string[]) { - setState('rows', produce(rows => { - for (const prop of props) { - delete rows[prop]; - } - - return rows; - })); - }, - - insert(prop: string) { - setState('rows', produce(rows => { - rows[prop] = Object.fromEntries(state.columns.slice(1).map(lang => [lang, ''])); - - return rows - })) - }, - - addColumn(name: string): void { - setState(produce(state => { - state.columns.push(name); - state.rows = Object.fromEntries(Object.entries(state.rows).map(([key, row]) => [key, { ...row, [name]: '' }])); - - return state; - })) - }, - }; - - return - - - - <_Grid class={props.class} columns={columns()} rows={rows()} /> - - ; -}; - -const _Grid: Component<{ class?: string, columns: string[], rows: Record> }> = (props) => { - const columnCount = createMemo(() => props.columns.length - 1); - const root = createMemo(() => Object.entries(props.rows) - .reduce((aggregate, [key, value]) => { - let obj: any = aggregate; - const parts = key.split('.'); - - for (const [i, part] of parts.entries()) { - if (Object.hasOwn(obj, part) === false) { - obj[part] = {}; - } - - if (i === (parts.length - 1)) { - obj[part] = value; - } - else { - obj = obj[part]; - } - } - - return aggregate; - }, {})); - - return
- - -
- -
-
-}; - -const Api: Component<{ api: undefined | ((api: GridApi) => any) }> = (props) => { - const gridContext = useGrid(); - const selectionContext = useSelection<{ key: string, value: Accessor>, element: WeakRef }>(); - - const api: GridApi = { - selection: createMemo(() => { - const selection = selectionContext.selection(); - - return Object.fromEntries(selection.map(({ key, value }) => [key, value()] as const)); - }), - rows: gridContext.rows, - mutations: gridContext.mutations, - selectAll() { - selectionContext.selectAll(); - }, - clear() { - selectionContext.clear(); - }, - remove(props: string[]) { - gridContext.remove(props); - }, - insert(prop: string) { - gridContext.insert(prop); - }, - - addColumn(name: string): void { - gridContext.addColumn(name); - }, - }; - - createEffect(() => { - props.api?.(api); - }); - - return null; -}; - -const Head: Component<{ headers: string[] }> = (props) => { - const context = useSelection(); - - return
-
- 0 && context.selection().length === context.length()} - indeterminate={context.selection().length !== 0 && context.selection().length !== context.length()} - on:input={(e: InputEvent) => e.target.checked ? context.selectAll() : context.clear()} - /> -
- - { - header => {header} - } -
; -}; - -const Row: Component<{ entry: Entry, path?: string[] }> = (props) => { - const grid = useGrid(); - - return { - ([key, value]) => { - const values = Object.entries(value); - const path = [...(props.path ?? []), key]; - const k = path.join('.'); - const context = useSelection(); - - const isSelected = context.isSelected(k); - - return }> -
-
- context.select([k])} on:pointerdown={e => e.stopPropagation()} /> -
- -
- {key} -
- - { - ([lang, value]) =>
-