diff --git a/apps/console2/src/components/form/ControlledField.tsx b/apps/console2/src/components/form/ControlledField.tsx index 1dd316b10..dddb296a2 100644 --- a/apps/console2/src/components/form/ControlledField.tsx +++ b/apps/console2/src/components/form/ControlledField.tsx @@ -19,7 +19,15 @@ export function ControlledField({ control={control} name={name} render={({ field }) => ( - + <> + + > )} /> ); diff --git a/apps/console2/src/components/form/PeopleSelect.tsx b/apps/console2/src/components/form/PeopleSelect.tsx index a44d69a9d..4c0e6eb8b 100644 --- a/apps/console2/src/components/form/PeopleSelect.tsx +++ b/apps/console2/src/components/form/PeopleSelect.tsx @@ -72,10 +72,11 @@ function PeopleSelectWithQuery({ variant="editor" placeholder={__("Select an owner")} onValueChange={field.onChange} + key={people?.length ?? 0} {...field} > {people?.map((p) => ( - + {p.fullName} diff --git a/apps/console2/src/components/risks/MeasureLinkDialog.tsx b/apps/console2/src/components/risks/MeasureLinkDialog.tsx index 412f11eed..2bd2efdcf 100644 --- a/apps/console2/src/components/risks/MeasureLinkDialog.tsx +++ b/apps/console2/src/components/risks/MeasureLinkDialog.tsx @@ -144,7 +144,7 @@ function MeasureLinkDialogContent(props: Omit) { ))} - + {filteredMeasures.map((measure) => ( ))} @@ -168,6 +168,9 @@ function MeasureRow(props: RowProps) { const isFetching = isFetchingAttach || isFetchingDetach; const onClick = () => { + if (isFetching) { + return; + } const action = isLinked ? detachMeasure : attachMeasure; action({ variables: { @@ -181,7 +184,10 @@ function MeasureRow(props: RowProps) { }; return ( - + {props.measure.name} {props.measure.category} {isLinked ? __("Unlink") : __("Link")} diff --git a/apps/console2/src/index.css b/apps/console2/src/index.css index dc3c6d32d..959b18833 100644 --- a/apps/console2/src/index.css +++ b/apps/console2/src/index.css @@ -4,3 +4,9 @@ @import "tw-animate-css"; @source "../../../packages/ui/src"; @source "../../../packages/helpers/src"; + +*:focus-visible { + box-shadow: var(--shadow-focus); + outline: none; + border-radius: 0.25rem; +} diff --git a/apps/console2/src/pages/organizations/risks/FormRiskDialog.tsx b/apps/console2/src/pages/organizations/risks/FormRiskDialog.tsx index ff1c90358..342315e7e 100644 --- a/apps/console2/src/pages/organizations/risks/FormRiskDialog.tsx +++ b/apps/console2/src/pages/organizations/risks/FormRiskDialog.tsx @@ -138,7 +138,7 @@ export default function FormRiskDialog({ }); const [showNote, toggleNote] = useToggle(false); - const [isOpen, setOpen] = useState(open); + const [isOpen, setOpen] = useState(!!open); return ( - + ; - } - return ( - {extractInitials(name ?? "")} + const className = clsx( + "bg-txt-success text-txt-invert rounded-full font-semibold flex items-center justify-center", + size === "s" && "size-5 text-xss", + size === "m" && "size-6 text-xxs", + size === "l" && "size-8 text-sm", + size === "xl" && "size-16 text-3xl", ); + if (src) { + return ; + } + return {extractInitials(name ?? "")}; } function extractInitials(name: string) { diff --git a/packages/ui/src/Atoms/Card/Card.tsx b/packages/ui/src/Atoms/Card/Card.tsx index aed7ab7c9..68cb717a3 100644 --- a/packages/ui/src/Atoms/Card/Card.tsx +++ b/packages/ui/src/Atoms/Card/Card.tsx @@ -9,7 +9,7 @@ type Props = PropsWithChildren<{ }>; const card = tv({ - base: "border border-border-low surface-1 rounded-2xl", + base: "border border-border-low bg-level-1 rounded-2xl", variants: { padded: { true: "p-6", diff --git a/packages/ui/src/Atoms/Dropdown/Dropdown.tsx b/packages/ui/src/Atoms/Dropdown/Dropdown.tsx index 9a233c5e9..03624961a 100644 --- a/packages/ui/src/Atoms/Dropdown/Dropdown.tsx +++ b/packages/ui/src/Atoms/Dropdown/Dropdown.tsx @@ -74,6 +74,7 @@ export function ActionDropdown( {...props} toggle={ diff --git a/packages/ui/src/Atoms/Logo/Logo.tsx b/packages/ui/src/Atoms/Logo/Logo.tsx index 5929f6f51..74f4c892d 100644 --- a/packages/ui/src/Atoms/Logo/Logo.tsx +++ b/packages/ui/src/Atoms/Logo/Logo.tsx @@ -13,7 +13,7 @@ export function Logo({ className }: Props) { viewBox="0 0 48 20" > diff --git a/packages/ui/src/Atoms/Select/Select.tsx b/packages/ui/src/Atoms/Select/Select.tsx index 9818c8ec6..712d7b0d7 100644 --- a/packages/ui/src/Atoms/Select/Select.tsx +++ b/packages/ui/src/Atoms/Select/Select.tsx @@ -13,13 +13,7 @@ import * as ScrollArea from "@radix-ui/react-scroll-area"; import { input } from "../Input/Input.tsx"; import { IconChevronGrabberVertical } from "../Icons/IconChevronGrabberVertical.tsx"; import { tv } from "tailwind-variants"; -import { - Children, - isValidElement, - type ComponentProps, - type PropsWithChildren, - type ReactNode, -} from "react"; +import { Children, type ComponentProps, type PropsWithChildren } from "react"; type Props = PropsWithChildren< { @@ -36,10 +30,10 @@ type Props = PropsWithChildren< const select = tv({ slots: { trigger: - "flex justify-between items-center data-placeholder:text-txt-tertiary whitespace-nowrap cursor-pointer", + "flex justify-between items-center data-placeholder:text-txt-tertiary whitespace-nowrap cursor-pointer *:first:contents", content: "z-100 shadow-mid rounded-[10px] bg-level-1 p-1 animate-in fade-in slide-in-from-top-2 overflow-y-auto overflow-y-auto", - option: "flex items-center h-8 text-sm font-medium text-txt-primary hover:bg-tertiary-hover active:bg-tertiary-pressed cursor-pointer px-[10px]", + option: "flex gap-2 items-center h-8 text-sm font-medium text-txt-primary hover:bg-tertiary-hover active:bg-tertiary-pressed cursor-pointer px-[10px]", icon: "-mr-1", }, variants: { @@ -79,23 +73,6 @@ const select = tv({ const { trigger, option, content, icon } = select(); -/** - * To display the selected value we need to find the selected option among children - */ -const findSelectedOption = ( - children: unknown[], - condition: (c: { props: Record }) => boolean, -): ReactNode => { - const selectedOptions = children.find( - // @ts-expect-error We know that the children are ReactElements with props - (c) => isValidElement(c) && condition(c), - ); - if (!isValidElement(selectedOptions)) { - return null; - } - return (selectedOptions.props as { children: ReactNode }).children; -}; - export function Select({ placeholder, children, @@ -103,26 +80,10 @@ export function Select({ value, ...props }: Props) { - const childrenArr = Children.toArray(children); - const valueNode = value - ? findSelectedOption( - childrenArr, - (c) => c.props.value?.toString() === value?.toString(), - ) - : undefined; - return ( - - - {valueNode ? ( - - {valueNode} - - ) : null} - - + @@ -152,10 +113,19 @@ export function Select({ } export function Option({ children, ...props }: ComponentProps) { + const hasSingleChildren = Children.count(children) <= 1; return ( - {children} + + {children} + ); diff --git a/packages/ui/src/Atoms/Table/Table.tsx b/packages/ui/src/Atoms/Table/Table.tsx index f90c454ba..fcd45d58f 100644 --- a/packages/ui/src/Atoms/Table/Table.tsx +++ b/packages/ui/src/Atoms/Table/Table.tsx @@ -58,13 +58,23 @@ export function Tbody({ children }: PropsWithChildren) { export function Td({ children, noLink, -}: PropsWithChildren<{ noLink?: boolean }>) { + className, +}: PropsWithChildren<{ noLink?: boolean; className?: string }>) { const { to } = useContext(TrContext); if (!to || noLink) { - return {children}; + return ( + + {children} + + ); } return ( - + {children} ); diff --git a/packages/ui/src/Layouts/Layout.tsx b/packages/ui/src/Layouts/Layout.tsx index 8f6746577..993d03659 100644 --- a/packages/ui/src/Layouts/Layout.tsx +++ b/packages/ui/src/Layouts/Layout.tsx @@ -37,14 +37,14 @@ export function Layout({ header, sidebar, children }: Props) { - + {header} diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css index 498fa8e4d..1e0fe6cd0 100644 --- a/packages/ui/src/theme.css +++ b/packages/ui/src/theme.css @@ -31,7 +31,6 @@ --color-active: #e4f7c7; --color-accent: #141e12; --color-danger: #ffefef; - --color-danger-plain: #dc3d43; --color-danger-dark: #dc3d43; --color-success: #eefadc; --color-info: #edf6ff; @@ -163,3 +162,76 @@ 0px 2px 4px 0px rgba(0, 0, 0, 0.08), 0px 2px 12px 0px rgba(0, 0, 0, 0.06); } + +@media (prefers-color-scheme: dark) { + :root { + --color-level-0: #151715; + --color-level-1: #1a1d19; + --color-level-2: #20241f; + --color-level-3: #3b3f3a; + + /* Text colors */ + --color-txt-primary: #eceeec; + --color-invert: #151715; + --color-txt-invert: var(--color-invert); + --color-txt-secondary: #9aa299; + --color-txt-tertiary: #778175; + --color-txt-quaternary: #4c514b; + --color-txt-disabled: #3b3f3a; + --color-txt-accent: #c4f042; + --color-txt-danger: #ff6369; + --color-txt-success: rgba(181, 255, 44, 0.72); + --color-txt-info: #52a9ff; + --color-txt-warning: #f1a10d; + + /* Backgrounds */ + --color-primary: #c4f042; + --color-invert: #151715; + --color-secondary: rgba(214, 251, 196, 0.06); + --color-tertiary: rgba(255, 255, 255, 0); + --color-subtle: rgba(213, 254, 175, 0.03); + --color-highlight: rgba(214, 251, 196, 0.06); + --color-active: rgba(239, 254, 226, 0.08); + --color-accent: #c4f042; + --color-danger: rgba(254, 58, 61, 0.13); + --color-danger-dark: rgba(255, 89, 95, 0.94); + --color-success: rgba(184, 253, 106, 0.06); + --color-info: rgba(22, 119, 254, 0.14); + --color-warning: rgba(254, 115, 0, 0.09); + --color-dialog: #151715; + + /* Borders */ + --color-border-solid: #2b2f2a; + --color-border-low: rgba(239, 254, 226, 0.08); + --color-border-mid: rgba(233, 254, 223, 0.1); + --color-border-strong: rgba(241, 255, 237, 0.25); + --color-border-active: rgba(253, 255, 253, 0.93); + --color-border-accent: #c4f042; + --color-border-danger: #f2555a; + --color-border-success: #c4f042; + --color-border-warning: #ffcb47; + --color-border-info: #369eff; + + /* Hover */ + --color-primary-hover: rgba(196, 240, 66, 0.88); + --color-invert-hover: #1a1d19; + --color-secondary-hover: rgba(214, 251, 196, 0.06); + --color-tertiary-hover: rgba(213, 254, 175, 0.03); + --color-subtle-hover: rgba(214, 251, 196, 0.06); + --color-highlight-hover: rgba(233, 254, 223, 0.1); + --color-accent-hover: rgba(183, 255, 50, 0.82); + --color-active-hover: rgba(233, 254, 223, 0.1); + --color-danger-hover: rgba(254, 58, 61, 0.7); + + /* Pressed */ + --color-primary-pressed: rgba(196, 240, 66, 0.84); + --color-invert-pressed: #20241f; + --color-secondary-pressed: rgba(239, 254, 226, 0.08); + --color-tertiary-pressed: rgba(214, 251, 196, 0.06); + --color-subtle-pressed: rgba(239, 254, 226, 0.08); + --color-highlight-pressed: rgba(236, 254, 229, 0.13); + --color-accent-pressed: rgba(209, 255, 70, 0.94); + --color-active-pressed: rgba(236, 254, 229, 0.13); + --color-danger-pressed: rgba(254, 58, 61, 0.5); + } +}