Add checkboxes for documents table

Helps #167

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Jonathan
2025-07-08 11:09:41 +02:00
committed by Sacha Al Himdani
parent 25b330f948
commit a4606f95f5
7 changed files with 148 additions and 18 deletions

View File

@@ -1,3 +1,4 @@
export { usePageTitle } from "./usePageTitle";
export { useToggle } from "./useToggle";
export { useRefSync } from "./useRefSync";
export { useList } from "./useList";

View File

@@ -0,0 +1,25 @@
import { useCallback, useState } from "react";
export function useList<T>(items: T[]) {
const [list, setList] = useState(items);
const push = useCallback(
(item: T) => setList((prev) => [...prev, item]),
[],
);
const remove = useCallback(
(item: T) => setList((prev) => prev.filter((i) => i !== item)),
[],
);
const toggle = useCallback(
(item: T) =>
setList((prev) =>
prev.includes(item)
? prev.filter((i) => i !== item)
: [...prev, item],
),
[],
);
const reset = useCallback((items: T[]) => setList(items), []);
const clear = useCallback(() => setList([]), []);
return { list, push, remove, toggle, reset, clear };
}

View File

@@ -0,0 +1,12 @@
import { Checkbox } from "./Checkbox";
import type { Meta, StoryObj } from "@storybook/react";
export default {
title: "Atoms/Checkbox",
component: Checkbox,
argTypes: {},
} satisfies Meta<typeof Checkbox>;
type Story = StoryObj<typeof Checkbox>;
export const Default: Story = {};

View File

@@ -0,0 +1,37 @@
import { useState } from "react";
import { tv } from "tailwind-variants";
import { IconCheckmark1 } from "../Icons";
type Props = {
checked: boolean;
onChange: (checked: boolean) => void;
};
const checkbox = tv({
base: "size-4 border border-border-mid relative rounded-sm flex items-center justify-center",
variants: {
isFocused: {
true: "shadow shadow-focus",
},
checked: {
true: "bg-accent text-invert",
},
},
});
export function Checkbox({ checked, onChange }: Props) {
const [isFocused, setFocus] = useState(false);
return (
<div className={checkbox({ isFocused, checked })}>
<input
className="absolute inset-0 opacity-0"
type="checkbox"
checked={checked}
onChange={(e) => onChange(e.target.checked)}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
/>
{checked && <IconCheckmark1 size={12} />}
</div>
);
}

View File

@@ -5,6 +5,7 @@ import {
type HTMLAttributes,
type PropsWithChildren,
type ReactNode,
type ThHTMLAttributes,
} from "react";
import { Card } from "../Card/Card";
import { Link } from "react-router";
@@ -34,9 +35,15 @@ export function Th({
children,
className,
width,
}: PropsWithChildren<{ className?: string; width?: number }>) {
...props
}: {
className?: string;
width?: number;
colspan?: number;
} & ThHTMLAttributes<HTMLTableCellElement>) {
return (
<th
{...props}
className={clsx(
"first:pl-6 last:pr-6 py-3 whitespace-nowrap",
className,

View File

@@ -37,6 +37,7 @@ export { ControlItem } from "./Atoms/ControlItem/ControlItem";
export { InfiniteScrollTrigger } from "./Atoms/InfiniteScrollTrigger/InfiniteScrollTrigger";
export { PriorityLevel } from "./Atoms/PriorityLevel/PriorityLevel.tsx";
export { TaskStateIcon } from "./Atoms/Icons/TaskStateIcon";
export { Checkbox } from "./Atoms/Checkbox/Checkbox";
// Molecules
export {