fix and expand table styles. man do I ever love scroll animations!!!
This commit is contained in:
parent
41bd3463e7
commit
f21fa5e224
2 changed files with 109 additions and 34 deletions
|
@ -1,26 +1,29 @@
|
||||||
.table {
|
.table {
|
||||||
|
--shadow: hsla(0 0% 0% / .1) 0 .5em 2em;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
display: block grid;
|
||||||
grid-template-columns: repeat(var(--columns), minmax(0, auto));
|
grid-template-columns: repeat(var(--columns), minmax(max-content, auto));
|
||||||
align-content: start;
|
align-content: start;
|
||||||
padding-inline: 1px;
|
padding-inline: 1px;
|
||||||
margin-inline: -1px;
|
margin-inline: -1px;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: inherit;
|
||||||
|
isolation: isolate;
|
||||||
|
|
||||||
block-size: 100%;
|
block-size: 100%;
|
||||||
|
|
||||||
&.selectable {
|
|
||||||
grid-template-columns: 2em repeat(calc(var(--columns) - 1), minmax(0, auto));
|
|
||||||
}
|
|
||||||
|
|
||||||
& input[type="checkbox"] {
|
& input[type="checkbox"] {
|
||||||
margin: .1em;
|
margin: .1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .cell {
|
& .cell {
|
||||||
display: grid;
|
display: block grid;
|
||||||
padding: var(--padding-m);
|
padding: var(--padding-m);
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: var(--radii-m);
|
border-radius: var(--radii-m);
|
||||||
|
background: inherit;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
&:has(textarea:focus) {
|
&:has(textarea:focus) {
|
||||||
border-color: var(--info);
|
border-color: var(--info);
|
||||||
|
@ -29,11 +32,32 @@
|
||||||
& > span {
|
& > span {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
position: sticky;
|
||||||
|
inset-inline-start: calc(var(--padding-m) * var(--depth));
|
||||||
|
padding-inline-start: calc(var(--padding-m) * (1 + var(--depth)));
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-start: 100%;
|
||||||
|
inset-block-start: -2px;
|
||||||
|
display: block;
|
||||||
|
inline-size: 2em;
|
||||||
|
block-size: calc(3px + 100%);
|
||||||
|
background: linear-gradient(90deg, hsla(0 0% 0% / .05), transparent);
|
||||||
|
animation: column-scroll-shadow linear both;
|
||||||
|
animation-timeline: scroll(inline);
|
||||||
|
animation-range: 0 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& :is(.header, .main, .footer) {
|
& :is(.header, .main, .footer) {
|
||||||
grid-column: span calc(2 + var(--columns));
|
grid-column: span calc(2 + var(--columns));
|
||||||
display: grid;
|
display: block grid;
|
||||||
grid-template-columns: subgrid;
|
grid-template-columns: subgrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,35 +65,49 @@
|
||||||
position: sticky;
|
position: sticky;
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
border-block-end: 1px solid var(--surface-300);
|
border-block-end: 1px solid var(--surface-300);
|
||||||
|
background-color: inherit;
|
||||||
|
z-index: 2;
|
||||||
|
animation: header-scroll-shadow linear both;
|
||||||
|
animation-timeline: scroll();
|
||||||
|
animation-range: 0 2em;
|
||||||
|
|
||||||
|
& > aside {
|
||||||
|
position: sticky;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
background: inherit;
|
||||||
|
padding: var(--padding-m);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .main {
|
& .main {
|
||||||
overflow: clip auto;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .row {
|
& .row {
|
||||||
--bg: var(--text);
|
|
||||||
--alpha: 0;
|
--alpha: 0;
|
||||||
grid-column: span calc(2 + var(--columns));
|
grid-column: span calc(2 + var(--columns));
|
||||||
display: grid;
|
display: block grid;
|
||||||
grid-template-columns: subgrid;
|
grid-template-columns: subgrid;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
background-color: color(from var(--bg) srgb r g b / var(--alpha));
|
background-color: inherit;
|
||||||
|
background-image: linear-gradient(0deg, oklch(from var(--info) l c h / var(--alpha)), oklch(from var(--info) l c h / var(--alpha)));
|
||||||
|
|
||||||
&:has(> .cell > :checked) {
|
&:has(> aside > :checked) {
|
||||||
--bg: var(--info);
|
|
||||||
--alpha: .1;
|
--alpha: .1;
|
||||||
border-color: var(--bg);
|
border-color: var(--info);
|
||||||
|
|
||||||
& span {
|
& span {
|
||||||
font-variation-settings: 'GRAD' 1000;
|
font-variation-settings: 'GRAD' 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
& + :has(> .cell> :checked) {
|
/* Remove the top border when directly preceded by a selected row */
|
||||||
|
& + :has(> aside > :checked) {
|
||||||
border-block-start-color: transparent;
|
border-block-start-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(+ .row > .cell > :checked) {
|
/* Remove the top border when directly succeeded by a selected row */
|
||||||
|
&:has(+ .row > aside > :checked) {
|
||||||
border-block-end-color: transparent;
|
border-block-end-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,15 +115,25 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
--alpha: .2 !important;
|
--alpha: .2 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > aside {
|
||||||
|
position: sticky;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
background: inherit;
|
||||||
|
padding: var(--padding-m);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& details {
|
& details {
|
||||||
display: contents;
|
display: contents;
|
||||||
|
background-color: inherit;
|
||||||
|
|
||||||
&::details-content {
|
&::details-content {
|
||||||
grid-column: span calc(2 + var(--columns));
|
grid-column: span calc(2 + var(--columns));
|
||||||
display: grid;
|
display: block grid;
|
||||||
grid-template-columns: subgrid;
|
grid-template-columns: subgrid;
|
||||||
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not([open])::details-content {
|
&:not([open])::details-content {
|
||||||
|
@ -93,19 +141,54 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& > summary {
|
& > summary {
|
||||||
|
position: sticky;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
grid-column: 1;
|
||||||
padding: .5em;
|
padding: .5em;
|
||||||
padding-inline-start: calc(var(--depth) * 1em + .5em);
|
padding-inline-start: calc(var(--depth) * 1em + .5em);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& > .row > .cell {
|
& > .row > .cell {
|
||||||
padding-inline-start: calc(var(--depth) * 1em + var(--padding-m));
|
padding-inline-start: calc(var(--depth) * 1em + var(--padding-m));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.selectable {
|
||||||
|
grid-template-columns: 2em repeat(calc(var(--columns) - 1), minmax(max-content, auto));
|
||||||
|
|
||||||
|
& .cell:first-of-type {
|
||||||
|
inset-inline-start: calc(2em + var(--padding-m) * var(--depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
& details > summary {
|
||||||
|
inset-inline-start: 2em;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@property --depth {
|
@property --depth {
|
||||||
syntax: "<number>";
|
syntax: "<number>";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
initial-value: 0;
|
initial-value: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes header-scroll-shadow {
|
||||||
|
from {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes column-scroll-shadow {
|
||||||
|
from {
|
||||||
|
background: linear-gradient(90deg, transparent, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
background: linear-gradient(90deg, hsla(0 0% 0% / .05), transparent);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -102,14 +102,14 @@ function Head<T extends Record<string, any>>(props: {}) {
|
||||||
|
|
||||||
return <header class={css.header}>
|
return <header class={css.header}>
|
||||||
<Show when={table.selectionMode() !== SelectionMode.None}>
|
<Show when={table.selectionMode() !== SelectionMode.None}>
|
||||||
<div class={css.cell}>
|
<aside>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={context.selection().length > 0 && context.selection().length === context.length()}
|
checked={context.selection().length > 0 && context.selection().length === context.length()}
|
||||||
indeterminate={context.selection().length !== 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()}
|
on:input={(e: InputEvent) => e.target.checked ? context.selectAll() : context.clear()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</aside>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<For each={table.columns()}>{
|
<For each={table.columns()}>{
|
||||||
|
@ -137,15 +137,15 @@ function Row<T extends Record<string, any>>(props: { key: string, value: T, dept
|
||||||
const values = createMemo(() => Object.entries(props.value));
|
const values = createMemo(() => Object.entries(props.value));
|
||||||
const isSelected = context.isSelected(props.key);
|
const isSelected = context.isSelected(props.key);
|
||||||
|
|
||||||
return <div class={css.row} use:selectable={{ value: props.value, key: props.key }}>
|
return <div class={css.row} style={{ '--depth': props.depth }} use:selectable={{ value: props.value, key: props.key }}>
|
||||||
<Show when={table.selectionMode() !== SelectionMode.None}>
|
<Show when={table.selectionMode() !== SelectionMode.None}>
|
||||||
<div class={css.cell}>
|
<aside>
|
||||||
<input type="checkbox" checked={isSelected()} on:input={() => context.select([props.key])} on:pointerdown={e => e.stopPropagation()} />
|
<input type="checkbox" checked={isSelected()} on:input={() => context.select([props.key])} on:pointerdown={e => e.stopPropagation()} />
|
||||||
</div>
|
</aside>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<For each={values()}>{
|
<For each={values()}>{
|
||||||
([k, v]) => <div style={k === props.groupedBy ? { '--depth': props.depth } : {}} class={css.cell}>{table.cellRenderers()[k]?.({ value: v }) ?? v}</div>
|
([k, v]) => <div class={css.cell}>{table.cellRenderers()[k]?.({ value: v }) ?? v}</div>
|
||||||
}</For>
|
}</For>
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
@ -153,16 +153,8 @@ function Row<T extends Record<string, any>>(props: { key: string, value: T, dept
|
||||||
function Group<T extends Record<string, any>>(props: { key: string, groupedBy: keyof T, nodes: Node<T>[], depth: number }) {
|
function Group<T extends Record<string, any>>(props: { key: string, groupedBy: keyof T, nodes: Node<T>[], depth: number }) {
|
||||||
const table = useTable();
|
const table = useTable();
|
||||||
|
|
||||||
const gridColumn = createMemo(() => {
|
|
||||||
const groupedBy = props.groupedBy;
|
|
||||||
const columns = table.columns();
|
|
||||||
const selectable = table.selectionMode() !== SelectionMode.None;
|
|
||||||
|
|
||||||
return columns.findIndex(({ id }) => id === groupedBy) + (selectable ? 2 : 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
return <details open>
|
return <details open>
|
||||||
<summary style={{ '--depth': props.depth, 'grid-column-start': gridColumn() }}>{props.key}</summary>
|
<summary style={{ '--depth': props.depth }}>{props.key}</summary>
|
||||||
|
|
||||||
<For each={props.nodes}>{
|
<For each={props.nodes}>{
|
||||||
node => <Node node={node} depth={props.depth + 1} groupedBy={props.groupedBy} />
|
node => <Node node={node} depth={props.depth + 1} groupedBy={props.groupedBy} />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue