Add measures evidences tab

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Jonathan
2025-06-09 12:14:56 +02:00
committed by Sacha Al Himdani
parent b660c0ce7f
commit 140857bfb3
92 changed files with 8427 additions and 865 deletions

View File

@@ -9,7 +9,7 @@ import { tv, type VariantProps } from "tailwind-variants";
import { Slot } from "../Slot";
export const button = tv({
base: "flex items-center justify-center gap-[6px] px-3 py-2 rounded-full cursor-pointer text-sm font-medium h-8 focus:outline-none whitespace-nowrap",
base: "flex items-center justify-center gap-[6px] px-3 py-2 rounded-full cursor-pointer text-sm font-medium h-8 focus:outline-none whitespace-nowrap w-max",
variants: {
variant: {
primary:

View File

@@ -0,0 +1,5 @@
import type {IconProps} from "./type.ts";
export function IconWarning({size = 24, className}: IconProps) {
return <svg className={className} xmlns="http://www.w3.org/2000/svg" width={size} height={size} fill="currentColor" viewBox="0 0 24 24"><path fill="currentColor" d="M12.188 1.993a3.001 3.001 0 0 1 2.41 1.51L22.596 17.5l.093.174A3 3 0 0 1 20.001 22H4v-.001a2.999 2.999 0 0 1-2.618-4.495l8-14a3 3 0 0 1 2.608-1.518l.198.007Zm-.33 2.002a1 1 0 0 0-.738.498l-.001.003-8 14-.003.004A1.002 1.002 0 0 0 3.99 20h16.008a1.001 1.001 0 0 0 .999-1 1 1 0 0 0-.134-.5l-.002-.004-8-14-.002-.003a1 1 0 0 0-.87-.507l-.132.009ZM12.01 16a1 1 0 0 1 0 2H12a1 1 0 0 1 0-2h.01ZM11 13V9a1 1 0 0 1 2 0v4a1 1 0 1 1-2 0Z"/></svg>
}

View File

@@ -71,6 +71,7 @@ export { IconSettingsGear2 } from "./IconSettingsGear2.tsx";
export { IconBook } from "./IconBook.tsx";
export { IconCircleQuestionmarkSolid } from "./IconCircleQuestionmarkSolid.tsx";
export { IconBlock1 } from "./IconBlock1.tsx";
export { IconWarning } from "./IconWarning.tsx";
export { IconChevronUp } from "./IconChevronUp.tsx";
export { IconBlock } from "./IconBlock.tsx";
export { IconChevronDown } from "./IconChevronDown.tsx";

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" d="M12.188 1.993a3.001 3.001 0 0 1 2.41 1.51L22.596 17.5l.093.174A3 3 0 0 1 20.001 22H4v-.001a2.999 2.999 0 0 1-2.618-4.495l8-14a3 3 0 0 1 2.608-1.518l.198.007Zm-.33 2.002a1 1 0 0 0-.738.498l-.001.003-8 14-.003.004A1.002 1.002 0 0 0 3.99 20h16.008a1.001 1.001 0 0 0 .999-1 1 1 0 0 0-.134-.5l-.002-.004-8-14-.002-.003a1 1 0 0 0-.87-.507l-.132.009ZM12.01 16a1 1 0 0 1 0 2H12a1 1 0 0 1 0-2h.01ZM11 13V9a1 1 0 0 1 2 0v4a1 1 0 1 1-2 0Z"/></svg>

After

Width:  |  Height:  |  Size: 560 B

View File

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

View File

@@ -0,0 +1,37 @@
import { useEffect, type ReactNode } from "react";
import { useTranslate } from "@probo/i18n";
import { useRefSync } from "@probo/hooks";
import { useInView } from "react-intersection-observer";
import { Spinner } from "../Spinner/Spinner";
type Props = {
children?: ReactNode;
onView: () => void;
loading?: boolean;
};
export function InfiniteScrollTrigger({ children, onView, loading }: Props) {
const { __ } = useTranslate();
const { ref, inView } = useInView({
threshold: 0,
});
const onViewRef = useRefSync(onView);
console.log(inView);
useEffect(() => {
if (inView && !loading) onViewRef.current();
}, [inView, loading]);
return (
<div
className="flex gap-2 items-center justify-center text-xs text-txt-secondary"
ref={ref}
>
{children ?? (
<>
<Spinner size={16} />
{__("Loading")}
</>
)}
</div>
);
}

View File

@@ -1,4 +1,4 @@
import { Table } from "./Table";
import { Table, Tbody, Td, Th, Thead, Tr, TrButton } from "./Table";
import type { Meta, StoryObj } from "@storybook/react";
export default {
@@ -9,4 +9,33 @@ export default {
type Story = StoryObj<typeof Table>;
export const Default: Story = {};
export const Default: Story = {
render: () => {
return (
<Table>
<Thead>
<Tr>
<Th>Header 1</Th>
<Th>Header 2</Th>
<Th>Header 3</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>Row 1, Cell 1</Td>
<Td>Row 1, Cell 2</Td>
<Td>Row 1, Cell 3</Td>
</Tr>
<Tr>
<Td>Row 2, Cell 1</Td>
<Td>Row 2, Cell 2</Td>
<Td>Row 2, Cell 3</Td>
</Tr>
<TrButton onClick={() => {}} colspan={3}>
Add row
</TrButton>
</Tbody>
</Table>
);
},
};

View File

@@ -1,12 +1,15 @@
import {
createContext,
useContext,
type FC,
type HTMLAttributes,
type PropsWithChildren,
type ReactNode,
} from "react";
import { Card } from "../Card/Card";
import { Link } from "react-router";
import clsx from "clsx";
import { IconPlusLarge } from "../Icons";
export function Table({
children,
@@ -34,7 +37,10 @@ export function Th({
}: PropsWithChildren<{ className?: string; width?: number }>) {
return (
<th
className={clsx("first:pl-6 last:pr-6 py-3", className)}
className={clsx(
"first:pl-6 last:pr-6 py-3 whitespace-nowrap",
className,
)}
style={{ width }}
>
{children}
@@ -98,12 +104,35 @@ export function Td({
<td
{...props}
width={width}
className={clsx(
"first:*:pl-6 *:block last:*:pr-6 *:py-3",
className,
)}
className={clsx("first:*:pl-6 *:pr-6 *:block *:py-3", className)}
>
<Link to={to}>{children}</Link>
</td>
);
}
export function TrButton({
icon = IconPlusLarge,
children,
colspan,
...props
}: {
colspan?: number;
children: ReactNode;
icon?: FC<{ size: number; className?: string }>;
} & HTMLAttributes<HTMLButtonElement>) {
const IconComponent = icon;
return (
<tr>
<td colSpan={colspan}>
<button
{...props}
className="py-2 bg-highlight hover:bg-highlight-hover active:bg-highlight-pressed cursor-pointer w-full flex gap-2 items-center justify-center"
>
<IconComponent size={16} />
{children}
</button>
</td>
</tr>
);
}

View File

@@ -1,4 +1,4 @@
import { Tabs, TabLink } from "./Tabs";
import { Tabs, TabLink, TabBadge } from "./Tabs";
import type { Meta, StoryObj } from "@storybook/react";
export default {
@@ -13,8 +13,10 @@ export const Default: Story = {
render: () => (
<Tabs>
<TabLink to="#">Tab 1</TabLink>
<TabLink to="#">Tab 2</TabLink>
<TabLink to="#">Tab 3</TabLink>
<TabLink to="/demo">Tab 2</TabLink>
<TabLink to="/demo2">
Tab 3 <TabBadge>3</TabBadge>
</TabLink>
</Tabs>
),
};

View File

@@ -21,7 +21,7 @@ export function TabLink(props: PropsWithChildren<{ to: string }>) {
<NavLink
className={(params) =>
clsx(
"py-4 hover:text-txt-primary border-b-2 active:border-border-active -mb-[1px] active:text-txt-primary",
"py-4 hover:text-txt-primary border-b-2 active:border-border-active -mb-[1px] active:text-txt-primary flex items-center gap-1",
params.isActive
? "border-border-active text-txt-primary"
: "border-transparent",
@@ -31,3 +31,11 @@ export function TabLink(props: PropsWithChildren<{ to: string }>) {
/>
);
}
export function TabBadge(props: PropsWithChildren) {
return (
<span className="py-1 px-2 text-txt-secondary text-xs font-semibold rounded-lg bg-highlight text-primary">
{props.children}
</span>
);
}

View File

@@ -19,7 +19,7 @@ type State = {
message: string | null;
variant?: ComponentProps<typeof Button>["variant"];
label?: string;
onConfirm: () => Promise<void>;
onConfirm: () => Promise<unknown>;
};
const useConfirmStore = create(

View File

@@ -29,11 +29,12 @@ export { Textarea } from "./Atoms/Textarea/Textarea.tsx";
export { Select, Option } from "./Atoms/Select/Select.tsx";
export { Label } from "./Atoms/Label/Label";
export { PropertyRow } from "./Atoms/PropertyRow/PropertyRow";
export { Table, Thead, Tr, Tbody, Td, Th } from "./Atoms/Table/Table";
export { Tabs, TabLink } from "./Atoms/Tabs/Tabs";
export { Table, Thead, Tr, Tbody, Td, Th, TrButton } from "./Atoms/Table/Table";
export { Tabs, TabLink, TabBadge } from "./Atoms/Tabs/Tabs";
export { Markdown } from "./Atoms/Markdown/Markdown";
export { Dropzone } from "./Atoms/Dropzone/Dropzone";
export { ControlItem } from "./Atoms/ControlItem/ControlItem";
export { InfiniteScrollTrigger } from "./Atoms/InfiniteScrollTrigger/InfiniteScrollTrigger";
// Molecules
export {