<script module lang="ts">
import { tv, type VariantProps } from "tailwind-variants";
export type Band = "none" | "first" | "middle" | "last" | "only";
// `--graph-dot` : dot border color (default to `--graph-line`)
// `--graph-fill` : dot fill color (default to `--color-background-default`)
// `--graph-line` : line color (default to `--color-border-strong`)
export const graphCell = tv({
slots: {
root: [
"relative flex w-fit justify-center",
"before:absolute before:top-0 before:h-5 before:border-l before:border-(--line)",
"after:absolute after:top-5 after:bottom-0 after:border-l after:border-(--line)"
],
dot: "z-10 size-1.75 rounded-full border border-(--dot)"
},
variants: {
band: {
none: { root: "before:hidden after:hidden" },
first: { root: "before:hidden" },
middle: {},
last: { root: "after:hidden" },
only: { root: "before:hidden after:hidden" }
},
direction: {
vertical: {},
horizontal: { root: "origin-[--spacing(5)_--spacing(5)] rotate-90" }
},
fill: {
true: { dot: "bg-(--dot)" },
false: { dot: "bg-(--fill)" }
},
tail: {
true: {},
false: {}
}
},
compoundVariants: [
{
tail: true,
band: ["last", "only"],
class: {
root: [
"after:block after:w-px after:border-l-0",
"after:bg-linear-to-b",
"after:from-(--line)",
"after:to-transparent"
]
}
}
],
defaultVariants: {
band: "middle",
fill: false,
tail: false
}
});
export type GraphCellVariants = VariantProps<typeof graphCell>;
</script>
<script lang="ts">
interface Props {
band?: Band;
direction?: GraphCellVariants["direction"];
/** solid dot in `--graph-dot`, else hollow in `--graph-fill` */
fill?: boolean;
/** on `last` / `only`, trail the lower line off in a fade -- the run continues */
tail?: boolean;
class?: string;
style?: string;
}
let {
band = "middle",
direction = "vertical",
fill = false,
tail = false,
class: className,
style,
...rest
}: Props = $props();
const classes = $derived(graphCell({ band, direction, fill, tail }));
</script>
<div class="graph-cell {classes.root({ class: className })}" {style} {...rest}>
<div class="flex size-10 items-center justify-center">
{#if band !== "none"}
<div class={classes.dot()}></div>
{/if}
</div>
</div>
<style>
.graph-cell {
/* the fallbacks resolve once here instead of inline on every utility. they can't be
declared as `--graph-line` etc. directly -- a declaration on this element would beat
an ancestor's, and the caller could never set the colour from above. */
--line: var(--graph-line, var(--color-border-strong));
--dot: var(--graph-dot, var(--line));
--fill: var(--graph-fill, var(--color-background-default));
}
</style>