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:
committed by
Sacha Al Himdani
parent
b660c0ce7f
commit
140857bfb3
@@ -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:
|
||||
|
||||
5
packages/ui/src/Atoms/Icons/IconWarning.tsx
Normal file
5
packages/ui/src/Atoms/Icons/IconWarning.tsx
Normal 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>
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
1
packages/ui/src/Atoms/Icons/warning.svg
Normal file
1
packages/ui/src/Atoms/Icons/warning.svg
Normal 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 |
@@ -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: () => {},
|
||||
},
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user