finally back up and running again
This commit is contained in:
parent
529647b0d7
commit
4a5f0cf2d1
8 changed files with 101 additions and 41 deletions
41
src/app.css
41
src/app.css
|
@ -30,16 +30,11 @@
|
||||||
--text-1: light-dark(oklch(from var(--primary-500) .2 .02 h), oklch(from var(--primary-500) .9 .02 h));
|
--text-1: light-dark(oklch(from var(--primary-500) .2 .02 h), oklch(from var(--primary-500) .9 .02 h));
|
||||||
--text-2: oklch(from var(--text-1) calc(l + .1) c h);
|
--text-2: oklch(from var(--text-1) calc(l + .1) c h);
|
||||||
|
|
||||||
--weight-lighter: 100;
|
--text-lighter: 100;
|
||||||
--weight-light: 300;
|
--text-light: 300;
|
||||||
--weight-normal: 500;
|
--text-normal: 500;
|
||||||
--weight-bold: 700;
|
--text-bold: 700;
|
||||||
--weight-bolder: 900;
|
--text-bolder: 900;
|
||||||
|
|
||||||
--radii-s: .125em;
|
|
||||||
--radii-m: .25em;
|
|
||||||
--radii-l: .5em;
|
|
||||||
--radii-xl: 1em;
|
|
||||||
|
|
||||||
--text-s: .8rem;
|
--text-s: .8rem;
|
||||||
--text-m: 1rem;
|
--text-m: 1rem;
|
||||||
|
@ -47,6 +42,12 @@
|
||||||
--text-xl: 1.6rem;
|
--text-xl: 1.6rem;
|
||||||
--text-xxl: 2rem;
|
--text-xxl: 2rem;
|
||||||
|
|
||||||
|
--radii-s: .125em;
|
||||||
|
--radii-m: .25em;
|
||||||
|
--radii-l: .5em;
|
||||||
|
--radii-xl: 1em;
|
||||||
|
|
||||||
|
--padding-xs: .125em;
|
||||||
--padding-s: .25em;
|
--padding-s: .25em;
|
||||||
--padding-m: .5em;
|
--padding-m: .5em;
|
||||||
--padding-l: .75em;
|
--padding-l: .75em;
|
||||||
|
@ -160,6 +161,26 @@ del {
|
||||||
color: oklch(from var(--fail) .1 .2 h);
|
color: oklch(from var(--fail) .1 .2 h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
background-color: var(--surface-600);
|
||||||
|
border-radius: var(--radii-m);
|
||||||
|
border: 1px solid var(--surface-500);
|
||||||
|
box-shadow:
|
||||||
|
0 1px 1px rgba(0, 0, 0, 0.2),
|
||||||
|
0 2px 0 0 rgba(255, 255, 255, 0.7) inset;
|
||||||
|
color: var(--text-2);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: var(--text-s);
|
||||||
|
font-weight: var(--text-bold);
|
||||||
|
line-height: 1;
|
||||||
|
padding: var(--padding-xs) var(--padding-s);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
samp {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
@property --hue {
|
@property --hue {
|
||||||
syntax: '<angle>';
|
syntax: '<angle>';
|
||||||
inherits: false;
|
inherits: false;
|
||||||
|
|
|
@ -60,6 +60,12 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& .caption {
|
||||||
|
/* grid-column: 1 / -1; */
|
||||||
|
position: sticky;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
& :is(.header, .main, .footer) {
|
& :is(.header, .main, .footer) {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
display: block grid;
|
display: block grid;
|
||||||
|
@ -106,7 +112,7 @@
|
||||||
animation: header-scroll-shadow linear both;
|
animation: header-scroll-shadow linear both;
|
||||||
animation-timeline: scroll();
|
animation-timeline: scroll();
|
||||||
animation-range: 0 2em;
|
animation-range: 0 2em;
|
||||||
font-weight: var(--weight-bold);
|
font-weight: var(--text-bold);
|
||||||
|
|
||||||
& > tr {
|
& > tr {
|
||||||
all: inherit;
|
all: inherit;
|
||||||
|
@ -139,7 +145,7 @@
|
||||||
animation: header-scroll-shadow linear both reverse;
|
animation: header-scroll-shadow linear both reverse;
|
||||||
animation-timeline: scroll();
|
animation-timeline: scroll();
|
||||||
animation-range: calc(100% - 2em) 100%;
|
animation-range: calc(100% - 2em) 100%;
|
||||||
font-weight: var(--weight-bold);
|
font-weight: var(--text-bold);
|
||||||
}
|
}
|
||||||
|
|
||||||
& details {
|
& details {
|
||||||
|
|
|
@ -86,11 +86,11 @@ function InnerTable<T extends Record<string, any>>(props: InnerTableProps<T>) {
|
||||||
const columnCount = createMemo(() => table.columns().length);
|
const columnCount = createMemo(() => table.columns().length);
|
||||||
|
|
||||||
return <table class={`${css.table} ${selectable() ? css.selectable : ''} ${props.class}`} style={{ '--columns': columnCount() }}>
|
return <table class={`${css.table} ${selectable() ? css.selectable : ''} ${props.class}`} style={{ '--columns': columnCount() }}>
|
||||||
{/* <Show when={(props.summary?.length ?? 0) > 0 ? props.summary : undefined}>{
|
<Show when={(props.summary?.length ?? 0) > 0 ? props.summary : undefined}>{
|
||||||
summary => {
|
summary => {
|
||||||
return <caption>Kaas {summary()}</caption>;
|
return <caption class={css.caption}>{summary()}</caption>;
|
||||||
}
|
}
|
||||||
}</Show> */}
|
}</Show>
|
||||||
|
|
||||||
<Groups />
|
<Groups />
|
||||||
<Head />
|
<Head />
|
||||||
|
@ -247,3 +247,11 @@ function Group<T extends Record<string, any>>(props: { key: keyof T, groupedBy:
|
||||||
}</For>
|
}</For>
|
||||||
</details>;
|
</details>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare module "solid-js" {
|
||||||
|
namespace JSX {
|
||||||
|
interface HTMLAttributes<T> {
|
||||||
|
indeterminate?: boolean | undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { Accessor, Component, createContext, createEffect, createMemo, createSignal, createUniqueId, For, JSX, ParentComponent, splitProps, useContext } from "solid-js";
|
import { Accessor, Component, createContext, createEffect, createMemo, createSignal, For, JSX, ParentComponent, splitProps, useContext } from "solid-js";
|
||||||
import { CommandType } from "./index";
|
import { CommandType } from "./index";
|
||||||
import css from "./contextMenu.module.css";
|
import css from "./contextMenu.module.css";
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ const Menu: Component<{ children: (command: CommandType) => JSX.Element }> = (pr
|
||||||
command();
|
command();
|
||||||
};
|
};
|
||||||
|
|
||||||
return <ul ref={setRoot} class={css.menu} style={`position-anchor: ${context.target()?.style.getPropertyValue('anchor-name')};`} popover ontoggle={onToggle}>
|
return <menu ref={setRoot} class={css.menu} style={`position-anchor: ${context.target()?.style.getPropertyValue('anchor-name')};`} popover ontoggle={onToggle}>
|
||||||
<For each={context.commands()}>{
|
<For each={context.commands()}>{
|
||||||
command => <li onpointerdown={onCommand(command)}>{props.children(command)}</li>
|
command => <li onpointerdown={onCommand(command)}>{props.children(command)}</li>
|
||||||
}</For>
|
}</For>
|
||||||
</ul>;
|
</menu>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Handle: ParentComponent<Record<string, any>> = (props) => {
|
const Handle: ParentComponent<Record<string, any>> = (props) => {
|
||||||
|
@ -75,7 +75,7 @@ const Handle: ParentComponent<Record<string, any>> = (props) => {
|
||||||
const context = useContext(ContextMenu)!;
|
const context = useContext(ContextMenu)!;
|
||||||
const [handle, setHandle] = createSignal<HTMLElement>();
|
const [handle, setHandle] = createSignal<HTMLElement>();
|
||||||
|
|
||||||
return <span {...rest} ref={setHandle} style={`anchor-name: --context-menu-handle-${createUniqueId()};`} oncontextmenu={(e) => {
|
return <span {...rest} ref={setHandle} style={`anchor-name: --context-menu-${createUniqueId()};`} oncontextmenu={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
context.show(handle()!);
|
context.show(handle()!);
|
||||||
|
@ -84,4 +84,7 @@ const Handle: ParentComponent<Record<string, any>> = (props) => {
|
||||||
}}>{local.children}</span>;
|
}}>{local.children}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let handleCounter = 0;
|
||||||
|
const createUniqueId = () => `handle-${handleCounter++}`
|
||||||
|
|
||||||
export const Context = { Root, Menu, Handle };
|
export const Context = { Root, Menu, Handle };
|
|
@ -1,4 +1,4 @@
|
||||||
import { Accessor, children, Component, createContext, createEffect, createMemo, JSX, ParentComponent, ParentProps, Show, useContext } from 'solid-js';
|
import { Accessor, children, Component, createContext, createEffect, createMemo, For, JSX, ParentComponent, ParentProps, Show, useContext } from 'solid-js';
|
||||||
|
|
||||||
interface CommandContextType {
|
interface CommandContextType {
|
||||||
set(commands: CommandType<any>[]): void;
|
set(commands: CommandType<any>[]): void;
|
||||||
|
@ -115,19 +115,27 @@ const Context = <T extends (...args: any[]) => any = any>(props: ParentProps<{ f
|
||||||
};
|
};
|
||||||
|
|
||||||
const Handle: Component<{ command: CommandType }> = (props) => {
|
const Handle: Component<{ command: CommandType }> = (props) => {
|
||||||
return <>
|
return <samp>
|
||||||
{props.command.label}
|
{props.command.label}
|
||||||
<Show when={props.command.shortcut}>{
|
<Show when={props.command.shortcut}>{
|
||||||
shortcut => {
|
shortcut => {
|
||||||
const shift = shortcut().modifier & Modifier.Shift ? 'Shft+' : '';
|
const modifier = shortcut().modifier;
|
||||||
const ctrl = shortcut().modifier & Modifier.Control ? 'Ctrl+' : '';
|
const modifierMap: Record<number, string> = {
|
||||||
const meta = shortcut().modifier & Modifier.Meta ? 'Meta+' : '';
|
[Modifier.Shift]: 'Shft',
|
||||||
const alt = shortcut().modifier & Modifier.Alt ? 'Alt+' : '';
|
[Modifier.Control]: 'Ctrl',
|
||||||
|
[Modifier.Meta]: 'Meta',
|
||||||
|
[Modifier.Alt]: 'Alt',
|
||||||
|
};
|
||||||
|
|
||||||
return <sub>{ctrl}{shift}{meta}{alt}{shortcut().key}</sub>;
|
return <>
|
||||||
|
<For each={Object.values(Modifier).filter((m): m is number => typeof m === 'number').filter(m => modifier & m)}>{
|
||||||
|
(m) => <><kbd>{modifierMap[m]}</kbd>+</>
|
||||||
|
}</For>
|
||||||
|
<kbd>{shortcut().key}</kbd>
|
||||||
|
</>;
|
||||||
}
|
}
|
||||||
}</Show>
|
}</Show>
|
||||||
</>;
|
</samp>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Command = { Root, Handle, Add, Context };
|
export const Command = { Root, Handle, Add, Context };
|
||||||
|
|
|
@ -182,7 +182,7 @@ const Root: ParentComponent<{}> = (props) => {
|
||||||
const Mount: Component = (props) => {
|
const Mount: Component = (props) => {
|
||||||
const menu = useMenu();
|
const menu = useMenu();
|
||||||
|
|
||||||
return <div class={css.root} ref={menu.setRef} />;
|
return <menu class={css.root} ref={menu.setRef} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Menu = { Mount, Root, Item, Separator } as const;
|
export const Menu = { Mount, Root, Item, Separator } as const;
|
||||||
|
@ -233,7 +233,7 @@ export const CommandPalette: Component<{ api?: (api: CommandPaletteApi) => any,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <dialog ref={setRoot} class={css.commandPalette} onClose={() => setOpen(false)}>
|
return <dialog ref={setRoot} class={css.commandPalette} onClose={() => setOpen(false)}>
|
||||||
<SearchableList<CommandType> items={context.commands()} keySelector={item => item.label} context={setSearch} onSubmit={onSubmit}>{
|
<SearchableList title="command palette" items={context.commands()} keySelector={item => item.label} context={setSearch} onSubmit={onSubmit}>{
|
||||||
(item, ctx) => <For each={item.label.split(ctx.filter())}>{
|
(item, ctx) => <For each={item.label.split(ctx.filter())}>{
|
||||||
(part, index) => <>
|
(part, index) => <>
|
||||||
<Show when={index() !== 0}><b>{ctx.filter()}</b></Show>
|
<Show when={index() !== 0}><b>{ctx.filter()}</b></Show>
|
||||||
|
@ -258,6 +258,7 @@ interface SearchContext<T> {
|
||||||
|
|
||||||
interface SearchableListProps<T> {
|
interface SearchableListProps<T> {
|
||||||
items: T[];
|
items: T[];
|
||||||
|
title?: string;
|
||||||
keySelector(item: T): string;
|
keySelector(item: T): string;
|
||||||
filter?: (item: T, search: string) => boolean;
|
filter?: (item: T, search: string) => boolean;
|
||||||
children(item: T, context: SearchContext<T>): JSX.Element;
|
children(item: T, context: SearchContext<T>): JSX.Element;
|
||||||
|
@ -333,7 +334,8 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
||||||
props.onSubmit?.(v);
|
props.onSubmit?.(v);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <form method="dialog" class={css.search} onkeydown={onKeyDown} onsubmit={onSubmit}>
|
return <search title={props.title}>
|
||||||
|
<form method="dialog" class={css.search} onkeydown={onKeyDown} onsubmit={onSubmit}>
|
||||||
<input id={`search-${id}`} ref={setInput} value={term()} oninput={(e) => setTerm(e.target.value)} placeholder="start typing for command" autofocus autocomplete="off" enterkeyhint="go" />
|
<input id={`search-${id}`} ref={setInput} value={term()} oninput={(e) => setTerm(e.target.value)} placeholder="start typing for command" autofocus autocomplete="off" enterkeyhint="go" />
|
||||||
|
|
||||||
<output for={`search-${id}`}>
|
<output for={`search-${id}`}>
|
||||||
|
@ -341,7 +343,8 @@ function SearchableList<T>(props: SearchableListProps<T>): JSX.Element {
|
||||||
(result, index) => <div classList={{ [css.selected]: index() === selected() }}>{props.children(result, ctx)}</div>
|
(result, index) => <div classList={{ [css.selected]: index() === selected() }}>{props.children(result, ctx)}</div>
|
||||||
}</For>
|
}</For>
|
||||||
</output>
|
</output>
|
||||||
</form>;
|
</form>
|
||||||
|
</search>;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module "solid-js" {
|
declare module "solid-js" {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Accessor, children, createContext, createEffect, createMemo, createRenderEffect, createSignal, createUniqueId, onCleanup, onMount, ParentComponent, ParentProps, Setter, Signal, useContext } from "solid-js";
|
import { Accessor, children, createContext, createEffect, createMemo, createRenderEffect, createSignal, onCleanup, onMount, ParentComponent, ParentProps, Setter, Signal, useContext } from "solid-js";
|
||||||
import { createStore } from "solid-js/store";
|
import { createStore } from "solid-js/store";
|
||||||
import { isServer } from "solid-js/web";
|
import { isServer } from "solid-js/web";
|
||||||
import css from "./index.module.css";
|
import css from "./index.module.css";
|
||||||
|
@ -280,6 +280,9 @@ export function selectable<T extends object>(element: HTMLElement, options: Acce
|
||||||
element.dataset.selectionKey = selectionKey;
|
element.dataset.selectionKey = selectionKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let keyCounter = 0;
|
||||||
|
const createUniqueId = () => `key-${keyCounter++}`;
|
||||||
|
|
||||||
declare module "solid-js" {
|
declare module "solid-js" {
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
interface Directives {
|
interface Directives {
|
||||||
|
|
|
@ -4,6 +4,8 @@ import { createStore } from 'solid-js/store';
|
||||||
import { Person, people } from './experimental.data';
|
import { Person, people } from './experimental.data';
|
||||||
import { createEffect, createMemo, For } from 'solid-js';
|
import { createEffect, createMemo, For } from 'solid-js';
|
||||||
import css from './table.module.css';
|
import css from './table.module.css';
|
||||||
|
import { Menu } from '~/features/menu';
|
||||||
|
import { Command, createCommand, Modifier } from '~/features/command';
|
||||||
|
|
||||||
export default function TableExperiment() {
|
export default function TableExperiment() {
|
||||||
const columns: Column<Person>[] = [
|
const columns: Column<Person>[] = [
|
||||||
|
@ -57,7 +59,7 @@ export default function TableExperiment() {
|
||||||
sort: undefined,
|
sort: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rows = createMemo(() => createDataSet(people.slice(0, 1)));
|
const rows = createMemo(() => createDataSet(people));
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
rows().setGrouping(store.group);
|
rows().setGrouping(store.group);
|
||||||
|
@ -69,6 +71,12 @@ export default function TableExperiment() {
|
||||||
|
|
||||||
return <div class={css.root}>
|
return <div class={css.root}>
|
||||||
<Sidebar as="aside" label={'Filters'} class={css.sidebar}>
|
<Sidebar as="aside" label={'Filters'} class={css.sidebar}>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Commands</legend>
|
||||||
|
|
||||||
|
<Command.Handle command={createCommand('kaas', () => { }, { key: 'k', modifier: Modifier.Control })} />
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>table properties</legend>
|
<legend>table properties</legend>
|
||||||
|
|
||||||
|
@ -117,7 +125,7 @@ export default function TableExperiment() {
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<div class={css.content}>
|
<div class={css.content}>
|
||||||
<Table class={css.table} summary="List of people" rows={rows()} columns={columns} selectionMode={store.selectionMode} />
|
<Table class={css.table} rows={rows()} columns={columns} selectionMode={store.selectionMode} />
|
||||||
</div>
|
</div>
|
||||||
</div >;
|
</div >;
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue