From 23ba227b4c741f179005c9e9bccc897a40a40c3c Mon Sep 17 00:00:00 2001 From: Alex <alex.zemliakov@pixelpoint.io> Date: Thu, 21 Nov 2024 23:05:10 +0800 Subject: [PATCH] fix: fixes for updated common layout and navbar (#7) fix: fixes for updated common layout and navbar --- packages/canary/configs/tailwind.ts | 8 + .../canary/src/components/alert-dialog.tsx | 78 +++- packages/canary/src/components/alert.tsx | 0 packages/canary/src/components/button.tsx | 8 +- packages/canary/src/components/calendar.tsx | 3 +- .../canary/src/components/dropdown-menu.tsx | 12 +- packages/canary/src/components/icon.tsx | 86 +++-- .../canary/src/components/navbar-user.tsx | 82 +++-- .../canary/src/components/navbar/index.tsx | 49 ++- packages/canary/src/components/popover.tsx | 4 +- .../canary/src/components/scroll-area.tsx | 24 +- packages/canary/src/components/search-box.tsx | 160 +++++---- packages/canary/src/components/sheet.tsx | 13 +- .../canary/src/icons/artifacts-gradient.svg | 9 + packages/canary/src/icons/artifacts-icon.svg | 7 + packages/canary/src/icons/artifacts.svg | 3 + packages/canary/src/icons/bookmark.svg | 19 - .../src/icons/chaos-engineering-gradient.svg | 9 + .../src/icons/chaos-engineering-icon.svg | 13 +- ...ud-mining.svg => cloud-costs-gradient.svg} | 5 +- .../canary/src/icons/cloud-costs-icon.svg | 11 + .../canary/src/icons/dashboards-gradient.svg | 11 + packages/canary/src/icons/dashboards-icon.svg | 8 + .../canary/src/icons/database-gradient.svg | 10 + packages/canary/src/icons/database-icon.svg | 7 + .../canary/src/icons/dev-envs-gradient.svg | 9 + packages/canary/src/icons/dev-envs-icon.svg | 7 + ...-content.svg => dev-insights-gradient.svg} | 0 .../canary/src/icons/dev-insights-icon.svg | 8 + ...ore-folder.svg => dev-portal-gradient.svg} | 0 packages/canary/src/icons/dev-portal-icon.svg | 7 + .../canary/src/icons/execution-gradient.svg | 9 + packages/canary/src/icons/execution-icon.svg | 6 +- .../canary/src/icons/featured-flags-icon.svg | 3 - .../src/icons/{flag.svg => flag-gradient.svg} | 5 +- packages/canary/src/icons/flag-icon.svg | 5 + .../canary/src/icons/incidents-gradient.svg | 9 + packages/canary/src/icons/incidents-icon.svg | 5 + ...zation.svg => infrastructure-gradient.svg} | 5 +- .../canary/src/icons/infrastructure-icon.svg | 8 + packages/canary/src/icons/log-out-icon.svg | 6 + packages/canary/src/icons/menu-dots-icon.svg | 7 + packages/canary/src/icons/navigation-icon.svg | 5 + packages/canary/src/icons/paint-icon.svg | 6 + packages/canary/src/icons/pin.svg | 8 +- .../canary/src/icons/pipelines-gradient.svg | 11 + packages/canary/src/icons/pipelines-icon.svg | 13 +- .../src/icons/repositories-gradient.svg | 9 + .../canary/src/icons/repositories-icon.svg | 18 +- ...d-tick.svg => security-tests-gradient.svg} | 5 +- .../canary/src/icons/security-tests-icon.svg | 6 + .../{chain.svg => supply-chain-gradient.svg} | 0 .../canary/src/icons/supply-chain-icon.svg | 8 + packages/canary/src/styles.css | 10 + .../src/components/branch-chooser.tsx | 6 +- .../branch-selector-dropdown.tsx | 10 +- .../branch-selector/branch-selector.tsx | 6 +- .../src/components/branches-list.tsx | 6 +- .../src/components/contact-card.tsx | 4 +- .../src/components/create-branch-dialog.tsx | 2 +- .../src/components/create-pipeline-page.tsx | 4 +- .../src/components/divergence-gauge.tsx | 2 +- .../src/components/execution-list.tsx | 2 +- .../src/components/execution/console-logs.tsx | 8 +- .../execution/execution-details.tsx | 12 +- .../components/execution/execution-status.tsx | 16 +- .../components/execution/key-value-table.tsx | 4 +- .../components/execution/stage-execution.tsx | 4 +- .../src/components/file-explorer.tsx | 8 +- .../src/components/filters/filter-trigger.tsx | 21 +- .../filters-bar/filter-variants/calendar.tsx | 4 +- .../filters-bar/filter-variants/checkbox.tsx | 21 +- .../filters-bar/filter-variants/number.tsx | 9 +- .../filters-bar/filter-variants/text.tsx | 7 +- .../filters/filters-bar/filters-bar.tsx | 21 +- .../filters/filters-bar/filters.tsx | 37 +- .../components/filters/filters-bar/sorts.tsx | 71 ++-- .../src/components/filters/filters.tsx | 2 +- .../src/components/filters/index.ts | 3 +- .../src/components/filters/use-filters.tsx | 2 +- .../src/components/filters/utils.ts | 7 +- .../src/components/form-field-set.tsx | 2 +- .../src/components/form-inputs/GroupInput.tsx | 2 +- .../src/components/image-carousel.tsx | 2 +- .../src/components/loaders/skeleton-list.tsx | 2 +- .../manage-navigation/draggable-item.tsx | 37 ++ .../components/manage-navigation/index.tsx | 224 ++++++++++++ .../manage-navigation-search.tsx | 156 ++++++++ .../src/components/markdown-viewer.tsx | 2 +- .../src/components/more-submenu.tsx | 55 +-- packages/playground/src/components/navbar.tsx | 194 ---------- .../playground/src/components/navbar/data.ts | 44 +++ .../src/components/navbar/index.tsx | 114 ++++++ .../src/components/navbar/navbar-ai/index.tsx | 37 ++ .../components/navbar/navbar-item/index.tsx | 93 +++++ .../components/navbar/navbar-link/index.tsx | 17 + .../components/navbar/navbar-user/index.tsx | 67 ++++ .../playground/src/components/navbar/types.ts | 37 ++ .../src/components/no-search-results.tsx | 4 +- .../src/components/pipeline-list.tsx | 2 +- .../pipeline-studio-footer-bar.tsx | 8 +- .../pipeline-studio-toolbar-actions.tsx | 4 +- .../step-form/step-form-section.tsx | 4 +- .../pipeline-studio/step-form/step-form.tsx | 4 +- .../step-palette/step-palette-content.tsx | 2 +- .../step-palette/step-palette-filters.tsx | 2 +- .../step-palette/step-palette-item.tsx | 4 +- .../step-palette/step-palette.tsx | 2 +- .../pipeline-studio/visual-yaml-toggle.tsx | 8 +- .../profile-settings-keys-list.tsx | 2 +- .../profile-settings-tokens-list.tsx | 2 +- .../ssh-key-create-dialog.tsx | 2 +- .../profile-settings/token-create-dialog.tsx | 2 +- .../project-settings/members-list.tsx | 8 +- .../project-settings/moreActionsDropdown.tsx | 4 +- .../pull-request/pull-request-commits.tsx | 4 +- .../pull-request-conversation-header.tsx | 10 +- .../pull-request/pull-request-diff-viewer.tsx | 6 +- .../pull-request/pull-request-panel.tsx | 4 +- .../pull-request/pull-request-side-bar.tsx | 2 +- .../pull-request-status-select-button.tsx | 3 +- .../sections/pull-request-changes-section.tsx | 10 +- .../repo-clone/clone-repo-dialog.tsx | 2 +- .../components/repo-clone/clone-repo-form.tsx | 2 +- .../src/components/repo-create-form.tsx | 2 +- .../playground/src/components/repo-list.tsx | 7 +- .../repo-branch-settings-rules-fields.tsx | 11 +- .../repo-settings-general-delete.tsx | 2 +- .../repo-settings-general-rules.tsx | 8 +- .../repo-settings-general-tooltip.tsx | 6 +- .../settings-create-new-user-form.tsx | 4 +- .../src/components/settings-menu.tsx | 60 ++-- .../playground/src/components/sha-badge.tsx | 4 +- .../src/components/steps/harness-steps.ts | 8 +- .../user-management/form-user-edit-dialog.tsx | 6 +- .../components/user-management/users-list.tsx | 6 +- .../playground/src/components/users-list.tsx | 4 +- .../src/components/webhook-list.tsx | 8 +- .../webhooks/create-webhook-form-data.ts | 3 +- .../playground/src/data/mockNavbarMenuData.ts | 337 ++++++++++++++++++ .../src/data/mockNavbarSubmenuData.ts | 122 ------- .../src/data/mockPinnedAndRecentMenuData.ts | 48 +++ .../src/hooks/use-drag-and-drop.tsx | 1 + packages/playground/src/index.ts | 2 +- .../src/layouts/RepoExecutionLayout.tsx | 2 +- .../playground/src/layouts/RootLayout.tsx | 168 ++++++--- .../SandboxPullRequestCompareLayout.tsx | 6 +- .../playground/src/layouts/SandboxRoot.tsx | 145 +++++++- .../src/layouts/SandboxSettings.tsx | 2 +- packages/playground/src/layouts/types.ts | 1 + .../src/pages/mocks/mockCurrentUserData.ts | 5 +- .../src/pages/pull-request-changes-page.tsx | 2 +- .../src/pages/sandbox-repo-code-page.tsx | 2 +- .../pages/settings-account-general-page.tsx | 2 +- packages/playground/src/utils/debaunce.ts | 14 + 155 files changed, 2393 insertions(+), 933 deletions(-) create mode 100644 packages/canary/src/components/alert.tsx create mode 100644 packages/canary/src/icons/artifacts-gradient.svg create mode 100644 packages/canary/src/icons/artifacts-icon.svg create mode 100644 packages/canary/src/icons/artifacts.svg delete mode 100644 packages/canary/src/icons/bookmark.svg create mode 100644 packages/canary/src/icons/chaos-engineering-gradient.svg rename packages/canary/src/icons/{cloud-mining.svg => cloud-costs-gradient.svg} (96%) create mode 100644 packages/canary/src/icons/cloud-costs-icon.svg create mode 100644 packages/canary/src/icons/dashboards-gradient.svg create mode 100644 packages/canary/src/icons/dashboards-icon.svg create mode 100644 packages/canary/src/icons/database-gradient.svg create mode 100644 packages/canary/src/icons/database-icon.svg create mode 100644 packages/canary/src/icons/dev-envs-gradient.svg create mode 100644 packages/canary/src/icons/dev-envs-icon.svg rename packages/canary/src/icons/{search-content.svg => dev-insights-gradient.svg} (100%) create mode 100644 packages/canary/src/icons/dev-insights-icon.svg rename packages/canary/src/icons/{more-folder.svg => dev-portal-gradient.svg} (100%) create mode 100644 packages/canary/src/icons/dev-portal-icon.svg create mode 100644 packages/canary/src/icons/execution-gradient.svg delete mode 100644 packages/canary/src/icons/featured-flags-icon.svg rename packages/canary/src/icons/{flag.svg => flag-gradient.svg} (87%) create mode 100644 packages/canary/src/icons/flag-icon.svg create mode 100644 packages/canary/src/icons/incidents-gradient.svg create mode 100644 packages/canary/src/icons/incidents-icon.svg rename packages/canary/src/icons/{filter-organization.svg => infrastructure-gradient.svg} (90%) create mode 100644 packages/canary/src/icons/infrastructure-icon.svg create mode 100644 packages/canary/src/icons/log-out-icon.svg create mode 100644 packages/canary/src/icons/menu-dots-icon.svg create mode 100644 packages/canary/src/icons/navigation-icon.svg create mode 100644 packages/canary/src/icons/paint-icon.svg create mode 100644 packages/canary/src/icons/pipelines-gradient.svg create mode 100644 packages/canary/src/icons/repositories-gradient.svg rename packages/canary/src/icons/{shield-tick.svg => security-tests-gradient.svg} (93%) create mode 100644 packages/canary/src/icons/security-tests-icon.svg rename packages/canary/src/icons/{chain.svg => supply-chain-gradient.svg} (100%) create mode 100644 packages/canary/src/icons/supply-chain-icon.svg create mode 100644 packages/playground/src/components/manage-navigation/draggable-item.tsx create mode 100644 packages/playground/src/components/manage-navigation/index.tsx create mode 100644 packages/playground/src/components/manage-navigation/manage-navigation-search.tsx delete mode 100644 packages/playground/src/components/navbar.tsx create mode 100644 packages/playground/src/components/navbar/data.ts create mode 100644 packages/playground/src/components/navbar/index.tsx create mode 100644 packages/playground/src/components/navbar/navbar-ai/index.tsx create mode 100644 packages/playground/src/components/navbar/navbar-item/index.tsx create mode 100644 packages/playground/src/components/navbar/navbar-link/index.tsx create mode 100644 packages/playground/src/components/navbar/navbar-user/index.tsx create mode 100644 packages/playground/src/components/navbar/types.ts create mode 100644 packages/playground/src/data/mockNavbarMenuData.ts create mode 100644 packages/playground/src/data/mockPinnedAndRecentMenuData.ts create mode 100644 packages/playground/src/utils/debaunce.ts diff --git a/packages/canary/configs/tailwind.ts b/packages/canary/configs/tailwind.ts index 212fc1b5a..688fdead9 100644 --- a/packages/canary/configs/tailwind.ts +++ b/packages/canary/configs/tailwind.ts @@ -118,6 +118,9 @@ export default { 8: 'hsl(var(--background-08))', 9: 'hsl(var(--background-09))', 10: 'hsl(var(--background-10))', + 11: 'hsl(var(--background-11))', + 12: 'hsl(var(--background-12))', + 13: 'hsl(var(--background-13))', danger: 'hsla(var(--background-danger))', success: 'hsla(var(--background-success))' }, @@ -144,12 +147,17 @@ export default { 6: 'hsl(var(--icon-06))', 7: 'hsl(var(--icon-07))', 8: 'hsl(var(--icon-08))', + 9: 'hsl(var(--icon-09))', + 10: 'hsl(var(--icon-10))', danger: 'hsl(var(--icon-danger))', alert: 'hsl(var(--icon-alert))', success: 'hsl(var(--icon-success))', accent: 'hsl(var(--icon-accent))' } }, + letterSpacing: { + tight: '-0.02em' + }, boxShadow: { 1: '0px 8px 16px rgba(0, 0, 0, 0.30)', 2: '0px 8px 8px rgba(0, 0, 0, 0.60)', diff --git a/packages/canary/src/components/alert-dialog.tsx b/packages/canary/src/components/alert-dialog.tsx index 44bd28e2e..9b0002729 100644 --- a/packages/canary/src/components/alert-dialog.tsx +++ b/packages/canary/src/components/alert-dialog.tsx @@ -10,37 +10,66 @@ const AlertDialogTrigger = AlertDialogPrimitive.Trigger const AlertDialogPortal = AlertDialogPrimitive.Portal +interface AlertDialogOverlayProps extends React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay> { + onClick?: () => void +} + const AlertDialogOverlay = React.forwardRef< React.ElementRef<typeof AlertDialogPrimitive.Overlay>, - React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay> ->(({ className, ...props }, ref) => ( + AlertDialogOverlayProps +>(({ className, onClick, ...props }, ref) => ( <AlertDialogPrimitive.Overlay className={cn( - 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', + 'bg-background-7/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50', className )} {...props} ref={ref} + onClick={onClick} /> )) AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName +interface AlertDialogContentProps extends React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> { + onOverlayClick?: () => void +} + const AlertDialogContent = React.forwardRef< React.ElementRef<typeof AlertDialogPrimitive.Content>, - React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> ->(({ className, ...props }, ref) => ( - <AlertDialogPortal> - <AlertDialogOverlay /> - <AlertDialogPrimitive.Content - ref={ref} - className={cn( - 'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg', - className - )} - {...props} - /> - </AlertDialogPortal> -)) + AlertDialogContentProps +>(({ className = 'max-w-lg', children, onOverlayClick, ...props }, ref) => { + const mainContent: React.ReactNode[] = [] + let footer: React.ReactNode = null + + React.Children.forEach(children, child => { + if (React.isValidElement(child) && child.type === AlertDialogFooter) { + footer = child + } else { + mainContent.push(child) + } + }) + + return ( + <AlertDialogPortal> + <AlertDialogOverlay onClick={onOverlayClick} /> + <AlertDialogPrimitive.Content + ref={ref} + className={cn( + 'bg-background-1 shadow-1 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 flex w-full translate-x-[-50%] translate-y-[-50%] flex-col overflow-hidden rounded-[0.625rem] border duration-200', + className + )} + {...props} + > + <div + className={cn('flex flex-col gap-y-4 overflow-y-auto p-5', footer ? 'max-h-[calc(100%-65px)]' : 'max-h-full')} + > + {mainContent} + </div> + {footer} + </AlertDialogPrimitive.Content> + </AlertDialogPortal> + ) +}) AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( @@ -49,7 +78,14 @@ const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDiv AlertDialogHeader.displayName = 'AlertDialogHeader' const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( - <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} /> + <div + className={cn( + 'bg-background-2 border-borders-1 relative mt-auto flex h-fit flex-col-reverse gap-x-4 border-t px-5 py-4 sm:flex-row sm:justify-end', + 'before:from-background-1 before:pointer-events-none before:absolute before:inset-x-0 before:-top-px before:h-3 before:-translate-y-full before:bg-gradient-to-t before:to-transparent', + className + )} + {...props} + /> ) AlertDialogFooter.displayName = 'AlertDialogFooter' @@ -57,7 +93,11 @@ const AlertDialogTitle = React.forwardRef< React.ElementRef<typeof AlertDialogPrimitive.Title>, React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title> >(({ className, ...props }, ref) => ( - <AlertDialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold', className)} {...props} /> + <AlertDialogPrimitive.Title + ref={ref} + className={cn('text-foreground-1 text-xl font-semibold tracking-tight', className)} + {...props} + /> )) AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName diff --git a/packages/canary/src/components/alert.tsx b/packages/canary/src/components/alert.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/packages/canary/src/components/button.tsx b/packages/canary/src/components/button.tsx index 0e5ba7edc..8b9f3397b 100644 --- a/packages/canary/src/components/button.tsx +++ b/packages/canary/src/components/button.tsx @@ -12,11 +12,12 @@ const buttonVariants = cva( variant: { default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90', destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', - outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', + outline: 'border border-borders-2 text-foreground-2 hover:border-borders-6 hover:text-foreground-8', secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', tertiary: 'bg-tertiary text-secondary-foreground shadow-sm hover:bg-tertiary/80', - ghost: 'hover:bg-accent hover:text-accent-foreground', + ghost: 'text-foreground-8 hover:bg-background-4 hover:text-foreground-1', link: 'text-primary underline-offset-4 hover:underline', + link_accent: 'text-foreground-accent underline-offset-4 hover:underline', split: 'flex items-center gap-1.5 border p-0', 'gradient-border': 'bg-background-2 text-foreground-1 hover:bg-background-8', custom: '' @@ -28,7 +29,8 @@ const buttonVariants = cva( lg: 'h-10 px-8', icon: 'size-8', sm_icon: 'size-7', - xs_split: 'h-auto p-0 text-xs font-medium' + xs_split: 'h-auto p-0 text-xs font-medium', + custom: '' }, borderRadius: { default: '', diff --git a/packages/canary/src/components/calendar.tsx b/packages/canary/src/components/calendar.tsx index 44f9cc514..5a42015ac 100644 --- a/packages/canary/src/components/calendar.tsx +++ b/packages/canary/src/components/calendar.tsx @@ -1,6 +1,5 @@ import * as React from 'react' -import { DayPicker } from 'react-day-picker' -import type { DateRange } from 'react-day-picker' +import { DayPicker, type DateRange } from 'react-day-picker' import { buttonVariants } from '@/components/button' import { cn } from '@/lib/utils' diff --git a/packages/canary/src/components/dropdown-menu.tsx b/packages/canary/src/components/dropdown-menu.tsx index 13bd4387b..568281734 100644 --- a/packages/canary/src/components/dropdown-menu.tsx +++ b/packages/canary/src/components/dropdown-menu.tsx @@ -17,7 +17,7 @@ const DropdownMenuTrigger = React.forwardRef< <DropdownMenuPrimitive.Trigger ref={ref} className={cn( - 'ring-offset-background outline-none focus:ring-2 focus:ring-offset-2 [&>svg.chevron-down]:duration-100 [&>svg.chevron-down]:ease-in-out [&>svg.chevron-down]:data-[state=open]:rotate-180', + 'ring-offset-background group outline-none focus:ring-2 focus:ring-offset-2 [&>svg.chevron-down]:duration-100 [&>svg.chevron-down]:ease-in-out [&>svg.chevron-down]:data-[state=open]:rotate-180', { 'flex cursor-pointer items-center border-l border-inherit px-2.5 py-0.5 outline-none': insideSplitButton }, className )} @@ -86,6 +86,7 @@ const DropdownMenuContent = React.forwardRef< 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', className )} + onCloseAutoFocus={e => e.preventDefault()} {...props} /> </DropdownMenuPrimitive.Portal> @@ -101,7 +102,8 @@ const DropdownMenuItem = React.forwardRef< <DropdownMenuPrimitive.Item ref={ref} className={cn( - 'text-foreground-8 focus:bg-background-4 focus:text-primary relative flex cursor-pointer select-none items-center rounded-sm px-2 py-[7px] text-sm outline-none transition-colors', + 'text-foreground-8 focus:bg-background-4 focus:text-primary relative flex cursor-pointer select-none items-center rounded px-2 py-[7px] text-sm outline-none transition-colors', + 'data-[highlighted]:bg-background-4', 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50', inset && 'pl-8', className @@ -124,9 +126,9 @@ const DropdownMenuCheckboxItem = React.forwardRef< checked={checked} {...props} > - <span className="border-borders-9 group-data-[state=checked]:border-icons-2 absolute left-2 flex h-4 w-4 items-center justify-center rounded-sm border"> - <DropdownMenuPrimitive.ItemIndicator className="bg-icons-2 flex h-full w-full items-center justify-center"> - <Icon className="text-icons-5 h-[7px]" name="checkbox" /> + <span className="absolute left-2 flex size-4 items-center justify-center rounded-sm border border-borders-9 group-data-[state=checked]:border-icons-2"> + <DropdownMenuPrimitive.ItemIndicator className="flex size-full items-center justify-center bg-icons-2"> + <Icon className="h-[7px] text-icons-5" name="checkbox" /> </DropdownMenuPrimitive.ItemIndicator> </span> <span className="text-14 text-foreground-8">{children}</span> diff --git a/packages/canary/src/components/icon.tsx b/packages/canary/src/components/icon.tsx index c86495493..0454cbc4b 100644 --- a/packages/canary/src/components/icon.tsx +++ b/packages/canary/src/components/icon.tsx @@ -7,9 +7,10 @@ import AddFolder from '../icons/add-folder.svg' import AISparks from '../icons/ai-sparks.svg' import AppleShortcut from '../icons/apple-shortcut.svg' import ArrowLong from '../icons/arrow-long.svg' +import ArtifactsGradient from '../icons/artifacts-gradient.svg' +import Artifacts from '../icons/artifacts-icon.svg' import BitrisePlugin from '../icons/bitrise-plugin.svg' import BookmarkIcon from '../icons/bookmark-icon.svg' -import Bookmark from '../icons/bookmark.svg' import BoxCloning from '../icons/box-cloning.svg' import BoxGuide from '../icons/box-guide.svg' import BoxLightning from '../icons/box-lightning.svg' @@ -17,8 +18,8 @@ import BoxPullRequests from '../icons/box-pull-requests.svg' import Branch from '../icons/branch.svg' import Briefcase from '../icons/briefcase-icon.svg' import CancelGrey from '../icons/cancel-grey.svg' -import Chain from '../icons/chain.svg' import Changes from '../icons/changes.svg' +import ChaosEngineeringGradient from '../icons/chaos-engineering-gradient.svg' import ChaosEngineering from '../icons/chaos-engineering-icon.svg' import Checkbox from '../icons/checkbox.svg' import Checks from '../icons/checks.svg' @@ -34,23 +35,34 @@ import ClockIcon from '../icons/clock-icon.svg' import Clock from '../icons/clock.svg' import Clone from '../icons/clone.svg' import Close from '../icons/close.svg' -import CloudMining from '../icons/cloud-mining.svg' +import CloudCostsGradient from '../icons/cloud-costs-gradient.svg' +import CloudCosts from '../icons/cloud-costs-icon.svg' import Cog6 from '../icons/cog-6.svg' import Comments from '../icons/comments.svg' import Connectors from '../icons/connectors-icon.svg' import CreateWorkspace from '../icons/create-workspace.svg' +import DashboardsGradient from '../icons/dashboards-gradient.svg' +import Dashboards from '../icons/dashboards-icon.svg' +import DatabaseGradient from '../icons/database-gradient.svg' +import Database from '../icons/database-icon.svg' +import DevEnvsGradient from '../icons/dev-envs-gradient.svg' +import DevEnvs from '../icons/dev-envs-icon.svg' +import DevInsightsGradient from '../icons/dev-insights-gradient.svg' +import DevInsights from '../icons/dev-insights-icon.svg' +import DevPortalGradient from '../icons/dev-portal-gradient.svg' +import DevPortal from '../icons/dev-portal-icon.svg' import Download from '../icons/download.svg' import Edit from '../icons/edit.svg' import Environment from '../icons/environment-icon.svg' +import ExecutionGradient from '../icons/execution-gradient.svg' import Execution from '../icons/execution-icon.svg' import Eye from '../icons/eye-icon.svg' import Fail from '../icons/fail.svg' -import FeaturedFlags from '../icons/featured-flags-icon.svg' import FileIcon from '../icons/file-icon.svg' import File from '../icons/file.svg' import FilterList from '../icons/filter-list.svg' -import FilterOrganization from '../icons/filter-organization.svg' -import Flag from '../icons/flag.svg' +import FlagGradient from '../icons/flag-gradient.svg' +import Flag from '../icons/flag-icon.svg' import FolderIcon from '../icons/folder-icon.svg' import Folder from '../icons/folder.svg' import GitBranch from '../icons/git-branch.svg' @@ -63,15 +75,21 @@ import HarnessLogoText from '../icons/harness-logo-text.svg' import HarnessPlugin from '../icons/harness-plugin.svg' import Harness from '../icons/harness.svg' import Hierarchy from '../icons/hierarchy-icon.svg' +import IncidentsGradient from '../icons/incidents-gradient.svg' +import Incidents from '../icons/incidents-icon.svg' import InfoCircle from '../icons/info-circle.svg' +import InfrastructureGradient from '../icons/infrastructure-gradient.svg' +import Infrastructure from '../icons/infrastructure-icon.svg' import Key from '../icons/key-icon.svg' import Lightning from '../icons/lightning.svg' +import LogOut from '../icons/log-out-icon.svg' import HarnessLogoGradientEllipse from '../icons/logo-gradient-ellipse.svg' import HarnessLogoGradient from '../icons/logo-gradient.svg' +import MenuDots from '../icons/menu-dots-icon.svg' import Merged from '../icons/merged.svg' import MoreDotsFill from '../icons/more-dots-fill-icon.svg' import Ellipsis from '../icons/more-dots-icon.svg' -import MoreFolder from '../icons/more-folder.svg' +import Navigation from '../icons/navigation-icon.svg' import NoDataBranches from '../icons/no-data-branches.svg' import NoDataCog from '../icons/no-data-cog.svg' import NoDataFolder from '../icons/no-data-folder.svg' @@ -83,8 +101,10 @@ import NoSearchMagnifyingGlass from '../icons/no-search-magnifying-glass.svg' import NodeLogo from '../icons/node-logo.svg' import Notification from '../icons/notification-icon.svg' import OpenPR from '../icons/open-pr.svg' +import Paint from '../icons/paint-icon.svg' import PendingClock from '../icons/pending-clock.svg' import Pin from '../icons/pin.svg' +import PipelinesGradient from '../icons/pipelines-gradient.svg' import Pipelines from '../icons/pipelines-icon.svg' import Play from '../icons/play-solid.svg' import Plug from '../icons/plug.svg' @@ -98,19 +118,20 @@ import PrReview from '../icons/pr-review.svg' import Pull from '../icons/pull-icon.svg' import PythonAndNodeLogo from '../icons/python-and-node-logo.svg' import PythonLogo from '../icons/python-logo.svg' +import RepositoriesGradient from '../icons/repositories-gradient.svg' import Repositories from '../icons/repositories-icon.svg' import Rocket from '../icons/rocket.svg' import RunTest from '../icons/run-test.svg' import Run from '../icons/run.svg' import Running from '../icons/running.svg' -import SearchContent from '../icons/search-content.svg' import Search from '../icons/search-icon.svg' import Secrets from '../icons/secrets-icon.svg' +import SecurityTestsGradient from '../icons/security-tests-gradient.svg' +import SecurityTests from '../icons/security-tests-icon.svg' import Settings1 from '../icons/setting-1.svg' import Settings2 from '../icons/setting-2.svg' import Shield from '../icons/shield-icon.svg' import ShieldLock from '../icons/shield-lock.svg' -import ShieldTick from '../icons/shield-tick.svg' import SidebarIcon from '../icons/sidebar-icon.svg' import Signpost from '../icons/signpost.svg' import Snow from '../icons/snow-icon.svg' @@ -120,6 +141,8 @@ import Stack from '../icons/stack-icon.svg' import Star from '../icons/star-icon.svg' import SubMenuEllipse from '../icons/sub-menu-ellipse.svg' import Success from '../icons/success.svg' +import SupplyChainGradient from '../icons/supply-chain-gradient.svg' +import SupplyChain from '../icons/supply-chain-icon.svg' import Tag from '../icons/tag.svg' import Tasks from '../icons/tasks.svg' import Tick from '../icons/tick.svg' @@ -151,10 +174,10 @@ const IconNameMap = { checkbox: Checkbox, harness: Harness, pipelines: Pipelines, - 'featured-flags': FeaturedFlags, + 'pipelines-gradient': PipelinesGradient, ellipsis: Ellipsis, repositories: Repositories, - 'chaos-engineering': ChaosEngineering, + 'repositories-gradient': RepositoriesGradient, environment: Environment, secrets: Secrets, connectors: Connectors, @@ -226,15 +249,7 @@ const IconNameMap = { unpin: Unpin, rocket: Rocket, plug: Plug, - flag: Flag, - 'filter-organization': FilterOrganization, 'shield-lock': ShieldLock, - 'more-folder': MoreFolder, - bookmark: Bookmark, - 'search-content': SearchContent, - chain: Chain, - 'shield-tick': ShieldTick, - 'cloud-mining': CloudMining, 'pr-merged': PRMerged, run: Run, 'run-test': RunTest, @@ -275,7 +290,38 @@ const IconNameMap = { 'circle-arrows-updown': CircleArrowsUpDown, 'chevron-fill-down': ChevronFillDown, 'more-dots-fill': MoreDotsFill, - execution: Execution + execution: Execution, + 'execution-gradient': ExecutionGradient, + paint: Paint, + navigation: Navigation, + logOut: LogOut, + 'database-gradient': DatabaseGradient, + database: Database, + 'artifacts-gradient': ArtifactsGradient, + artifacts: Artifacts, + 'infrastructure-gradient': InfrastructureGradient, + infrastructure: Infrastructure, + 'flag-gradient': FlagGradient, + flag: Flag, + 'dev-portal-gradient': DevPortalGradient, + 'dev-portal': DevPortal, + 'dev-envs-gradient': DevEnvsGradient, + 'dev-envs': DevEnvs, + 'dev-insights-gradient': DevInsightsGradient, + 'dev-insights': DevInsights, + 'security-tests-gradient': SecurityTestsGradient, + 'security-tests': SecurityTests, + 'supply-chain-gradient': SupplyChainGradient, + 'supply-chain': SupplyChain, + 'cloud-costs-gradient': CloudCostsGradient, + 'cloud-costs': CloudCosts, + 'incidents-gradient': IncidentsGradient, + incidents: Incidents, + 'chaos-engineering-gradient': ChaosEngineeringGradient, + 'chaos-engineering': ChaosEngineering, + 'dashboards-gradient': DashboardsGradient, + dashboards: Dashboards, + 'menu-dots': MenuDots // fork: Fork } satisfies Record<string, React.FunctionComponent<React.SVGProps<SVGSVGElement>>> diff --git a/packages/canary/src/components/navbar-user.tsx b/packages/canary/src/components/navbar-user.tsx index 94f575ea8..88358246c 100644 --- a/packages/canary/src/components/navbar-user.tsx +++ b/packages/canary/src/components/navbar-user.tsx @@ -1,50 +1,90 @@ +import { Fragment } from 'react' + import { getInitials } from '@/utils/StringUtils' import { Avatar, AvatarFallback, AvatarImage, + cn, DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuSeparator, DropdownMenuTrigger } from '..' -interface items { +interface UserItem { element: React.ReactNode - key: number + key: string + isSeparated?: boolean +} + +interface UserBlockProps { + username: string + role?: string + url?: string + isButton?: boolean + className?: string +} + +const UserBlock = ({ username, role, url, isButton = false, className }: UserBlockProps) => { + const Tag = isButton ? 'button' : 'div' + + return ( + <Tag + className={cn( + 'relative grid w-full grid-cols-[auto_1fr] grid-rows-2 items-center justify-start gap-x-2.5 text-left', + className + )} + > + {isButton && ( + <div className="absolute -inset-2 rounded duration-100 ease-in-out group-hover:bg-background-4 group-data-[state=open]:bg-background-4" /> + )} + <div className="col-start-1 row-span-2"> + <Avatar className="overflow-hidden rounded-md" size="8"> + {url && <AvatarImage src={url} alt="user" />} + <AvatarFallback>{getInitials(username)}</AvatarFallback> + </Avatar> + </div> + <p className="col-start-2 row-start-1 text-13 font-medium leading-none text-foreground-1">{username}</p> + {!!role && ( + <p className="col-start-2 row-start-2 mt-0.5 text-13 font-normal leading-none text-foreground-4">{role}</p> + )} + </Tag> + ) } const Root: React.FC<{ username: string - email?: string + role?: string url?: string - menuItems?: items[] -}> = ({ username, email, url, menuItems }) => { + menuItems?: UserItem[] +}> = ({ username, role, url, menuItems }) => { return ( <DropdownMenu> <DropdownMenuTrigger asChild> - <div className="group relative grid cursor-pointer grid-cols-[auto_1fr] grid-rows-2 items-center justify-start gap-x-2.5"> - <div className="absolute -inset-2 rounded duration-100 ease-in-out group-hover:bg-primary/5" /> - <div className="col-start-1 row-span-2"> - <Avatar className="overflow-hidden rounded-md" size="8"> - {url && <AvatarImage src={url} alt="user" />} - <AvatarFallback>{getInitials(username)}</AvatarFallback> - </Avatar> - </div> - <p className="col-start-2 row-start-1 text-13 font-medium leading-none text-foreground-1">{username}</p> - {!!email && ( - <p className="col-start-2 row-start-2 mt-0.5 text-13 font-normal leading-none text-foreground-4">{email}</p> - )} + <div> + <UserBlock username={username} role={role} url={url} isButton /> </div> </DropdownMenuTrigger> {menuItems && ( - <DropdownMenuContent align="end" className="mb-2 w-[180px]"> + <DropdownMenuContent + className="ml-3 w-[230px] bg-background-1" + align="start" + sideOffset={-40} + alignOffset={187} + > + <UserBlock className="p-2" username={username} role={role} url={url} /> + <DropdownMenuSeparator /> {menuItems.map(itm => { return ( - <DropdownMenuItem asChild key={itm.key}> - {itm.element} - </DropdownMenuItem> + <Fragment key={itm.key}> + {!!itm?.isSeparated && <DropdownMenuSeparator />} + <DropdownMenuItem className="[&_svg]:data-[highlighted]:text-icons-2" asChild> + {itm.element} + </DropdownMenuItem> + </Fragment> ) })} </DropdownMenuContent> diff --git a/packages/canary/src/components/navbar/index.tsx b/packages/canary/src/components/navbar/index.tsx index 5edc52a55..f5d89d94c 100644 --- a/packages/canary/src/components/navbar/index.tsx +++ b/packages/canary/src/components/navbar/index.tsx @@ -1,8 +1,9 @@ +import { Icon } from '@/components/icon' import { cn } from '@/lib/utils' +import { isSafari } from '@/utils/isSafari' + import { Text } from '../text' import noiseBg from './noise.png' -import { Icon } from '@/components/icon' -import { isSafari } from '@/utils/isSafari' interface NavbarRootProps { className?: string @@ -17,7 +18,8 @@ function Root({ className, children, isSubMenu = false }: NavbarRootProps) { 'border-borders-5 bg-background-7 grid h-screen w-[220px] select-none grid-rows-[auto_1fr_auto] overflow-y-auto border-r', { 'bg-background-7/70 backdrop-blur-[10px]': isSubMenu }, className - )}> + )} + > {!isSubMenu && ( <> <div @@ -63,8 +65,8 @@ function Header({ children }: { children: React.ReactNode }) { return <div className="sticky top-0 z-20 grid items-center">{children}</div> } -function Content({ children }: { children: React.ReactNode }) { - return <div className="flex min-w-0 flex-col">{children}</div> +function Content({ children, className }: { children: React.ReactNode; className?: string }) { + return <div className={cn('flex min-w-0 flex-col', className)}>{children}</div> } interface GroupProps { @@ -82,7 +84,8 @@ function Group({ children, title, topBorder, isSubMenu = false, titleClassName } 'flex w-full flex-col overflow-x-hidden px-5', { 'border-borders-5 border-t pt-2.5': topBorder }, isSubMenu ? 'pb-2.5' : 'gap-1.5 pb-3' - )}> + )} + > {title && ( <div className={cn('text-foreground-7 mt-1.5', isSubMenu ? 'mb-3' : 'mb-2.5', titleClassName)}> <p className="text-xs font-normal">{title}</p> @@ -108,21 +111,22 @@ function Item({ icon, text, description, active, submenuItem, className }: ItemP return ( <div className={cn( - 'group relative grid cursor-pointer select-none grid-cols-[auto_1fr] items-center gap-3 py-2', + 'group relative grid cursor-pointer select-none grid-cols-[auto_1fr] items-center gap-3 pb-[0.6875rem] pt-[0.5625rem]', { 'gap-0': !icon }, className - )}> + )} + > <div className={cn( 'group-hover:bg-background-4 absolute -inset-x-3 z-0 h-full w-auto rounded-[10px] bg-transparent', { 'bg-background-4': active } )} /> - <div className="z-10 col-start-1 row-span-full flex items-center"> + <div className="z-10 col-start-1 row-span-full mt-px flex items-center"> {icon ? ( - <div className="sub-menu-icon-bg border-borders-1 bg-background-2 relative flex size-8 place-content-center place-items-center rounded border"> + <div className="sub-menu-icon-bg relative flex size-8 place-content-center place-items-center rounded border border-borders-1 bg-background-2"> <Icon - className="text-foreground-3 absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" + className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-foreground-3" name="sub-menu-ellipse" size={18} /> @@ -139,19 +143,12 @@ function Item({ icon, text, description, active, submenuItem, className }: ItemP weight="medium" className={cn('text-foreground-2 group-hover:text-foreground-1 z-10 w-full duration-0 ease-in-out', { 'text-foreground-1': active - })}> + })} + > {text} </Text> {!!description && ( - <Text - size={0} - truncate - className={cn( - 'text-foreground-5 group-hover:text-foreground-3 z-10 w-full truncate leading-[1.125rem] duration-0 ease-in-out', - { - 'text-foreground-3': active - } - )}> + <Text className="z-10 w-full truncate leading-4 text-foreground-4 duration-0 ease-in-out" size={1} truncate> {description} </Text> )} @@ -165,9 +162,10 @@ function Item({ icon, text, description, active, submenuItem, className }: ItemP {icon && ( <div className={cn( - 'text-icons-4 group-hover:text-icons-2 relative z-10 mt-[3px] flex h-3 w-3 min-w-3 items-center duration-100 ease-in-out', + 'text-icons-4 group-hover:text-icons-2 relative z-10 mt-1 flex h-3 w-3 min-w-3 items-center duration-100 ease-in-out', { 'text-icons-2': active } - )}> + )} + > {active && ( <span className="absolute left-1/2 top-1/2 z-[-1] size-7 -translate-x-1/2 -translate-y-1/2" @@ -185,7 +183,8 @@ function Item({ icon, text, description, active, submenuItem, className }: ItemP weight="medium" className={cn('text-foreground-3 group-hover:text-foreground-1 z-10 text-left duration-100 ease-in-out', { 'text-foreground-1': active - })}> + })} + > {text} </Text> </div> @@ -194,7 +193,7 @@ function Item({ icon, text, description, active, submenuItem, className }: ItemP function Footer({ children }: { children: React.ReactNode }) { return ( - <div className="border-borders-5 sticky bottom-0 z-20 grid h-[72px] items-center border-t px-4">{children}</div> + <div className="sticky bottom-0 z-20 grid h-[72px] items-center border-t border-borders-5 px-4">{children}</div> ) } diff --git a/packages/canary/src/components/popover.tsx b/packages/canary/src/components/popover.tsx index a88d0b742..575b3298d 100644 --- a/packages/canary/src/components/popover.tsx +++ b/packages/canary/src/components/popover.tsx @@ -12,14 +12,14 @@ const PopoverAnchor = PopoverPrimitive.Anchor const PopoverContent = React.forwardRef< React.ElementRef<typeof PopoverPrimitive.Content>, React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> ->(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( +>(({ className = 'w-72', align = 'center', sideOffset = 4, ...props }, ref) => ( <PopoverPrimitive.Portal> <PopoverPrimitive.Content ref={ref} align={align} sideOffset={sideOffset} className={cn( - 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', + 'bg-background-2 text-foreground-1 shadow-1 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 rounded-md border p-4 outline-none', className )} {...props} diff --git a/packages/canary/src/components/scroll-area.tsx b/packages/canary/src/components/scroll-area.tsx index cf7ba78b7..7ac4ecba1 100644 --- a/packages/canary/src/components/scroll-area.tsx +++ b/packages/canary/src/components/scroll-area.tsx @@ -6,13 +6,15 @@ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area' const ScrollArea = React.forwardRef< React.ElementRef<typeof ScrollAreaPrimitive.Root>, React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> ->(({ className, children, ...props }, ref) => ( - <ScrollAreaPrimitive.Root ref={ref} className={cn('relative overflow-hidden', className)} {...props}> - <ScrollAreaPrimitive.Viewport className="size-full rounded-[inherit]">{children}</ScrollAreaPrimitive.Viewport> - <ScrollBar /> - <ScrollAreaPrimitive.Corner /> - </ScrollAreaPrimitive.Root> -)) +>(({ className, children, ...props }, ref) => { + return ( + <ScrollAreaPrimitive.Root ref={ref} className={cn('relative overflow-hidden', className)} {...props}> + <ScrollAreaPrimitive.Viewport className="size-full rounded-[inherit]">{children}</ScrollAreaPrimitive.Viewport> + <ScrollBar /> + <ScrollAreaPrimitive.Corner /> + </ScrollAreaPrimitive.Root> + ) +}) ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName const ScrollBar = React.forwardRef< @@ -23,14 +25,14 @@ const ScrollBar = React.forwardRef< ref={ref} orientation={orientation} className={cn( - 'flex touch-none select-none transition-colors', - orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-[1px]', - orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-[1px]', + 'group absolute z-10 flex touch-none select-none transition-colors', + orientation === 'vertical' && 'right-0 top-0 h-full w-3.5 border-l border-l-transparent p-1', + orientation === 'horizontal' && 'bottom-0 left-0 h-2.5 flex-col border-t border-t-transparent p-[1px]', className )} {...props} > - <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" /> + <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-background-9" /> </ScrollAreaPrimitive.ScrollAreaScrollbar> )) ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName diff --git a/packages/canary/src/components/search-box.tsx b/packages/canary/src/components/search-box.tsx index 3f916c1db..1c393ef69 100644 --- a/packages/canary/src/components/search-box.tsx +++ b/packages/canary/src/components/search-box.tsx @@ -1,5 +1,4 @@ -import type { FormEventHandler, InputHTMLAttributes } from 'react' -import { useEffect } from 'react' +import { forwardRef, useEffect, type ChangeEventHandler, type ForwardedRef, type InputHTMLAttributes } from 'react' import { cn } from '@/lib/utils' import { noop } from 'lodash-es' @@ -28,97 +27,116 @@ interface SearchBoxProps { placeholder: string width?: 'full' | 'fixed' hasShortcut?: boolean + hasSearchIcon?: boolean shortcutLetter?: string shortcutModifier?: string textSize?: TextSize onSearch?: () => void - handleChange?: FormEventHandler<HTMLInputElement> + onFocus?: () => void + handleChange?: ChangeEventHandler<HTMLInputElement> showOnFocus?: boolean // New prop to control dialog appearance on focus defaultValue?: InputHTMLAttributes<HTMLInputElement>['defaultValue'] value?: InputHTMLAttributes<HTMLInputElement>['value'] className?: string + inputClassName?: string } -const Root = ({ - textSize = TextSize['text-sm'], - placeholder, - width = 'fixed', - hasShortcut = false, - shortcutLetter, - shortcutModifier, - onSearch, - handleChange = noop, - defaultValue, - value, - showOnFocus = false, - className -}: SearchBoxProps) => { - const textSizeClass = TextSize[textSize] +const Root = forwardRef<HTMLInputElement, SearchBoxProps>( + ( + { + textSize = TextSize['text-sm'], + placeholder, + width = 'fixed', + hasShortcut = false, + shortcutLetter, + shortcutModifier, + onSearch, + onFocus, + handleChange = noop, + defaultValue, + hasSearchIcon = true, + value, + showOnFocus = false, + className, + inputClassName = 'h-8' + }, + ref: ForwardedRef<HTMLInputElement> + ) => { + const textSizeClass = TextSize[textSize] - const handleSearch = () => { - if (onSearch) { - onSearch() + const handleSearch = () => { + if (onSearch) { + onSearch() + } } - } - const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - if (e.key === 'Enter') { - e.preventDefault() - handleSearch() + const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { + if (e.key === 'Enter') { + e.preventDefault() + handleSearch() + } } - } - const handleFocus = () => { - if (showOnFocus) { - handleSearch() + const handleFocus = () => { + if (onFocus) { + onFocus() + } + if (showOnFocus) { + handleSearch() + } } - } - useEffect(() => { - const handleShortcutKey = (e: KeyboardEvent) => { - if (hasShortcut && shortcutLetter && shortcutModifier) { - const isModifierPressed = - (shortcutModifier === 'cmd' && e.metaKey) || // For Mac Command key - (shortcutModifier === 'ctrl' && e.ctrlKey) || // For Ctrl key on Windows/Linux - (shortcutModifier === 'alt' && e.altKey) || // For Alt key - (shortcutModifier === 'shift' && e.shiftKey) // For Shift key + useEffect(() => { + const handleShortcutKey = (e: KeyboardEvent) => { + if (hasShortcut && shortcutLetter && shortcutModifier) { + const isModifierPressed = + (shortcutModifier === 'cmd' && e.metaKey) || + (shortcutModifier === 'ctrl' && e.ctrlKey) || + (shortcutModifier === 'alt' && e.altKey) || + (shortcutModifier === 'shift' && e.shiftKey) - if (isModifierPressed && e.key.toLowerCase() === shortcutLetter.toLowerCase()) { - e.preventDefault() // Prevent the default behavior (optional) - handleSearch() + if (isModifierPressed && e.key.toLowerCase() === shortcutLetter.toLowerCase()) { + e.preventDefault() + handleSearch() + } } } - } - window.addEventListener('keydown', handleShortcutKey) + window.addEventListener('keydown', handleShortcutKey) - return () => { - window.removeEventListener('keydown', handleShortcutKey) - } - }, [hasShortcut, shortcutLetter, shortcutModifier, handleSearch]) + return () => { + window.removeEventListener('keydown', handleShortcutKey) + } + }, [hasShortcut, shortcutLetter, shortcutModifier, handleSearch]) - return ( - <div className={cn('relative', width === 'full' ? 'w-full' : 'w-96', className)}> - <Icon name="search" size={12} className="text-icons-1 absolute left-2.5 top-1/2 -translate-y-1/2" /> - {hasShortcut && !!shortcutLetter && ( - <div className="bg-background-3 text-foreground-2 absolute right-1.5 top-1/2 flex h-5 -translate-y-1/2 cursor-pointer items-center gap-0.5 rounded-sm border px-1 duration-100 ease-in-out"> - <Icon name="apple-shortcut" size={12} /> - <Text size={0} className="text-inherit"> - {shortcutLetter} - </Text> - </div> - )} - <Input - placeholder={placeholder} - defaultValue={defaultValue} - className={cn('h-8 pl-7', { 'pr-10': hasShortcut }, textSizeClass)} - onKeyDown={handleKeyDown} - onFocus={handleFocus} - onInput={handleChange} - value={value} - /> - </div> - ) -} + return ( + <div className={cn('relative', width === 'full' ? 'w-full' : 'w-96', className)}> + {hasSearchIcon && ( + <Icon name="search" size={12} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-icons-1" /> + )} + {hasShortcut && !!shortcutLetter && ( + <div className="absolute right-1.5 top-1/2 flex h-5 -translate-y-1/2 cursor-pointer items-center gap-0.5 rounded-sm border bg-background-3 px-1 text-foreground-2 duration-100 ease-in-out"> + <Icon name="apple-shortcut" size={12} /> + <Text size={0} className="text-inherit"> + {shortcutLetter} + </Text> + </div> + )} + <Input + ref={ref} + placeholder={placeholder} + defaultValue={defaultValue} + className={cn(inputClassName, { 'pr-10': hasShortcut, 'pl-7': hasSearchIcon }, textSizeClass)} + onKeyDown={handleKeyDown} + onFocus={handleFocus} + onInput={handleChange} + value={value} + /> + </div> + ) + } +) + +Root.displayName = 'Root' export { Root } diff --git a/packages/canary/src/components/sheet.tsx b/packages/canary/src/components/sheet.tsx index 127600719..1b9beed4d 100644 --- a/packages/canary/src/components/sheet.tsx +++ b/packages/canary/src/components/sheet.tsx @@ -16,7 +16,7 @@ const SheetPortal = SheetPrimitive.Portal interface SheetOverlayProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay> { modal?: boolean - handleClose?: () => void + handleClose?: ((event: React.MouseEvent<HTMLDivElement>) => void) | (() => void) } const SheetOverlay = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Overlay>, SheetOverlayProps>( @@ -38,7 +38,7 @@ const SheetOverlay = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Ove <div aria-hidden="true" className={cn('bg-background-7/50 fixed left-0 top-0 h-full w-full', className)} - onClick={handleClose} + onClick={e => handleClose?.(e)} /> ) } @@ -88,7 +88,7 @@ const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Con ref ) => ( <SheetPortal> - <SheetOverlay modal={modal} className={overlayClassName} handleClose={handleClose ?? props.onClick} /> + <SheetOverlay modal={modal} className={overlayClassName} handleClose={handleClose || props.onClick} /> <SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}> {children} {!hideCloseButton && ( @@ -96,7 +96,12 @@ const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Con asChild className="absolute right-[0.1875rem] top-2 flex items-center justify-center transition-colors disabled:pointer-events-none" > - <Button className="text-icons-4 hover:text-icons-2" variant="custom" size="icon" onClick={handleClose}> + <Button + className="text-icons-4 hover:text-icons-2" + variant="custom" + size="icon" + onClick={() => handleClose?.()} + > <Icon name="close" size={16} /> <span className="sr-only">Close</span> </Button> diff --git a/packages/canary/src/icons/artifacts-gradient.svg b/packages/canary/src/icons/artifacts-gradient.svg new file mode 100644 index 000000000..b52c75874 --- /dev/null +++ b/packages/canary/src/icons/artifacts-gradient.svg @@ -0,0 +1,9 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M9.20218 0.667698C9.0734 0.610767 8.9266 0.610767 8.79782 0.667698L1.29782 3.98349C1.11678 4.06353 1 4.24284 1 4.44079V4.4997C1 4.49972 1 4.49974 1 4.49975V13.5592C1 13.7571 1.11678 13.9364 1.29782 14.0165L8.78783 17.3279C8.84488 17.3547 8.90782 17.371 8.97417 17.3743C8.98278 17.3748 8.99139 17.375 9 17.375C9.00955 17.375 9.01911 17.3747 9.02865 17.3742C9.09397 17.3705 9.15593 17.3543 9.21218 17.3279L16.7022 14.0165C16.8832 13.9364 17 13.7571 17 13.5592V4.51451C17.0003 4.50467 17.0003 4.49481 17 4.48493V4.44079C17 4.24284 16.8832 4.06353 16.7022 3.98349L9.20218 0.667698ZM15.3894 4.49646L9 1.67168L2.61074 4.49641L9.00011 7.69109L15.3894 4.49646ZM2 5.30908V13.2335L8.5 16.1073V8.55907L2 5.30908ZM9.5 16.1073L16 13.2335V5.30918L9.5 8.55918V16.1073Z" fill="url(#paint0_linear_17614_128159)"/> +<defs> +<linearGradient id="paint0_linear_17614_128159" x1="9.00011" y1="0.625" x2="9.00011" y2="17.375" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/artifacts-icon.svg b/packages/canary/src/icons/artifacts-icon.svg new file mode 100644 index 000000000..aa8b9f27d --- /dev/null +++ b/packages/canary/src/icons/artifacts-icon.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M6 1L11 3.14286V9.57143L6 11.7143L1 9.57143V3.14286L6 1Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M2.75 4.25L6 5.75L9.25 4.25" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M6 6V9.75" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/artifacts.svg b/packages/canary/src/icons/artifacts.svg new file mode 100644 index 000000000..64f9971f0 --- /dev/null +++ b/packages/canary/src/icons/artifacts.svg @@ -0,0 +1,3 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M9.20218 0.667698C9.0734 0.610767 8.9266 0.610767 8.79782 0.667698L1.29782 3.98349C1.11678 4.06353 1 4.24284 1 4.44079V4.4997C1 4.49972 1 4.49974 1 4.49975V13.5592C1 13.7571 1.11678 13.9364 1.29782 14.0165L8.78783 17.3279C8.84488 17.3547 8.90782 17.371 8.97417 17.3743C8.98278 17.3748 8.99139 17.375 9 17.375C9.00955 17.375 9.01911 17.3747 9.02865 17.3742C9.09397 17.3705 9.15593 17.3543 9.21218 17.3279L16.7022 14.0165C16.8832 13.9364 17 13.7571 17 13.5592V4.51451C17.0003 4.50467 17.0003 4.49481 17 4.48493V4.44079C17 4.24284 16.8832 4.06353 16.7022 3.98349L9.20218 0.667698ZM15.3894 4.49646L9 1.67168L2.61074 4.49641L9.00011 7.69109L15.3894 4.49646ZM2 5.30908V13.2335L8.5 16.1073V8.55907L2 5.30908ZM9.5 16.1073L16 13.2335V5.30918L9.5 8.55918V16.1073Z" fill="currentColor"/> +</svg> diff --git a/packages/canary/src/icons/bookmark.svg b/packages/canary/src/icons/bookmark.svg deleted file mode 100644 index 1a591adce..000000000 --- a/packages/canary/src/icons/bookmark.svg +++ /dev/null @@ -1,19 +0,0 @@ -<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_9309_36459)"> -<path fill-rule="evenodd" clip-rule="evenodd" d="M1.97839 1.97839C2.2847 1.67208 2.70015 1.5 3.13333 1.5H3.69995V8.46667C3.69995 8.65887 3.81012 8.83406 3.98336 8.91732C4.15659 9.00058 4.36221 8.97717 4.5123 8.8571L6.86662 6.97365L9.22094 8.8571C9.37102 8.97717 9.57665 9.00058 9.74988 8.91732C9.92311 8.83406 10.0333 8.65887 10.0333 8.46667V1.5H14.8667C15.2999 1.5 15.7153 1.67208 16.0216 1.97839C16.3279 2.2847 16.5 2.70015 16.5 3.13333V15.4C16.5 15.6761 16.7239 15.9 17 15.9C17.2761 15.9 17.5 15.6761 17.5 15.4V3.13333C17.5 2.43493 17.2226 1.76513 16.7287 1.27129C16.2349 0.77744 15.5651 0.5 14.8667 0.5H9.53329H4.19995H3.13333C2.43493 0.5 1.76513 0.77744 1.27129 1.27129C0.77744 1.76513 0.5 2.43493 0.5 3.13333V15.4C0.5 15.6761 0.723858 15.9 1 15.9C1.27614 15.9 1.5 15.6761 1.5 15.4V3.13333C1.5 2.70015 1.67208 2.2847 1.97839 1.97839ZM4.69995 1.5V7.42635L6.55427 5.9429C6.73688 5.79681 6.99636 5.79681 7.17897 5.9429L9.03329 7.42635V1.5H4.69995Z" fill="url(#paint0_linear_9309_36459)"/> -<path fill-rule="evenodd" clip-rule="evenodd" d="M2.6 14.3008C1.99249 14.3008 1.5 14.7933 1.5 15.4008C1.5 16.0083 1.99249 16.5008 2.6 16.5008H15.4C16.0075 16.5008 16.5 16.0083 16.5 15.4008C16.5 14.7933 16.0075 14.3008 15.4 14.3008H2.6ZM0.5 15.4008C0.5 14.241 1.4402 13.3008 2.6 13.3008H15.4C16.5598 13.3008 17.5 14.241 17.5 15.4008C17.5 16.5606 16.5598 17.5008 15.4 17.5008H2.6C1.4402 17.5008 0.5 16.5606 0.5 15.4008Z" fill="url(#paint1_linear_9309_36459)"/> -</g> -<defs> -<linearGradient id="paint0_linear_9309_36459" x1="9" y1="0.5" x2="9" y2="15.9" gradientUnits="userSpaceOnUse"> -<stop stop-color="currentColor"/> -<stop offset="1" stop-color="currentColor"/> -</linearGradient> -<linearGradient id="paint1_linear_9309_36459" x1="9" y1="0.500733" x2="9" y2="15.5007" gradientUnits="userSpaceOnUse"> -<stop stop-color="currentColor"/> -<stop offset="1" stop-color="currentColor"/> -</linearGradient> -<clipPath id="clip0_9309_36459"> -<rect width="100%" height="100%" fill="currentColor"/> -</clipPath> -</defs> -</svg> diff --git a/packages/canary/src/icons/chaos-engineering-gradient.svg b/packages/canary/src/icons/chaos-engineering-gradient.svg new file mode 100644 index 000000000..2f351523d --- /dev/null +++ b/packages/canary/src/icons/chaos-engineering-gradient.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="none"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M8.99909 0.417969L9.35264 0.771522L10.8526 2.27152C11.0479 2.46678 11.0479 2.78337 10.8526 2.97863C10.6574 3.17389 10.3408 3.17389 10.1455 2.97863L9.49909 2.33218V6.80583C9.94823 6.90774 10.3463 7.14402 10.6489 7.47016L14.5174 5.23671L13.5706 4.98304C13.3039 4.91157 13.1456 4.6374 13.2171 4.37067C13.2886 4.10393 13.5627 3.94564 13.8295 4.01711L15.8785 4.56615L16.3615 4.69556L16.2321 5.17852L15.683 7.22756C15.6115 7.49429 15.3374 7.65259 15.0706 7.58111C14.8039 7.50964 14.6456 7.23548 14.7171 6.96874L14.9367 6.14933L11.1494 8.33588C11.2142 8.54582 11.2491 8.76887 11.2491 9.00008C11.2491 9.23128 11.2142 9.45434 11.1494 9.66428L14.9367 11.8508L14.7171 11.0314C14.6456 10.7647 14.8039 10.4905 15.0706 10.419C15.3374 10.3476 15.6115 10.5059 15.683 10.7726L16.2321 12.8216L16.3615 13.3046L15.8785 13.434L13.8295 13.983C13.5627 14.0545 13.2886 13.8962 13.2171 13.6295C13.1456 13.3628 13.3039 13.0886 13.5706 13.0171L14.5174 12.7634L10.6489 10.53C10.3463 10.8561 9.94823 11.0924 9.49909 11.1943V15.668L10.1455 15.0215C10.3408 14.8263 10.6574 14.8263 10.8526 15.0215C11.0479 15.2168 11.0479 15.5334 10.8526 15.7286L9.35264 17.2286L8.99909 17.5822L8.64554 17.2286L7.14554 15.7286C6.95028 15.5334 6.95028 15.2168 7.14554 15.0215C7.3408 14.8263 7.65738 14.8263 7.85264 15.0215L8.49909 15.668V11.1943C8.04993 11.0924 7.65181 10.8561 7.34922 10.5299L3.48072 12.7634L4.42754 13.0171C4.69427 13.0886 4.85256 13.3628 4.78109 13.6295C4.70962 13.8962 4.43545 14.0545 4.16872 13.983L2.11968 13.434L1.63672 13.3046L1.76613 12.8216L2.31517 10.7726C2.38664 10.5059 2.66081 10.3476 2.92754 10.419C3.19427 10.4905 3.35256 10.7647 3.28109 11.0314L3.06156 11.8507L6.84871 9.6642C6.78396 9.45429 6.74909 9.23125 6.74909 9.00008C6.74909 8.7689 6.78396 8.54587 6.84871 8.33595L3.06156 6.14943L3.28109 6.96874C3.35256 7.23548 3.19427 7.50964 2.92754 7.58111C2.66081 7.65259 2.38664 7.49429 2.31517 7.22756L1.76613 5.17852L1.63672 4.69556L2.11968 4.56615L4.16872 4.01711C4.43545 3.94564 4.70962 4.10393 4.78109 4.37067C4.85256 4.6374 4.69427 4.91157 4.42754 4.98304L3.48073 5.23674L7.34922 7.47021C7.65181 7.14404 8.04993 6.90775 8.49909 6.80583V2.33218L7.85264 2.97863C7.65738 3.17389 7.3408 3.17389 7.14554 2.97863C6.95028 2.78337 6.95028 2.46678 7.14554 2.27152L8.64554 0.771522L8.99909 0.417969Z" fill="url(#paint0_linear_16731_78963)"/> + <defs> + <linearGradient id="paint0_linear_16731_78963" x1="8.99909" y1="0.417969" x2="8.99909" y2="17.5822" gradientUnits="userSpaceOnUse"> + <stop stop-color="currentColor"/> + <stop offset="1" stop-color="currentColor"/> + </linearGradient> + </defs> +</svg> diff --git a/packages/canary/src/icons/chaos-engineering-icon.svg b/packages/canary/src/icons/chaos-engineering-icon.svg index 6351b2e1c..417ce1f66 100644 --- a/packages/canary/src/icons/chaos-engineering-icon.svg +++ b/packages/canary/src/icons/chaos-engineering-icon.svg @@ -1,9 +1,6 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> - <path fill-rule="evenodd" clip-rule="evenodd" d="M8.99909 0.417969L9.35264 0.771522L10.8526 2.27152C11.0479 2.46678 11.0479 2.78337 10.8526 2.97863C10.6574 3.17389 10.3408 3.17389 10.1455 2.97863L9.49909 2.33218V6.80583C9.94823 6.90774 10.3463 7.14402 10.6489 7.47016L14.5174 5.23671L13.5706 4.98304C13.3039 4.91157 13.1456 4.6374 13.2171 4.37067C13.2886 4.10393 13.5627 3.94564 13.8295 4.01711L15.8785 4.56615L16.3615 4.69556L16.2321 5.17852L15.683 7.22756C15.6115 7.49429 15.3374 7.65259 15.0706 7.58111C14.8039 7.50964 14.6456 7.23548 14.7171 6.96874L14.9367 6.14933L11.1494 8.33588C11.2142 8.54582 11.2491 8.76887 11.2491 9.00008C11.2491 9.23128 11.2142 9.45434 11.1494 9.66428L14.9367 11.8508L14.7171 11.0314C14.6456 10.7647 14.8039 10.4905 15.0706 10.419C15.3374 10.3476 15.6115 10.5059 15.683 10.7726L16.2321 12.8216L16.3615 13.3046L15.8785 13.434L13.8295 13.983C13.5627 14.0545 13.2886 13.8962 13.2171 13.6295C13.1456 13.3628 13.3039 13.0886 13.5706 13.0171L14.5174 12.7634L10.6489 10.53C10.3463 10.8561 9.94823 11.0924 9.49909 11.1943V15.668L10.1455 15.0215C10.3408 14.8263 10.6574 14.8263 10.8526 15.0215C11.0479 15.2168 11.0479 15.5334 10.8526 15.7286L9.35264 17.2286L8.99909 17.5822L8.64554 17.2286L7.14554 15.7286C6.95028 15.5334 6.95028 15.2168 7.14554 15.0215C7.3408 14.8263 7.65738 14.8263 7.85264 15.0215L8.49909 15.668V11.1943C8.04993 11.0924 7.65181 10.8561 7.34922 10.5299L3.48072 12.7634L4.42754 13.0171C4.69427 13.0886 4.85256 13.3628 4.78109 13.6295C4.70962 13.8962 4.43545 14.0545 4.16872 13.983L2.11968 13.434L1.63672 13.3046L1.76613 12.8216L2.31517 10.7726C2.38664 10.5059 2.66081 10.3476 2.92754 10.419C3.19427 10.4905 3.35256 10.7647 3.28109 11.0314L3.06156 11.8507L6.84871 9.6642C6.78396 9.45429 6.74909 9.23125 6.74909 9.00008C6.74909 8.7689 6.78396 8.54587 6.84871 8.33595L3.06156 6.14943L3.28109 6.96874C3.35256 7.23548 3.19427 7.50964 2.92754 7.58111C2.66081 7.65259 2.38664 7.49429 2.31517 7.22756L1.76613 5.17852L1.63672 4.69556L2.11968 4.56615L4.16872 4.01711C4.43545 3.94564 4.70962 4.10393 4.78109 4.37067C4.85256 4.6374 4.69427 4.91157 4.42754 4.98304L3.48073 5.23674L7.34922 7.47021C7.65181 7.14404 8.04993 6.90775 8.49909 6.80583V2.33218L7.85264 2.97863C7.65738 3.17389 7.3408 3.17389 7.14554 2.97863C6.95028 2.78337 6.95028 2.46678 7.14554 2.27152L8.64554 0.771522L8.99909 0.417969Z" fill="url(#paint0_linear_16731_78963)"/> - <defs> - <linearGradient id="paint0_linear_16731_78963" x1="8.99909" y1="0.417969" x2="8.99909" y2="17.5822" gradientUnits="userSpaceOnUse"> - <stop stop-color="currentColor"/> - <stop offset="1" stop-color="currentColor"/> - </linearGradient> - </defs> +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> + <g> + <path fill-rule="evenodd" clip-rule="evenodd" d="M5.99909 0.542969L6.35264 0.896522L7.35264 1.89652C7.54791 2.09178 7.54791 2.40837 7.35264 2.60363C7.15738 2.79889 6.8408 2.79889 6.64554 2.60363L6.49909 2.45718V5.08543C6.67464 5.14748 6.83519 5.24127 6.97384 5.35992L9.24614 4.04801L9.00366 3.98304C8.73692 3.91157 8.57863 3.6374 8.6501 3.37067C8.72157 3.10393 8.99574 2.94564 9.26248 3.01711L10.6285 3.38314L11.1115 3.51255L10.9821 3.99551L10.616 5.36154C10.5446 5.62827 10.2704 5.78656 10.0037 5.71509C9.73692 5.64362 9.57863 5.36945 9.6501 5.10272L9.69234 4.9451L7.47408 6.22581C7.4905 6.31473 7.49909 6.4064 7.49909 6.50008C7.49909 6.59375 7.4905 6.68542 7.47408 6.77434L9.69234 8.05505L9.6501 7.89743C9.57863 7.6307 9.73692 7.35653 10.0037 7.28506C10.2704 7.21359 10.5446 7.37188 10.616 7.63862L10.9821 9.00464L11.1115 9.4876L10.6285 9.61701L9.26248 9.98304C8.99574 10.0545 8.72157 9.89622 8.6501 9.62949C8.57863 9.36275 8.73692 9.08858 9.00366 9.01711L9.24614 8.95214L6.97384 7.64023C6.83519 7.75888 6.67464 7.85267 6.49909 7.91472V10.543L6.64554 10.3965C6.8408 10.2013 7.15738 10.2013 7.35264 10.3965C7.54791 10.5918 7.54791 10.9084 7.35264 11.1036L6.35264 12.1036L5.99909 12.4572L5.64554 12.1036L4.64554 11.1036C4.45028 10.9084 4.45028 10.5918 4.64554 10.3965C4.8408 10.2013 5.15738 10.2013 5.35264 10.3965L5.49909 10.543V7.91472C5.32353 7.85267 5.16296 7.75886 5.0243 7.64019L2.75197 8.95212L2.99453 9.01711C3.26126 9.08858 3.41955 9.36275 3.34808 9.62949C3.27661 9.89622 3.00244 10.0545 2.73571 9.98304L1.36968 9.61701L0.886719 9.4876L1.01613 9.00464L1.38215 7.63862C1.45362 7.37188 1.72779 7.21359 1.99453 7.28506C2.26126 7.35653 2.41955 7.6307 2.34808 7.89743L2.30586 8.05498L4.5241 6.77428C4.50767 6.68538 4.49909 6.59373 4.49909 6.50008C4.49909 6.40642 4.50767 6.31477 4.5241 6.22587L2.30586 4.94517L2.34808 5.10272C2.41955 5.36945 2.26126 5.64362 1.99453 5.71509C1.72779 5.78656 1.45362 5.62827 1.38215 5.36154L1.01613 3.99551L0.886719 3.51255L1.36968 3.38314L2.73571 3.01711C3.00244 2.94564 3.27661 3.10393 3.34808 3.37067C3.41955 3.6374 3.26126 3.91157 2.99453 3.98304L2.75198 4.04803L5.0243 5.35996C5.16296 5.24129 5.32353 5.14748 5.49909 5.08543V2.45718L5.35264 2.60363C5.15738 2.79889 4.8408 2.79889 4.64554 2.60363C4.45028 2.40837 4.45028 2.09178 4.64554 1.89652L5.64554 0.896522L5.99909 0.542969Z" fill="currentColor"/> + </g> </svg> + diff --git a/packages/canary/src/icons/cloud-mining.svg b/packages/canary/src/icons/cloud-costs-gradient.svg similarity index 96% rename from packages/canary/src/icons/cloud-mining.svg rename to packages/canary/src/icons/cloud-costs-gradient.svg index a2206a08f..52d30b82f 100644 --- a/packages/canary/src/icons/cloud-mining.svg +++ b/packages/canary/src/icons/cloud-costs-gradient.svg @@ -1,5 +1,5 @@ <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_9309_36518)"> +<g> <path fill-rule="evenodd" clip-rule="evenodd" d="M9 0.0625C7.84727 0.0625 6.72308 0.421059 5.78323 1.08849C4.94553 1.68337 4.29125 2.49737 3.88995 3.43793C2.87943 3.45032 1.91295 3.85712 1.19746 4.5726C0.470758 5.29931 0.0625 6.28493 0.0625 7.31264C0.0625 8.34036 0.470758 9.32598 1.19746 10.0527C1.92416 10.7794 2.90979 11.1876 3.9375 11.1876H3.99988V13.293L2.91609 14.3768C2.63702 14.2167 2.31358 14.1251 1.96875 14.1251C0.915957 14.1251 0.0625 14.9786 0.0625 16.0314C0.0625 17.0842 0.915957 17.9376 1.96875 17.9376C3.02154 17.9376 3.875 17.0842 3.875 16.0314C3.875 15.6865 3.78341 15.363 3.62323 15.0839L4.85344 13.8537C4.94721 13.7599 4.99988 13.6327 4.99988 13.5001V11.1876H8.5V14.1914C7.68974 14.411 7.09375 15.1516 7.09375 16.0314C7.09375 17.0842 7.94721 17.9376 9 17.9376C10.0528 17.9376 10.9062 17.0842 10.9062 16.0314C10.9062 15.1516 10.3103 14.411 9.5 14.1914V11.1876H13V13.5001C13 13.6327 13.0527 13.7599 13.1464 13.8537L14.3767 15.084C14.2166 15.363 14.125 15.6865 14.125 16.0314C14.125 17.0842 14.9785 17.9376 16.0312 17.9376C17.084 17.9376 17.9375 17.0842 17.9375 16.0314C17.9375 14.9786 17.084 14.1251 16.0312 14.1251C15.6864 14.1251 15.3629 14.2167 15.0838 14.3769L14 13.293V11.1876H14.0625C15.0902 11.1876 16.0758 10.7794 16.8025 10.0527C17.5292 9.32598 17.9375 8.34036 17.9375 7.31264C17.9375 6.28493 17.5292 5.29931 16.8025 4.5726C16.0871 3.85711 15.1206 3.45032 14.1101 3.43793C13.7088 2.49737 13.0545 1.68337 12.2168 1.08849C11.2769 0.421059 10.1527 0.0625 9 0.0625ZM13.5044 10.1876H14.0625C14.825 10.1876 15.5563 9.88474 16.0954 9.34557C16.6346 8.80641 16.9375 8.07514 16.9375 7.31264C16.9375 6.55014 16.6346 5.81888 16.0954 5.27971C15.5563 4.74054 14.825 4.43764 14.0625 4.43764C13.9863 4.43764 13.9077 4.4429 13.8144 4.45058C13.5874 4.46928 13.3764 4.33213 13.3013 4.11703C12.9898 3.22458 12.4085 2.45111 11.6378 1.90382C10.8671 1.35652 9.94524 1.0625 9 1.0625C8.05476 1.0625 7.13292 1.35652 6.36223 1.90382C5.59154 2.45111 5.01018 3.22458 4.6987 4.11703C4.62363 4.33213 4.41264 4.46928 4.18559 4.45058C4.09235 4.4429 4.01375 4.43764 3.9375 4.43764C3.175 4.43764 2.44374 4.74054 1.90457 5.27971C1.3654 5.81888 1.0625 6.55014 1.0625 7.31264C1.0625 8.07514 1.3654 8.80641 1.90457 9.34557C2.44374 9.88474 3.175 10.1876 3.9375 10.1876H4.49547C4.49694 10.1876 4.49841 10.1876 4.49988 10.1876C4.50136 10.1876 4.50283 10.1876 4.5043 10.1876H8.99559C8.99706 10.1876 8.99853 10.1876 9 10.1876C9.00147 10.1876 9.00294 10.1876 9.00441 10.1876H13.4956C13.4971 10.1876 13.4985 10.1876 13.5 10.1876C13.5015 10.1876 13.5029 10.1876 13.5044 10.1876ZM8.09375 16.0314C8.09375 15.5309 8.49949 15.1251 9 15.1251C9.50051 15.1251 9.90625 15.5309 9.90625 16.0314C9.90625 16.5319 9.50051 16.9376 9 16.9376C8.49949 16.9376 8.09375 16.5319 8.09375 16.0314ZM1.96875 15.1251C1.46824 15.1251 1.0625 15.5309 1.0625 16.0314C1.0625 16.5319 1.46824 16.9376 1.96875 16.9376C2.46926 16.9376 2.875 16.5319 2.875 16.0314C2.875 15.5309 2.46926 15.1251 1.96875 15.1251ZM15.4122 15.3695C15.5742 15.2179 15.7919 15.1251 16.0312 15.1251C16.5318 15.1251 16.9375 15.5309 16.9375 16.0314C16.9375 16.5319 16.5318 16.9376 16.0312 16.9376C15.5307 16.9376 15.125 16.5319 15.125 16.0314C15.125 15.792 15.2178 15.5743 15.3694 15.4123C15.3769 15.4057 15.3842 15.3987 15.3914 15.3916C15.3986 15.3844 15.4055 15.377 15.4122 15.3695Z" fill="url(#paint0_linear_9309_36518)"/> </g> <defs> @@ -7,8 +7,5 @@ <stop stop-color="currentColor"/> <stop offset="1" stop-color="currentColor"/> </linearGradient> -<clipPath id="clip0_9309_36518"> -<rect width="100%" height="100%" fill="currentColor"/> -</clipPath> </defs> </svg> diff --git a/packages/canary/src/icons/cloud-costs-icon.svg b/packages/canary/src/icons/cloud-costs-icon.svg new file mode 100644 index 000000000..bab870255 --- /dev/null +++ b/packages/canary/src/icons/cloud-costs-icon.svg @@ -0,0 +1,11 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M1.41666 12.0003C1.92292 12.0003 2.33332 11.5899 2.33332 11.0837C2.33332 10.5774 1.92292 10.167 1.41666 10.167C0.910402 10.167 0.5 10.5774 0.5 11.0837C0.5 11.5899 0.910402 12.0003 1.41666 12.0003Z" fill="currentColor" stroke="currentColor" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M6.00064 12.0003C6.5069 12.0003 6.9173 11.5899 6.9173 11.0837C6.9173 10.5774 6.5069 10.167 6.00064 10.167C5.49439 10.167 5.08398 10.5774 5.08398 11.0837C5.08398 11.5899 5.49439 12.0003 6.00064 12.0003Z" fill="currentColor" stroke="currentColor" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10.5827 12.0003C11.0889 12.0003 11.4993 11.5899 11.4993 11.0837C11.4993 10.5774 11.0889 10.167 10.5827 10.167C10.0764 10.167 9.66602 10.5774 9.66602 11.0837C9.66602 11.5899 10.0764 12.0003 10.5827 12.0003Z" fill="currentColor" stroke="currentColor" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M6 10.1663V7.59961" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M9.93605 10.4354L8.93359 9.43293V7.59961" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M2.06445 10.4347L3.06618 9.43293V7.59961" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M9.29993 3.20007C9.23613 3.20007 9.17379 3.20447 9.11146 3.20961C8.88614 2.56402 8.46559 2.0045 7.90808 1.6086C7.35058 1.21269 6.68373 1 5.99995 1C5.31618 1 4.64933 1.21269 4.09182 1.6086C3.53432 2.0045 3.11377 2.56402 2.88845 3.20961C2.82611 3.20447 2.76378 3.20007 2.69998 3.20007C2.11651 3.20007 1.55694 3.43186 1.14436 3.84443C0.731783 4.25701 0.5 4.81658 0.5 5.40006C0.5 5.98353 0.731783 6.5431 1.14436 6.95568C1.55694 7.36825 2.11651 7.60004 2.69998 7.60004H9.29993C9.8834 7.60004 10.443 7.36825 10.8555 6.95568C11.2681 6.5431 11.4999 5.98353 11.4999 5.40006C11.4999 4.81658 11.2681 4.25701 10.8555 3.84443C10.443 3.43186 9.8834 3.20007 9.29993 3.20007Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/dashboards-gradient.svg b/packages/canary/src/icons/dashboards-gradient.svg new file mode 100644 index 000000000..6c65e9661 --- /dev/null +++ b/packages/canary/src/icons/dashboards-gradient.svg @@ -0,0 +1,11 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10.28 0.5C10.0039 0.5 9.78 0.723858 9.78 1V6C9.78 6.27614 10.0039 6.5 10.28 6.5H16.9996C17.2757 6.5 17.4996 6.27614 17.4996 6V1C17.4996 0.723858 17.2757 0.5 16.9996 0.5H10.28ZM10.78 5.5V1.5H16.4996V5.5H10.78ZM1 11.5C0.723858 11.5 0.5 11.7239 0.5 12V16.9991C0.5 17.2753 0.723858 17.4991 1 17.4991H7.72C7.99614 17.4991 8.22 17.2753 8.22 16.9991V12C8.22 11.7239 7.99614 11.5 7.72 11.5H1ZM1.5 16.4991V12.5H7.22V16.4991H1.5ZM0.5 1C0.5 0.723858 0.723858 0.5 1 0.5H7.72C7.99614 0.5 8.22 0.723858 8.22 1V9.5C8.22 9.77614 7.99614 10 7.72 10H1C0.723858 10 0.5 9.77614 0.5 9.5V1ZM1.5 1.5V9H7.22V1.5H1.5ZM10.28 8C10.0039 8 9.78 8.22386 9.78 8.5V17C9.78 17.2761 10.0039 17.5 10.28 17.5H16.9996C17.2757 17.5 17.4996 17.2761 17.4996 17V8.5C17.4996 8.22386 17.2757 8 16.9996 8H10.28ZM10.78 16.5V9H16.4996V16.5H10.78Z" fill="url(#paint0_linear_17614_128262)"/> +</g> +<defs> +<linearGradient id="paint0_linear_17614_128262" x1="8.99978" y1="0.5" x2="8.99978" y2="17.5" gradientUnits="userSpaceOnUse"> +<stop stop-color="#F0F0F0"/> +<stop offset="1" stop-color="#9C9C9C"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/dashboards-icon.svg b/packages/canary/src/icons/dashboards-icon.svg new file mode 100644 index 000000000..1e9b4ba44 --- /dev/null +++ b/packages/canary/src/icons/dashboards-icon.svg @@ -0,0 +1,8 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M4.97171 1.35742H0.857422V6.84314H4.97171V1.35742Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M4.97171 8.90039H0.857422V11.6432H4.97171V8.90039Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M11.1436 1.35742H7.0293V4.78599H11.1436V1.35742Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M11.1436 6.84277H7.0293V11.6428H11.1436V6.84277Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/database-gradient.svg b/packages/canary/src/icons/database-gradient.svg new file mode 100644 index 000000000..5af939708 --- /dev/null +++ b/packages/canary/src/icons/database-gradient.svg @@ -0,0 +1,10 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M2.8753 2.85852C2.56795 3.10074 2.5 3.2875 2.5 3.4C2.5 3.5125 2.56795 3.69926 2.8753 3.94148C3.17701 4.17926 3.64459 4.41526 4.26695 4.62271C5.50643 5.03588 7.25056 5.3 9.2 5.3C11.1494 5.3 12.8936 5.03588 14.1331 4.62271C14.7554 4.41526 15.223 4.17926 15.5247 3.94148C15.8321 3.69926 15.9 3.5125 15.9 3.4C15.9 3.2875 15.8321 3.10074 15.5247 2.85852C15.223 2.62074 14.7554 2.38474 14.1331 2.17729C12.8936 1.76412 11.1494 1.5 9.2 1.5C7.25056 1.5 5.50643 1.76412 4.26695 2.17729C3.64459 2.38474 3.17701 2.62074 2.8753 2.85852ZM3.95072 1.2286C5.31712 0.773134 7.17299 0.5 9.2 0.5C11.227 0.5 13.0829 0.773134 14.4493 1.2286C15.1299 1.45547 15.7167 1.73662 16.1437 2.07311C16.565 2.40515 16.9 2.84976 16.9 3.4C16.9 3.95024 16.565 4.39485 16.1437 4.72689C15.7167 5.06338 15.1299 5.34453 14.4493 5.5714C13.0829 6.02687 11.227 6.3 9.2 6.3C7.17299 6.3 5.31712 6.02687 3.95072 5.5714C3.27013 5.34453 2.68329 5.06338 2.25632 4.72689C1.835 4.39485 1.5 3.95024 1.5 3.4C1.5 2.84976 1.835 2.40515 2.25632 2.07311C2.68329 1.73662 3.27013 1.45547 3.95072 1.2286Z" fill="url(#paint0_linear_17614_128151)"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 3.4C2.5 3.12386 2.27614 2.89941 2 2.89941C1.72386 2.89941 1.5 3.12386 1.5 3.4V14.5994C1.5 15.1532 1.82768 15.6021 2.25098 15.9393C2.67731 16.2789 3.26339 16.5593 3.94298 16.7841C5.30727 17.2354 7.16321 17.4994 9.2 17.4994C11.2368 17.4994 13.0927 17.2354 14.457 16.7841C15.1366 16.5593 15.7227 16.2789 16.149 15.9393C16.5723 15.6021 16.9 15.1532 16.9 14.5994V3.4C16.9 3.12386 16.6761 2.89941 16.4 2.89941C16.1239 2.89941 15.9 3.12386 15.9 3.4V9C15.9 9.12621 15.8277 9.31734 15.526 9.55766C15.2273 9.79556 14.7634 10.0301 14.143 10.2353C12.9073 10.644 11.1632 10.9 9.2 10.9C7.23679 10.9 5.49273 10.644 4.25702 10.2353C3.63661 10.0301 3.17269 9.79556 2.87402 9.55766C2.57232 9.31734 2.5 9.12621 2.5 9V3.4ZM2.5 10.5199V14.5994C2.5 14.7256 2.57232 14.9167 2.87402 15.1571C3.17269 15.395 3.63661 15.6295 4.25702 15.8347C5.49273 16.2434 7.23679 16.4994 9.2 16.4994C11.1632 16.4994 12.9073 16.2434 14.143 15.8347C14.7634 15.6295 15.2273 15.395 15.526 15.1571C15.8277 14.9167 15.9 14.7256 15.9 14.5994V10.5199C15.5056 10.78 15.0126 11.0009 14.457 11.1847C13.0927 11.636 11.2368 11.9 9.2 11.9C7.16321 11.9 5.30727 11.636 3.94298 11.1847C3.38744 11.0009 2.89438 10.78 2.5 10.5199Z" fill="url(#paint0_linear_17614_128151)"/> +<defs> +<linearGradient id="paint0_linear_17614_128151" x1="9.2" y1="0.5" x2="9.2" y2="17.4994" gradientUnits="userSpaceOnUse"> +<stop stop-color="#F0F0F0"/> +<stop offset="1" stop-color="#9C9C9C"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/database-icon.svg b/packages/canary/src/icons/database-icon.svg new file mode 100644 index 000000000..76535d7f9 --- /dev/null +++ b/packages/canary/src/icons/database-icon.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M1.5 2.5V10.5C1.5 11.35 3.5 12 6 12C8.5 12 10.5 11.35 10.5 10.5V2.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M6 4C8.48528 4 10.5 3.32843 10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5C1.5 3.32843 3.51472 4 6 4Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10.5 6.5C10.5 7.35 8.5 8 6 8C3.5 8 1.5 7.35 1.5 6.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/dev-envs-gradient.svg b/packages/canary/src/icons/dev-envs-gradient.svg new file mode 100644 index 000000000..0a0d1507f --- /dev/null +++ b/packages/canary/src/icons/dev-envs-gradient.svg @@ -0,0 +1,9 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.75 1C0.473858 1 0.25 1.22386 0.25 1.5V13.5C0.25 13.7761 0.473858 14 0.75 14H8.5V16H4.5C4.22386 16 4 16.2239 4 16.5C4 16.7761 4.22386 17 4.5 17H9H13.5C13.7761 17 14 16.7761 14 16.5C14 16.2239 13.7761 16 13.5 16H9.5V14H17.25C17.5261 14 17.75 13.7761 17.75 13.5V1.5C17.75 1.22386 17.5261 1 17.25 1H0.75ZM9 13H16.75V2H1.25V13H9Z" fill="url(#paint0_linear_17614_128194)"/> +<defs> +<linearGradient id="paint0_linear_17614_128194" x1="9" y1="1" x2="9" y2="17" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/dev-envs-icon.svg b/packages/canary/src/icons/dev-envs-icon.svg new file mode 100644 index 000000000..2405b22cb --- /dev/null +++ b/packages/canary/src/icons/dev-envs-icon.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M3.5 12H8.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M6 9V12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M11.5 2H0.5V9H11.5V2Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/search-content.svg b/packages/canary/src/icons/dev-insights-gradient.svg similarity index 100% rename from packages/canary/src/icons/search-content.svg rename to packages/canary/src/icons/dev-insights-gradient.svg diff --git a/packages/canary/src/icons/dev-insights-icon.svg b/packages/canary/src/icons/dev-insights-icon.svg new file mode 100644 index 000000000..fbfba7d34 --- /dev/null +++ b/packages/canary/src/icons/dev-insights-icon.svg @@ -0,0 +1,8 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M0.5 2H11.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.5 5H4.16667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.5 8H4.16667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.5 11H11.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M8.20052 8C9.21304 8 10.0339 7.16053 10.0339 6.125C10.0339 5.08947 9.21304 4.25 8.20052 4.25C7.188 4.25 6.36719 5.08947 6.36719 6.125C6.36719 7.16053 7.188 8 8.20052 8Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M9.49609 7.45117L11.1329 9.12517" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/packages/canary/src/icons/more-folder.svg b/packages/canary/src/icons/dev-portal-gradient.svg similarity index 100% rename from packages/canary/src/icons/more-folder.svg rename to packages/canary/src/icons/dev-portal-gradient.svg diff --git a/packages/canary/src/icons/dev-portal-icon.svg b/packages/canary/src/icons/dev-portal-icon.svg new file mode 100644 index 000000000..f0594a9ac --- /dev/null +++ b/packages/canary/src/icons/dev-portal-icon.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M2.5 1H9.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10.5 4H1.5C0.947715 4 0.5 4.44772 0.5 5V11C0.5 11.5523 0.947715 12 1.5 12H10.5C11.0523 12 11.5 11.5523 11.5 11V5C11.5 4.44772 11.0523 4 10.5 4Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M4.5 7H7.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/execution-gradient.svg b/packages/canary/src/icons/execution-gradient.svg new file mode 100644 index 000000000..8d41ca79f --- /dev/null +++ b/packages/canary/src/icons/execution-gradient.svg @@ -0,0 +1,9 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 1C1.22386 1 1 1.22386 1 1.5V16.5C1 16.7761 1.22386 17 1.5 17H16.5C16.7761 17 17 16.7761 17 16.5V1.5C17 1.22386 16.7761 1 16.5 1H1.5ZM2 16V2H16V16H2ZM6.99807 5.56588C6.84332 5.47745 6.65319 5.47808 6.49904 5.56754C6.34488 5.65701 6.25 5.82176 6.25 6V12C6.25 12.1782 6.34488 12.343 6.49904 12.4325C6.65319 12.5219 6.84332 12.5226 6.99807 12.4341L12.2481 9.43412C12.4039 9.3451 12.5 9.17943 12.5 9C12.5 8.82057 12.4039 8.6549 12.2481 8.56588L6.99807 5.56588ZM10.9922 9L7.25 11.1384V6.86159L10.9922 9Z" fill="url(#paint0_linear_17614_128143)"/> +<defs> +<linearGradient id="paint0_linear_17614_128143" x1="9" y1="1" x2="9" y2="17" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/execution-icon.svg b/packages/canary/src/icons/execution-icon.svg index c743d65f5..c45b1a54a 100644 --- a/packages/canary/src/icons/execution-icon.svg +++ b/packages/canary/src/icons/execution-icon.svg @@ -1,6 +1,6 @@ -<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> <g> -<path d="M10 0.5H2C1.17157 0.5 0.5 1.17157 0.5 2V10C0.5 10.8284 1.17157 11.5 2 11.5H10C10.8284 11.5 11.5 10.8284 11.5 10V2C11.5 1.17157 10.8284 0.5 10 0.5Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> -<path d="M4.5 3.5L8.5 6L4.5 8.5V3.5Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10 1H2C1.17157 1 0.5 1.67157 0.5 2.5V10.5C0.5 11.3284 1.17157 12 2 12H10C10.8284 12 11.5 11.3284 11.5 10.5V2.5C11.5 1.67157 10.8284 1 10 1Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M4.5 4L8.5 6.5L4.5 9V4Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> </g> </svg> diff --git a/packages/canary/src/icons/featured-flags-icon.svg b/packages/canary/src/icons/featured-flags-icon.svg deleted file mode 100644 index f101df864..000000000 --- a/packages/canary/src/icons/featured-flags-icon.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path fill-rule="evenodd" clip-rule="evenodd" d="M3 0.5C3 0.223858 2.77614 0 2.5 0C2.22386 0 2 0.223858 2 0.5V11.5C2 11.7761 2.22386 12 2.5 12C2.77614 12 3 11.7761 3 11.5V0.5ZM4.72361 1.05279C4.56861 0.975289 4.38454 0.983571 4.23713 1.07467C4.08973 1.16578 4 1.32671 4 1.5V7.5C4 7.67329 4.08973 7.83422 4.23713 7.92533C4.38454 8.01643 4.56861 8.02471 4.72361 7.94721L10.7236 4.94721C10.893 4.86252 11 4.68939 11 4.5C11 4.31061 10.893 4.13748 10.7236 4.05279L4.72361 1.05279ZM9.38197 4.5L5 6.69098V2.30902L9.38197 4.5Z" fill="currentColor"/> -</svg> \ No newline at end of file diff --git a/packages/canary/src/icons/flag.svg b/packages/canary/src/icons/flag-gradient.svg similarity index 87% rename from packages/canary/src/icons/flag.svg rename to packages/canary/src/icons/flag-gradient.svg index a40ef7d49..b36b1d053 100644 --- a/packages/canary/src/icons/flag.svg +++ b/packages/canary/src/icons/flag-gradient.svg @@ -1,5 +1,5 @@ <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_9309_36390)"> +<g> <path fill-rule="evenodd" clip-rule="evenodd" d="M3.125 1.125C3.125 0.848858 2.90114 0.625 2.625 0.625C2.34886 0.625 2.125 0.848858 2.125 1.125V2.625V11.625V17.625C2.125 17.9011 2.34886 18.125 2.625 18.125C2.90114 18.125 3.125 17.9011 3.125 17.625V12.125H16.125C16.2983 12.125 16.4592 12.0353 16.5503 11.8879C16.6414 11.7405 16.6497 11.5564 16.5722 11.4014L14.434 7.125L16.5722 2.84861C16.6497 2.69361 16.6414 2.50954 16.5503 2.36213C16.4592 2.21473 16.2983 2.125 16.125 2.125H3.125V1.125ZM3.125 3.125V11.125H15.316L13.4278 7.34861C13.3574 7.20784 13.3574 7.04216 13.4278 6.90139L15.316 3.125H3.125Z" fill="url(#paint0_linear_9309_36390)"/> </g> <defs> @@ -7,8 +7,5 @@ <stop stop-color="currentColor"/> <stop offset="1" stop-color="currentColor"/> </linearGradient> -<clipPath id="clip0_9309_36390"> -<rect width="100%" height="100%" fill="currentColor"/> -</clipPath> </defs> </svg> diff --git a/packages/canary/src/icons/flag-icon.svg b/packages/canary/src/icons/flag-icon.svg new file mode 100644 index 000000000..4c292700e --- /dev/null +++ b/packages/canary/src/icons/flag-icon.svg @@ -0,0 +1,5 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C3 0.723858 2.77614 0.5 2.5 0.5C2.22386 0.5 2 0.723858 2 1V12C2 12.2761 2.22386 12.5 2.5 12.5C2.77614 12.5 3 12.2761 3 12V1ZM4.72361 1.55279C4.56861 1.47529 4.38454 1.48357 4.23713 1.57467C4.08973 1.66578 4 1.82671 4 2V8C4 8.17329 4.08973 8.33422 4.23713 8.42533C4.38454 8.51643 4.56861 8.52471 4.72361 8.44721L10.7236 5.44721C10.893 5.36252 11 5.18939 11 5C11 4.81061 10.893 4.63748 10.7236 4.55279L4.72361 1.55279ZM9.38197 5L5 7.19098V2.80902L9.38197 5Z" fill="currentColor"/> +</g> +</svg> diff --git a/packages/canary/src/icons/incidents-gradient.svg b/packages/canary/src/icons/incidents-gradient.svg new file mode 100644 index 000000000..de7ee5be8 --- /dev/null +++ b/packages/canary/src/icons/incidents-gradient.svg @@ -0,0 +1,9 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M3 3.25C1.89511 3.25 1 4.14511 1 5.25V11.25C1 12.3549 1.89511 13.25 3 13.25H10.5C10.7761 13.25 11 13.0261 11 12.75C11 12.4739 10.7761 12.25 10.5 12.25H3C2.44739 12.25 2 11.8026 2 11.25V5.25C2 4.69739 2.44739 4.25 3 4.25H15C15.5526 4.25 16 4.69739 16 5.25V9C16 9.27614 16.2239 9.5 16.5 9.5C16.7761 9.5 17 9.27614 17 9V5.25C17 4.14511 16.1049 3.25 15 3.25H3ZM5.4375 9.1875C5.95527 9.1875 6.375 8.76777 6.375 8.25C6.375 7.73223 5.95527 7.3125 5.4375 7.3125C4.91973 7.3125 4.5 7.73223 4.5 8.25C4.5 8.76777 4.91973 9.1875 5.4375 9.1875ZM9 9.1875C9.51777 9.1875 9.9375 8.76777 9.9375 8.25C9.9375 7.73223 9.51777 7.3125 9 7.3125C8.48223 7.3125 8.0625 7.73223 8.0625 8.25C8.0625 8.76777 8.48223 9.1875 9 9.1875ZM13.5 7.5C13.7761 7.5 14 7.72386 14 8V12.375C14 12.6511 13.7761 12.875 13.5 12.875C13.2239 12.875 13 12.6511 13 12.375V8C13 7.72386 13.2239 7.5 13.5 7.5ZM14.4375 15.5625C14.4375 16.0803 14.0178 16.5 13.5 16.5C12.9822 16.5 12.5625 16.0803 12.5625 15.5625C12.5625 15.0447 12.9822 14.625 13.5 14.625C14.0178 14.625 14.4375 15.0447 14.4375 15.5625Z" fill="url(#paint0_linear_17614_128232)"/> +<defs> +<linearGradient id="paint0_linear_17614_128232" x1="9" y1="3.25" x2="9" y2="16.5" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/incidents-icon.svg b/packages/canary/src/icons/incidents-icon.svg new file mode 100644 index 000000000..1428d11a2 --- /dev/null +++ b/packages/canary/src/icons/incidents-icon.svg @@ -0,0 +1,5 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M6.00039 9.9998C6.33176 9.9998 6.60039 9.73118 6.60039 9.3998C6.60039 9.06843 6.33176 8.7998 6.00039 8.7998C5.66902 8.7998 5.40039 9.06843 5.40039 9.3998C5.40039 9.73118 5.66902 9.9998 6.00039 9.9998Z" fill="currentColor"/> +<path d="M6 4.5L6 7.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.954374 10.0449L5.2843 2.20212C5.35394 2.07606 5.45727 1.97074 5.58333 1.89733C5.70938 1.82392 5.85346 1.78516 6.00028 1.78516C6.1471 1.78516 6.29118 1.82392 6.41723 1.89733C6.54329 1.97074 6.64662 2.07606 6.71626 2.20212L11.0462 10.0449C11.1128 10.1657 11.1461 10.3013 11.1429 10.4385C11.1397 10.5756 11.1002 10.7096 11.028 10.8273C10.9559 10.9451 10.8537 11.0426 10.7314 11.1103C10.6091 11.178 10.4708 11.2137 10.3302 11.2137H1.67035C1.52971 11.2137 1.39149 11.178 1.26918 11.1103C1.14688 11.0426 1.04467 10.9451 0.972537 10.8273C0.900405 10.7096 0.860814 10.5756 0.85763 10.4385C0.854447 10.3013 0.887779 10.1657 0.954374 10.0449Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/packages/canary/src/icons/filter-organization.svg b/packages/canary/src/icons/infrastructure-gradient.svg similarity index 90% rename from packages/canary/src/icons/filter-organization.svg rename to packages/canary/src/icons/infrastructure-gradient.svg index 82a0a42a9..6cc79c6e2 100644 --- a/packages/canary/src/icons/filter-organization.svg +++ b/packages/canary/src/icons/infrastructure-gradient.svg @@ -1,5 +1,5 @@ <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_9309_36401)"> +<g> <path fill-rule="evenodd" clip-rule="evenodd" d="M0.998566 0.5C1.27471 0.5 1.49857 0.723858 1.49857 1V5.83425H4.19914C4.47528 5.83425 4.69914 6.05811 4.69914 6.33425C4.69914 6.61039 4.47528 6.83425 4.19914 6.83425H1.49857V14.3692H4.19914C4.47528 14.3692 4.69914 14.593 4.69914 14.8692C4.69914 15.1453 4.47528 15.3692 4.19914 15.3692H0.998566C0.722423 15.3692 0.498566 15.1453 0.498566 14.8692V6.33425V1C0.498566 0.723858 0.722423 0.5 0.998566 0.5ZM7.39981 3.70062C7.12367 3.70062 6.89981 3.92448 6.89981 4.20062V8.46806C6.89981 8.7442 7.12367 8.96806 7.39981 8.96806H17.0015C17.2777 8.96806 17.5015 8.7442 17.5015 8.46806V4.20062C17.5015 3.92448 17.2777 3.70062 17.0015 3.70062H7.39981ZM16.5015 7.96806H7.89981V4.70062H16.5015V7.96806ZM7.39981 12.2355C7.12367 12.2355 6.89981 12.4594 6.89981 12.7355V17.0029C6.89981 17.2791 7.12367 17.5029 7.39981 17.5029H17.0015C17.2777 17.5029 17.5015 17.2791 17.5015 17.0029V12.7355C17.5015 12.4594 17.2777 12.2355 17.0015 12.2355H7.39981ZM7.89981 16.5029V13.2355H16.5015V16.5029H7.89981Z" fill="url(#paint0_linear_9309_36401)"/> </g> <defs> @@ -7,8 +7,5 @@ <stop stop-color="currentColor"/> <stop offset="1" stop-color="currentColor"/> </linearGradient> -<clipPath id="clip0_9309_36401"> -<rect width="100%" height="100%" fill="currentColor"/> -</clipPath> </defs> </svg> diff --git a/packages/canary/src/icons/infrastructure-icon.svg b/packages/canary/src/icons/infrastructure-icon.svg new file mode 100644 index 000000000..29a477c6a --- /dev/null +++ b/packages/canary/src/icons/infrastructure-icon.svg @@ -0,0 +1,8 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M11.5004 3.2002H4.90039V6.13353H11.5004V3.2002Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M11.5004 9.06641H4.90039V11.9997H11.5004V9.06641Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.5 1V10.5333H2.7" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M0.5 4.66699H2.7" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/log-out-icon.svg b/packages/canary/src/icons/log-out-icon.svg new file mode 100644 index 000000000..0f17c55f3 --- /dev/null +++ b/packages/canary/src/icons/log-out-icon.svg @@ -0,0 +1,6 @@ +<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M11.5 6H3.5M11.5 6L8.5 3M11.5 6L8.5 9" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M5.5 11.5H2C1.60218 11.5 1.22064 11.342 0.93934 11.0607C0.658035 10.7794 0.5 10.3978 0.5 10V2C0.5 1.60218 0.658035 1.22064 0.93934 0.93934C1.22064 0.658035 1.60218 0.5 2 0.5H5.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/menu-dots-icon.svg b/packages/canary/src/icons/menu-dots-icon.svg new file mode 100644 index 000000000..9d04d011b --- /dev/null +++ b/packages/canary/src/icons/menu-dots-icon.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<circle cx="6" cy="1" r="1" fill="currentColor"/> +<circle cx="6" cy="6" r="1" fill="currentColor"/> +<circle cx="6" cy="11" r="1" fill="currentColor"/> +</g> +</svg> diff --git a/packages/canary/src/icons/navigation-icon.svg b/packages/canary/src/icons/navigation-icon.svg new file mode 100644 index 000000000..bfe333470 --- /dev/null +++ b/packages/canary/src/icons/navigation-icon.svg @@ -0,0 +1,5 @@ +<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 0C0.223858 0 0 0.223858 0 0.5V4.5C0 4.77614 0.223858 5 0.5 5H4.5C4.77614 5 5 4.77614 5 4.5V0.5C5 0.223858 4.77614 0 4.5 0H0.5ZM1 4V1H4V4H1ZM0.5 7C0.223858 7 0 7.22386 0 7.5V11.5C0 11.7761 0.223858 12 0.5 12H4.5C4.77614 12 5 11.7761 5 11.5V7.5C5 7.22386 4.77614 7 4.5 7H0.5ZM1 11V8H4V11H1ZM6 0.5C6 0.223858 6.22386 0 6.5 0H11.5C11.7761 0 12 0.223858 12 0.5C12 0.776142 11.7761 1 11.5 1H6.5C6.22386 1 6 0.776142 6 0.5ZM6.5 3C6.22386 3 6 3.22386 6 3.5C6 3.77614 6.22386 4 6.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H6.5ZM6 7.5C6 7.22386 6.22386 7 6.5 7H11.5C11.7761 7 12 7.22386 12 7.5C12 7.77614 11.7761 8 11.5 8H6.5C6.22386 8 6 7.77614 6 7.5ZM6.5 10C6.22386 10 6 10.2239 6 10.5C6 10.7761 6.22386 11 6.5 11H11.5C11.7761 11 12 10.7761 12 10.5C12 10.2239 11.7761 10 11.5 10H6.5Z" fill="currentColor"/> +</g> +</svg> diff --git a/packages/canary/src/icons/paint-icon.svg b/packages/canary/src/icons/paint-icon.svg new file mode 100644 index 000000000..d6a864273 --- /dev/null +++ b/packages/canary/src/icons/paint-icon.svg @@ -0,0 +1,6 @@ +<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M1.25 0.5V6.36667C1.25 6.75565 1.40452 7.1287 1.67958 7.40376C1.95463 7.67881 2.32768 7.83333 2.71667 7.83333H4.91667V10.4C4.91667 10.6917 5.03256 10.9715 5.23885 11.1778C5.44514 11.3841 5.72493 11.5 6.01667 11.5C6.3084 11.5 6.58819 11.3841 6.79448 11.1778C7.00077 10.9715 7.11667 10.6917 7.11667 10.4V7.83333H9.31667C9.70565 7.83333 10.0787 7.67881 10.3538 7.40376C10.6288 7.1287 10.7833 6.75565 10.7833 6.36667V0.5H1.25Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M2.7168 5.63379H9.3168" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/pin.svg b/packages/canary/src/icons/pin.svg index 3d5fcc290..2cca950a2 100644 --- a/packages/canary/src/icons/pin.svg +++ b/packages/canary/src/icons/pin.svg @@ -1,9 +1,3 @@ <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2.6064 8.2064L12.8752 2.4752M9.7936 15.3936L12.6592 10.2592L15.5248 5.1248M11.4 1L17 6.6M6.2 11.8L1 17M1 6.6L11.4 17" stroke="url(#paint0_linear_4_17)" stroke-miterlimit="10" stroke-linecap="round"/> -<defs> -<linearGradient id="paint0_linear_4_17" x1="9" y1="1" x2="9" y2="17" gradientUnits="userSpaceOnUse"> -<stop stop-color="currentColor"/> -<stop offset="1" stop-color="currentColor"/> -</linearGradient> -</defs> +<path d="M2.6064 8.2064L12.8752 2.4752M9.7936 15.3936L12.6592 10.2592L15.5248 5.1248M11.4 1L17 6.6M6.2 11.8L1 17M1 6.6L11.4 17" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round"/> </svg> diff --git a/packages/canary/src/icons/pipelines-gradient.svg b/packages/canary/src/icons/pipelines-gradient.svg new file mode 100644 index 000000000..0aa249951 --- /dev/null +++ b/packages/canary/src/icons/pipelines-gradient.svg @@ -0,0 +1,11 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M6 1.25C4.61939 1.25 3.5 2.36939 3.5 3.75V10.75C3.5 11.0261 3.27614 11.25 3 11.25C2.72386 11.25 2.5 11.0261 2.5 10.75V3.75C2.5 1.81711 4.06711 0.25 6 0.25C7.93289 0.25 9.5 1.81711 9.5 3.75V14.25C9.5 15.6306 10.6194 16.75 12 16.75C13.3806 16.75 14.5 15.6306 14.5 14.25V7.25C14.5 6.97386 14.7239 6.75 15 6.75C15.2761 6.75 15.5 6.97386 15.5 7.25V14.25C15.5 16.1829 13.9329 17.75 12 17.75C10.0671 17.75 8.5 16.1829 8.5 14.25V3.75C8.5 2.36939 7.38061 1.25 6 1.25ZM15 1.25C14.0335 1.25 13.25 2.0335 13.25 3C13.25 3.9665 14.0335 4.75 15 4.75C15.9665 4.75 16.75 3.9665 16.75 3C16.75 2.0335 15.9665 1.25 15 1.25ZM12.25 3C12.25 1.48122 13.4812 0.25 15 0.25C16.5188 0.25 17.75 1.48122 17.75 3C17.75 4.51878 16.5188 5.75 15 5.75C13.4812 5.75 12.25 4.51878 12.25 3ZM1.25 15C1.25 14.0335 2.0335 13.25 3 13.25C3.9665 13.25 4.75 14.0335 4.75 15C4.75 15.9665 3.9665 16.75 3 16.75C2.0335 16.75 1.25 15.9665 1.25 15ZM3 12.25C1.48122 12.25 0.25 13.4812 0.25 15C0.25 16.5188 1.48122 17.75 3 17.75C4.51878 17.75 5.75 16.5188 5.75 15C5.75 13.4812 4.51878 12.25 3 12.25Z" fill="url(#paint0_linear_17614_128135)"/> +</g> +<defs> +<linearGradient id="paint0_linear_17614_128135" x1="9" y1="0.25" x2="9" y2="17.75" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/pipelines-icon.svg b/packages/canary/src/icons/pipelines-icon.svg index 11a407946..90a37cce6 100644 --- a/packages/canary/src/icons/pipelines-icon.svg +++ b/packages/canary/src/icons/pipelines-icon.svg @@ -1,8 +1,5 @@ -<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> - <path d="M2 11.5C2.82843 11.5 3.5 10.8284 3.5 10C3.5 9.17157 2.82843 8.5 2 8.5C1.17157 8.5 0.5 9.17157 0.5 10C0.5 10.8284 1.17157 11.5 2 11.5Z" - stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M10 3.5C10.8284 3.5 11.5 2.82843 11.5 2C11.5 1.17157 10.8284 0.5 10 0.5C9.17157 0.5 8.5 1.17157 8.5 2C8.5 2.82843 9.17157 3.5 10 3.5Z" - stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M2 6.5V3.5C2 2.96957 2.21071 2.46086 2.58579 2.08579C2.96086 1.71071 3.46957 1.5 4 1.5C4.53043 1.5 5.03914 1.71071 5.41421 2.08579C5.78929 2.46086 6 2.96957 6 3.5V8.5C6 9.03043 6.21071 9.53914 6.58579 9.91421C6.96086 10.2893 7.46957 10.5 8 10.5C8.53043 10.5 9.03914 10.2893 9.41421 9.91421C9.78929 9.53914 10 9.03043 10 8.5V5.5" - stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> -</svg> \ No newline at end of file +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M2 12C2.82843 12 3.5 11.3284 3.5 10.5C3.5 9.67157 2.82843 9 2 9C1.17157 9 0.5 9.67157 0.5 10.5C0.5 11.3284 1.17157 12 2 12Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10 4C10.8284 4 11.5 3.32843 11.5 2.5C11.5 1.67157 10.8284 1 10 1C9.17157 1 8.5 1.67157 8.5 2.5C8.5 3.32843 9.17157 4 10 4Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M2 7V4C2 3.46957 2.21071 2.96086 2.58579 2.58579C2.96086 2.21071 3.46957 2 4 2C4.53043 2 5.03914 2.21071 5.41421 2.58579C5.78929 2.96086 6 3.46957 6 4V9C6 9.53043 6.21071 10.0391 6.58579 10.4142C6.96086 10.7893 7.46957 11 8 11C8.53043 11 9.03914 10.7893 9.41421 10.4142C9.78929 10.0391 10 9.53043 10 9V6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/packages/canary/src/icons/repositories-gradient.svg b/packages/canary/src/icons/repositories-gradient.svg new file mode 100644 index 000000000..9c47b94ac --- /dev/null +++ b/packages/canary/src/icons/repositories-gradient.svg @@ -0,0 +1,9 @@ +<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M3.13333 1.5C2.70015 1.5 2.2847 1.67208 1.97839 1.97839C1.67208 2.2847 1.5 2.70015 1.5 3.13333V10H6.33333C6.60948 10 6.83333 10.2239 6.83333 10.5V13H11.1667V10.5C11.1667 10.2239 11.3905 10 11.6667 10H16.5V3.13333C16.5 2.70015 16.3279 2.2847 16.0216 1.97839C15.7153 1.67208 15.2999 1.5 14.8667 1.5H3.13333ZM0.5 3.13333V10.5V13.2998V15.4C0.5 15.4066 0.500126 15.4131 0.500377 15.4196C0.511 16.5703 1.44709 17.4998 2.60029 17.4998H15.4003C16.5601 17.4998 17.5003 16.5596 17.5003 15.3998V13.2998L17.5 13.3001V10.5V3.13333C17.5 2.43493 17.2226 1.76513 16.7287 1.27129C16.2349 0.77744 15.5651 0.5 14.8667 0.5H3.13333C2.43493 0.5 1.76513 0.77744 1.27129 1.27129C0.77744 1.76513 0.5 2.43493 0.5 3.13333ZM16.5002 15.4144C16.5001 15.4096 16.5 15.4048 16.5 15.4V14.2998V11H12.1667V13.5C12.1667 13.7761 11.9428 14 11.6667 14H6.33333C6.05719 14 5.83333 13.7761 5.83333 13.5V11H1.5V14.2995L1.50029 14.2998V15.3998C1.50029 16.0073 1.99277 16.4998 2.60029 16.4998H15.4003C16.0029 16.4998 16.4924 16.0152 16.5002 15.4144Z" fill="url(#paint0_linear_17635_52929)"/> +<defs> +<linearGradient id="paint0_linear_17635_52929" x1="9.00014" y1="0.5" x2="9.00014" y2="17.4998" gradientUnits="userSpaceOnUse"> +<stop stop-color="currentColor"/> +<stop offset="1" stop-color="currentColor"/> +</linearGradient> +</defs> +</svg> diff --git a/packages/canary/src/icons/repositories-icon.svg b/packages/canary/src/icons/repositories-icon.svg index 6187990a1..812e77835 100644 --- a/packages/canary/src/icons/repositories-icon.svg +++ b/packages/canary/src/icons/repositories-icon.svg @@ -1,13 +1,5 @@ -<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> - <g clip-path="url(#clip0_9839_14689)"> - <path fill-rule="evenodd" clip-rule="evenodd" - d="M1 2C1 1.44772 1.44772 1 2 1H10C10.5523 1 11 1.44772 11 2V6H8.5C8.22386 6 8 6.22386 8 6.5V8H4V6.5C4 6.22386 3.77614 6 3.5 6H1V2ZM0 6.5V2C0 0.89543 0.89543 0 2 0H10C11.1046 0 12 0.89543 12 2V6.5V10C12 11.1046 11.1046 12 10 12H2C0.89543 12 0 11.1046 0 10V6.5ZM11 7V10C11 10.5523 10.5523 11 10 11H2C1.44772 11 1 10.5523 1 10V7H3V8.5C3 8.77614 3.22386 9 3.5 9H8.5C8.77614 9 9 8.77614 9 8.5V7H11Z" - fill="currentColor" - /> - </g> - <defs> - <clipPath id="clip0_9839_14689"> - <rect width="100%" height="100%" fill="currentColor" /> - </clipPath> - </defs> -</svg> \ No newline at end of file +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path fill-rule="evenodd" clip-rule="evenodd" d="M1 2.49991C1 1.94767 1.44767 1.5 1.99991 1.5H9.9994C10.5516 1.5 10.9993 1.94767 10.9993 2.49991V6.50026H8.49949C8.22335 6.50026 7.9995 6.72412 7.9995 7.00026V8.50013H3.99981V7.00026C3.99981 6.72412 3.77595 6.50026 3.49981 6.50026H1V2.49991ZM0 7.00026V2.49991C0 1.39539 0.895388 0.5 1.99991 0.5H9.9994C11.1039 0.5 11.9993 1.39539 11.9993 2.49991V7.00026V10.4994C11.9993 11.6039 11.1039 12.4993 9.9994 12.4993H1.99991C0.895388 12.4993 0 11.6039 0 10.4994V7.00026ZM10.9993 7.50026V10.4994C10.9993 11.0516 10.5516 11.4993 9.9994 11.4993H1.99991C1.44767 11.4993 1 11.0516 1 10.4994V7.50026H2.99981V9.00013C2.99981 9.27627 3.22367 9.50013 3.49981 9.50013H8.49949C8.77564 9.50013 8.99949 9.27627 8.99949 9.00013V7.50026H10.9993Z" fill="currentColor"/> +</g> +</svg> diff --git a/packages/canary/src/icons/shield-tick.svg b/packages/canary/src/icons/security-tests-gradient.svg similarity index 93% rename from packages/canary/src/icons/shield-tick.svg rename to packages/canary/src/icons/security-tests-gradient.svg index 745c05c2a..24bc341ef 100644 --- a/packages/canary/src/icons/shield-tick.svg +++ b/packages/canary/src/icons/security-tests-gradient.svg @@ -1,5 +1,5 @@ <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> -<g clip-path="url(#clip0_9309_36504)"> +<g> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.15442 0.0243221C9.05428 -0.00810736 8.94646 -0.00810736 8.84632 0.0243221L1.84595 2.29138C1.63971 2.35817 1.5 2.55026 1.5 2.76706V10.135C1.5 12.9359 3.42191 14.9085 5.21673 16.1437C6.12408 16.7681 7.02796 17.2251 7.70317 17.5257C8.04149 17.6764 8.32421 17.7886 8.52365 17.8636C8.62341 17.9011 8.70246 17.9293 8.75736 17.9484C8.78482 17.958 8.80624 17.9653 8.82121 17.9703L8.83877 17.9761L8.84382 17.9778L8.84539 17.9783L8.84594 17.9785C8.84614 17.9785 8.84632 17.9786 9.00037 17.5029L8.84632 17.9786C8.94646 18.011 9.05428 18.011 9.15442 17.9786L9.00037 17.5029C9.15442 17.9786 9.1546 17.9785 9.15481 17.9785L9.15535 17.9783L9.15693 17.9778L9.16198 17.9761L9.17953 17.9703C9.1945 17.9653 9.21593 17.958 9.24338 17.9484C9.29828 17.9293 9.37733 17.9011 9.4771 17.8636C9.67654 17.7886 9.95925 17.6764 10.2976 17.5257C10.9728 17.2251 11.8767 16.7681 12.784 16.1437C14.5788 14.9085 16.5007 12.9359 16.5007 10.135V2.76706C16.5007 2.55026 16.361 2.35817 16.1548 2.29138L9.15442 0.0243221ZM9.12524 16.9275C9.07809 16.9452 9.03631 16.9606 9.00037 16.9736C8.96443 16.9606 8.92265 16.9452 8.8755 16.9275C8.69211 16.8586 8.42792 16.7538 8.10996 16.6122C7.4726 16.3284 6.62638 15.8998 5.78364 15.3199C4.07827 14.1463 2.5 12.435 2.5 10.135V3.1307L9.00037 1.02557L15.5007 3.1307V10.135C15.5007 12.435 13.9225 14.1463 12.2171 15.3199C11.3744 15.8998 10.5281 16.3284 9.89079 16.6122C9.57282 16.7538 9.30863 16.8586 9.12524 16.9275ZM13.3504 6.35672C13.5474 6.16323 13.5502 5.84666 13.3567 5.64965C13.1632 5.45263 12.8467 5.44978 12.6496 5.64328L7.91018 10.2981L5.35146 7.76937C5.15505 7.57526 4.83848 7.57713 4.64437 7.77354C4.45026 7.96995 4.45213 8.28652 4.64854 8.48063L7.55763 11.3556C7.75197 11.5477 8.0645 11.5482 8.25945 11.3567L13.3504 6.35672Z" fill="url(#paint0_linear_9309_36504)"/> </g> <defs> @@ -7,8 +7,5 @@ <stop stop-color="currentColor"/> <stop offset="1" stop-color="currentColor"/> </linearGradient> -<clipPath id="clip0_9309_36504"> -<rect width="100%" height="100%" fill="currentColor"/> -</clipPath> </defs> </svg> diff --git a/packages/canary/src/icons/security-tests-icon.svg b/packages/canary/src/icons/security-tests-icon.svg new file mode 100644 index 000000000..ffc31c82c --- /dev/null +++ b/packages/canary/src/icons/security-tests-icon.svg @@ -0,0 +1,6 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M6 1C4.49024 2.4246 2.56159 3.32475 0.5 3.567C0.5 3.567 0.5 9.8 6 12C11.5 9.8 11.5 3.567 11.5 3.567C9.43841 3.32475 7.50976 2.4246 6 1Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M8.5 5L5.6875 8L4 6.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/icons/chain.svg b/packages/canary/src/icons/supply-chain-gradient.svg similarity index 100% rename from packages/canary/src/icons/chain.svg rename to packages/canary/src/icons/supply-chain-gradient.svg diff --git a/packages/canary/src/icons/supply-chain-icon.svg b/packages/canary/src/icons/supply-chain-icon.svg new file mode 100644 index 000000000..f1abf1f68 --- /dev/null +++ b/packages/canary/src/icons/supply-chain-icon.svg @@ -0,0 +1,8 @@ +<svg viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g> +<path d="M7.75097 2.24999C7.32621 2.11318 6.87351 2.08731 6.43593 2.17482C5.99835 2.26234 5.59043 2.46034 5.25097 2.74999L2.25097 5.74999C1.96132 6.08946 1.76332 6.49738 1.6758 6.93496C1.58829 7.37254 1.61416 7.82523 1.75097 8.24999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M10.25 4.75C10.3868 5.17476 10.4127 5.62745 10.3252 6.06503C10.2377 6.50261 10.0397 6.91053 9.75 7.25L6.75 10.25C6.41053 10.5397 6.00261 10.7377 5.56503 10.8252C5.12745 10.9127 4.67476 10.8868 4.25 10.75" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M4.5 8L0.5 12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M11.5 1L7.5 5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/> +</g> +</svg> diff --git a/packages/canary/src/styles.css b/packages/canary/src/styles.css index afdee0953..1f7198bb0 100644 --- a/packages/canary/src/styles.css +++ b/packages/canary/src/styles.css @@ -131,6 +131,9 @@ --background-08: var(--grey-12); --background-09: var(--grey-15); --background-10: var(--grey-94); + --background-11: var(--grey-40); + --background-12: var(--grey-20); + --background-13: var(--grey-30); --background-danger: var(--red-65) / 0.1; /* red65/10 */ --background-success: 154 13% 10% / 0.4; /* Borders */ @@ -155,6 +158,8 @@ --icon-06: var(--grey-30); --icon-07: var(--grey-40); --icon-08: var(--grey-90); + --icon-09: var(--grey-70); + --icon-10: var(--grey-6); --icon-danger: var(--red-65); --icon-alert: var(--orange-55); --icon-success: var(--green-65); @@ -263,6 +268,9 @@ --background-08: var(--grey-12); --background-09: var(--grey-15); --background-10: var(--grey-94); + --background-11: var(--grey-40); + --background-12: var(--grey-20); + --background-13: var(--grey-30); --background-danger: var(--red-65) / 0.1; /* red65/10 */ --background-success: 154 13% 10% / 0.4; /* Borders */ @@ -287,6 +295,8 @@ --icon-06: var(--grey-30); --icon-07: var(--grey-40); --icon-08: var(--grey-90); + --icon-09: var(--grey-70); + --icon-10: var(--grey-6); --icon-danger: var(--red-65); --icon-alert: var(--orange-55); --icon-success: var(--green-65); diff --git a/packages/playground/src/components/branch-chooser.tsx b/packages/playground/src/components/branch-chooser.tsx index 7a3fdf745..27bf3ed42 100644 --- a/packages/playground/src/components/branch-chooser.tsx +++ b/packages/playground/src/components/branch-chooser.tsx @@ -46,11 +46,11 @@ export const BranchSelector = ({ ...props }: PageProps) => { 'border-2': prefix })} > - {prefix ? null : <Icon name="branch" size={12} className="text-tertiary-background min-w-[12px]" />} - <Text as="p" align="left" className="text-primary/90 w-full truncate"> + {prefix ? null : <Icon name="branch" size={12} className="min-w-[12px] text-tertiary-background" />} + <Text as="p" align="left" className="w-full truncate text-primary/90"> {prefix ? `${prefix}: ${name}` : name} </Text> - <Icon name="chevron-down" size={10} className="chevron-down text-tertiary-background ml-0 min-w-[10px]" /> + <Icon name="chevron-down" size={10} className="chevron-down ml-0 min-w-[10px] text-tertiary-background" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="start"> diff --git a/packages/playground/src/components/branch-selector/branch-selector-dropdown.tsx b/packages/playground/src/components/branch-selector/branch-selector-dropdown.tsx index 44792020a..37b4e0e83 100644 --- a/packages/playground/src/components/branch-selector/branch-selector-dropdown.tsx +++ b/packages/playground/src/components/branch-selector/branch-selector-dropdown.tsx @@ -121,7 +121,7 @@ export const BranchSelectorDropdown = ({ name, branchList, tagList, selectBranch <div className="mt-1"> {filteredItems.length === 0 && ( <div className="px-5 py-4 text-center"> - <Text className="text-foreground-2 leading-tight" size={2}> + <Text className="leading-tight text-foreground-2" size={2}> Nothing to show </Text> </div> @@ -143,7 +143,7 @@ export const BranchSelectorDropdown = ({ name, branchList, tagList, selectBranch key={item.name} > <div className="flex w-full min-w-0 items-center gap-x-2"> - {isSelected && <Icon name="tick" size={12} className="text-foreground-1 min-w-[12px]" />} + {isSelected && <Icon name="tick" size={12} className="min-w-[12px] text-foreground-1" />} <Text className={cn('text-foreground-2', { 'text-foreground-1': isSelected @@ -156,7 +156,7 @@ export const BranchSelectorDropdown = ({ name, branchList, tagList, selectBranch {isDefault && ( <Badge - className="text-foreground-3 bg-transparent font-medium" + className="bg-transparent font-medium text-foreground-3" variant="outline" // TODO: Review and update 'muted' theme implementation // Current 'muted' theme styles don't fully match the design requirements @@ -181,9 +181,9 @@ export const BranchSelectorDropdown = ({ name, branchList, tagList, selectBranch </div> <DropdownMenuItem className="p-0" asChild> - <div className="border-borders-4 mt-1 border-t px-3 py-2"> + <div className="mt-1 border-t border-borders-4 px-3 py-2"> <Link to={viewAllUrl}> - <Text className="text-ring hover:text-foreground-1 leading-none transition-colors duration-200"> + <Text className="leading-none text-ring transition-colors duration-200 hover:text-foreground-1"> View all {activeTab === BranchSelectorTab.BRANCHES ? 'branches' : 'tags'} </Text> </Link> diff --git a/packages/playground/src/components/branch-selector/branch-selector.tsx b/packages/playground/src/components/branch-selector/branch-selector.tsx index c20346d3e..2d46637d2 100644 --- a/packages/playground/src/components/branch-selector/branch-selector.tsx +++ b/packages/playground/src/components/branch-selector/branch-selector.tsx @@ -42,12 +42,12 @@ export const BranchSelector = ({ size={size} > {prefix ? null : ( - <Icon className="text-icons-9 min-w-[12px] fill-transparent" name={isTag ? 'tag' : 'branch'} size={12} /> + <Icon className="min-w-[12px] fill-transparent text-icons-9" name={isTag ? 'tag' : 'branch'} size={12} /> )} - <Text className="text-primary/90 w-full" truncate align="left"> + <Text className="w-full text-primary/90" truncate align="left"> {prefix ? `${prefix}: ${name}` : name} </Text> - <Icon className="chevron-down text-tertiary-background ml-0 min-w-[10px]" name="chevron-down" size={10} /> + <Icon className="chevron-down ml-0 min-w-[10px] text-tertiary-background" name="chevron-down" size={10} /> </Button> </DropdownMenuTrigger> <BranchSelectorDropdown branchList={branchList} tagList={tagList} name={name} selectBranch={selectBranch} /> diff --git a/packages/playground/src/components/branches-list.tsx b/packages/playground/src/components/branches-list.tsx index 0690ad798..f797b3d57 100644 --- a/packages/playground/src/components/branches-list.tsx +++ b/packages/playground/src/components/branches-list.tsx @@ -64,7 +64,7 @@ export const BranchesList = ({ branches, spaceId, repoId, defaultBranch }: PageP <Icon name="vertical-ellipsis" size={14} className="text-tertiary-background" /> </Button> </DropdownMenuTrigger> - <DropdownMenuContent className="bg-primary-background w-[180px] rounded-[10px] border border-gray-800 py-2 shadow-sm"> + <DropdownMenuContent className="w-[180px] rounded-[10px] border border-gray-800 bg-primary-background py-2 shadow-sm"> <DropdownMenuGroup> <Link replace @@ -163,7 +163,7 @@ export const BranchesList = ({ branches, spaceId, repoId, defaultBranch }: PageP <Badge variant="outline" size="xs" - className="text-tertiary-background m-auto h-5 rounded-full p-2 text-center text-xs font-normal" + className="m-auto h-5 rounded-full p-2 text-center text-xs font-normal text-tertiary-background" > Default </Badge> @@ -177,7 +177,7 @@ export const BranchesList = ({ branches, spaceId, repoId, defaultBranch }: PageP <TableCell className="content-center"> <div className="flex items-center justify-center gap-1.5"> {/* <Icon name="open-pr" size={11} className="text-success" /> */} - <Text wrap="nowrap" size={1} truncate className="text-tertiary-background font-mono"> + <Text wrap="nowrap" size={1} truncate className="font-mono text-tertiary-background"> <CommitCopyActions sha={branch.sha} /> </Text> </div> diff --git a/packages/playground/src/components/contact-card.tsx b/packages/playground/src/components/contact-card.tsx index a1d86fa74..a7a452255 100644 --- a/packages/playground/src/components/contact-card.tsx +++ b/packages/playground/src/components/contact-card.tsx @@ -21,8 +21,8 @@ export const ContactCard: React.FC<ContactCardProps> = ({ imgSrc, fallback, auth </Avatar> {initials && ( <div className="flex flex-col"> - {authorName && <Text className="text-primary text-sm">{authorName}</Text>} - {authorEmail && <Text className="text-user text-xs leading-3">{authorEmail}</Text>} + {authorName && <Text className="text-sm text-primary">{authorName}</Text>} + {authorEmail && <Text className="text-xs leading-3 text-user">{authorEmail}</Text>} </div> )} </Layout.Horizontal> diff --git a/packages/playground/src/components/create-branch-dialog.tsx b/packages/playground/src/components/create-branch-dialog.tsx index 77d8f0b64..4739252e1 100644 --- a/packages/playground/src/components/create-branch-dialog.tsx +++ b/packages/playground/src/components/create-branch-dialog.tsx @@ -67,7 +67,7 @@ export function CreateBranchDialog({ return ( <Dialog open={open} onOpenChange={onClose}> - <DialogContent className="border-border bg-primary-background max-w-[500px]"> + <DialogContent className="max-w-[500px] border-border bg-primary-background"> <DialogHeader> <DialogTitle>Create Branch</DialogTitle> </DialogHeader> diff --git a/packages/playground/src/components/create-pipeline-page.tsx b/packages/playground/src/components/create-pipeline-page.tsx index 462caeb66..c9d82eaca 100644 --- a/packages/playground/src/components/create-pipeline-page.tsx +++ b/packages/playground/src/components/create-pipeline-page.tsx @@ -106,7 +106,7 @@ const ResourceSection = ({ title, items }: ResourceSectionData) => ( </Text> </ResourceBox.HeaderTitle> <ResourceBox.HeaderLink> - <Button variant="ghost" size="sm_icon" asChild className="bg-primary/5 rounded-full"> + <Button variant="ghost" size="sm_icon" asChild className="rounded-full bg-primary/5"> <Link to="/#"> <Icon name="circle-arrow-top-right" size={12} className="text-tertiary-background" /> </Link> @@ -193,7 +193,7 @@ export function CreatePipelinePage({ onClickStartFromScratch = noop }: CreatePip Create your pipeline </Text> <Spacer size={3} /> - <Text as="p" size={2} weight="normal" className="text-primary/80 max-w-[50%]"> + <Text as="p" size={2} weight="normal" className="max-w-[50%] text-primary/80"> It's very simple to start using Playground. Allow our AI to create your pipeline based on the code base or start from a clean state. </Text> diff --git a/packages/playground/src/components/divergence-gauge.tsx b/packages/playground/src/components/divergence-gauge.tsx index 2ac2cf607..2dadd1b72 100644 --- a/packages/playground/src/components/divergence-gauge.tsx +++ b/packages/playground/src/components/divergence-gauge.tsx @@ -20,7 +20,7 @@ export const DivergenceGauge = ({ behindAhead, className }: GaugeProps) => { <Text as="p" size={1} truncate color="tertiaryBackground" className="leading-none"> {behindAhead.behind ?? 0} </Text> - <div className="border-tertiary-background/30 h-full border-r" /> + <div className="h-full border-r border-tertiary-background/30" /> <Text as="p" size={1} truncate color="tertiaryBackground" className="place-self-start leading-none"> {behindAhead.ahead ?? 0} </Text> diff --git a/packages/playground/src/components/execution-list.tsx b/packages/playground/src/components/execution-list.tsx index 9290fc8d8..070649253 100644 --- a/packages/playground/src/components/execution-list.tsx +++ b/packages/playground/src/components/execution-list.tsx @@ -39,7 +39,7 @@ const Description = ({ sha, description, version }: { sha: string; description: </div> )} {sha && ( - <div className="bg-tertiary-background/10 flex items-center gap-1 rounded-md px-1.5 font-mono"> + <div className="flex items-center gap-1 rounded-md bg-tertiary-background/10 px-1.5 font-mono"> <Icon size={11} name={'tube-sign'} /> {sha} </div> diff --git a/packages/playground/src/components/execution/console-logs.tsx b/packages/playground/src/components/execution/console-logs.tsx index dd1a739ef..672f3d0a7 100644 --- a/packages/playground/src/components/execution/console-logs.tsx +++ b/packages/playground/src/components/execution/console-logs.tsx @@ -43,14 +43,14 @@ const ConsoleLogs: FC<ConsoleLogsProps> = ({ logs, query }) => { (log: string) => { const match = log.match(new RegExp(query || '')) if (!match || !query?.length) { - return <Text className="text-ring ml-2 flex gap-1 font-mono text-sm font-normal">{log}</Text> + return <Text className="ml-2 flex gap-1 font-mono text-sm font-normal text-ring">{log}</Text> } const matchIndex = match?.index || 0 const startText = log.slice(0, matchIndex) const matchedText = log.slice(matchIndex, matchIndex + query?.length) const endText = log.slice(matchIndex + query?.length) return ( - <Text className="text-ring ml-2 flex gap-1 font-mono text-sm font-normal"> + <Text className="ml-2 flex gap-1 font-mono text-sm font-normal text-ring"> {startText ? <span>{startText}</span> : null} {matchedText ? <mark>{matchedText}</mark> : null} {endText ? <span>{endText}</span> : null} @@ -68,11 +68,11 @@ const ConsoleLogs: FC<ConsoleLogsProps> = ({ logs, query }) => { <div className="mb-2 flex items-baseline justify-between leading-[21px]" key={index}> <div className="flex items-baseline"> {pos !== undefined && !isNaN(pos) && pos >= 0 && ( - <Text className="text-log flex min-w-5 justify-end">{pos + 1}</Text> + <Text className="flex min-w-5 justify-end text-log">{pos + 1}</Text> )} {out && logText(out)} </div> - <Text className="text-log mr-2 flex gap-1 text-sm font-normal"> + <Text className="mr-2 flex gap-1 text-sm font-normal text-log"> {formatDuration(time ? time * 1_000 : 0)} </Text> </div> diff --git a/packages/playground/src/components/execution/execution-details.tsx b/packages/playground/src/components/execution/execution-details.tsx index fdff20f53..43a3a7b5f 100644 --- a/packages/playground/src/components/execution/execution-details.tsx +++ b/packages/playground/src/components/execution/execution-details.tsx @@ -43,24 +43,24 @@ export const ExecutionDetails: React.FC<ExecutionProps> = (): React.ReactElement <div className="my-5 flex flex-col gap-2"> <Text className="text-base text-white">{execution.message}</Text> <div className="flex items-center gap-2"> - <Badge variant="secondary" className="bg-primary-foreground flex gap-1"> + <Badge variant="secondary" className="flex gap-1 bg-primary-foreground"> <Layout.Horizontal gap="space-x-1" className="flex items-center"> <Icon size={12} name={'tube-sign'} /> - <Text className="text-git pb-0.5 text-sm">{execution.source}</Text> + <Text className="pb-0.5 text-sm text-git">{execution.source}</Text> </Layout.Horizontal> </Badge> <span>to</span> - <Badge variant="secondary" className="bg-primary-foreground flex gap-1"> + <Badge variant="secondary" className="flex gap-1 bg-primary-foreground"> <Layout.Horizontal gap="space-x-1" className="flex items-center"> <Icon size={12} name={'git-branch'} /> - <Text className="text-git pb-0.5 text-sm">{execution.target}</Text> + <Text className="pb-0.5 text-sm text-git">{execution.target}</Text> </Layout.Horizontal> </Badge> </div> </div> <Layout.Horizontal> <Layout.Vertical gap="space-y-1"> - <Text className="text-muted-foreground text-sm">Status</Text> + <Text className="text-sm text-muted-foreground">Status</Text> <ExecutionStatus.Badge status={execution.status as ExecutionState} minimal @@ -68,7 +68,7 @@ export const ExecutionDetails: React.FC<ExecutionProps> = (): React.ReactElement /> </Layout.Vertical> <Layout.Vertical gap="space-y-1"> - <Text className="text-muted-foreground text-sm">Created</Text> + <Text className="text-sm text-muted-foreground">Created</Text> <span className="text-white">{moment(execution.created).fromNow()}</span> </Layout.Vertical> </Layout.Horizontal> diff --git a/packages/playground/src/components/execution/execution-status.tsx b/packages/playground/src/components/execution/execution-status.tsx index 686bad143..e3099450d 100644 --- a/packages/playground/src/components/execution/execution-status.tsx +++ b/packages/playground/src/components/execution/execution-status.tsx @@ -19,11 +19,11 @@ const Badge: React.FC<ExecutionStatusProps & BadgeProps> = props => { case ExecutionState.PENDING: return minimal ? ( <div className="flex items-center gap-1"> - <div className="bg-muted size-2 rounded-full" /> + <div className="size-2 rounded-full bg-muted" /> <span className="text-muted">Pending</span> </div> ) : ( - <div className="border-muted bg-muted/[0.1] flex items-center gap-1 rounded-md border border-solid px-1 py-0.5"> + <div className="flex items-center gap-1 rounded-md border border-solid border-muted bg-muted/[0.1] px-1 py-0.5"> <div className="flex items-center gap-0.5"> <CanaryIcon size={12} name="pending-clock" /> <span className="text-muted">Pending</span> @@ -34,13 +34,13 @@ const Badge: React.FC<ExecutionStatusProps & BadgeProps> = props => { case ExecutionState.RUNNING: return minimal ? ( <div className="flex items-center gap-1"> - <div className="bg-studio-3 size-2 rounded-full" /> + <div className="size-2 rounded-full bg-studio-3" /> <span className="text-studio-3">Running</span> </div> ) : ( - <div className="border-studio-3/[0.12] bg-studio-3/10 flex items-center gap-1 rounded-md border border-solid px-1 py-0.5"> + <div className="flex items-center gap-1 rounded-md border border-solid border-studio-3/[0.12] bg-studio-3/10 px-1 py-0.5"> <div className="flex items-center gap-1"> - <CanaryIcon size={16} name="running" className="text-warning animate-spin" /> + <CanaryIcon size={16} name="running" className="animate-spin text-warning" /> <span className="text-studio-3">Running</span> </div> {duration && <span className="text-studio-3">{duration}</span>} @@ -66,11 +66,11 @@ const Badge: React.FC<ExecutionStatusProps & BadgeProps> = props => { case ExecutionState.SUCCESS: return minimal ? ( <div className="flex items-center gap-1"> - <div className="bg-success size-2 rounded-full" /> + <div className="size-2 rounded-full bg-success" /> <span className="text-success">Success</span> </div> ) : ( - <div className="border-success bg-success/[0.1] flex items-center gap-1 rounded-md border border-solid px-1 py-0.5"> + <div className="flex items-center gap-1 rounded-md border border-solid border-success bg-success/[0.1] px-1 py-0.5"> <div className="flex items-center gap-0.5"> <CanaryIcon size={12} name="success" /> <span className="text-success">Success</span> @@ -97,7 +97,7 @@ const Icon: React.FC<ExecutionStatusProps> = props => { case ExecutionState.SUCCESS: return <CanaryIcon size={16} name="success" /> case ExecutionState.RUNNING: - return <CanaryIcon size={20} name="running" className="text-warning animate-spin" /> + return <CanaryIcon size={20} name="running" className="animate-spin text-warning" /> case ExecutionState.SKIPPED: default: return <></> diff --git a/packages/playground/src/components/execution/key-value-table.tsx b/packages/playground/src/components/execution/key-value-table.tsx index 0354b62bf..1012e98fb 100644 --- a/packages/playground/src/components/execution/key-value-table.tsx +++ b/packages/playground/src/components/execution/key-value-table.tsx @@ -42,12 +42,12 @@ export const KeyValueTable: React.FC<KeyValueTableProps> = ({ if (typeof item.value === 'string') { return ( <ul className="flex flex-row border-b align-middle" key={index}> - <li className="text-studio-7 w-1/2 py-2.5 pr-2.5" style={{ paddingLeft: `${level + 1}rem` }}> + <li className="w-1/2 py-2.5 pr-2.5 text-studio-7" style={{ paddingLeft: `${level + 1}rem` }}> <Text size={2} weight="normal"> {item.name} </Text> </li> - <li className="text-studio-7 w-1/2 py-2.5 pl-1.5 pr-2.5"> + <li className="w-1/2 py-2.5 pl-1.5 pr-2.5 text-studio-7"> <Text size={2} weight="normal"> {item.value} </Text> diff --git a/packages/playground/src/components/execution/stage-execution.tsx b/packages/playground/src/components/execution/stage-execution.tsx index 0a72c25a2..4fa3acc2f 100644 --- a/packages/playground/src/components/execution/stage-execution.tsx +++ b/packages/playground/src/components/execution/stage-execution.tsx @@ -126,9 +126,9 @@ export const StageExecution: React.FC<StageExecutionProps> = ({ <Layout.Vertical gap="space-y-2" className="grow p-4"> {stage?.group ? ( <Layout.Horizontal gap="space-x-1" className="flex items-center"> - <Text className="text-stage text-sm">{stage.group}</Text> + <Text className="text-sm text-stage">{stage.group}</Text> <Icon name="x-mark" /> - <Text className="text-ring text-sm">{stage.name}</Text> + <Text className="text-sm text-ring">{stage.name}</Text> </Layout.Horizontal> ) : ( <Text>{stage.name}</Text> diff --git a/packages/playground/src/components/file-explorer.tsx b/packages/playground/src/components/file-explorer.tsx index bd41a0c25..99706d99c 100644 --- a/packages/playground/src/components/file-explorer.tsx +++ b/packages/playground/src/components/file-explorer.tsx @@ -27,9 +27,9 @@ function FolderItem({ children, key, value, isActive, content, chevronClass, lin })} > <div className="flex w-full items-center gap-2 py-1"> - <Icon name="folder" size={12} className="group-hover:text-primary min-w-[12px] duration-100 ease-in-out" /> + <Icon name="folder" size={12} className="min-w-[12px] duration-100 ease-in-out group-hover:text-primary" /> <Link to={link}> - <Text as="p" size={2} className="group-hover:text-primary truncate text-inherit duration-100 ease-in-out"> + <Text as="p" size={2} className="truncate text-inherit duration-100 ease-in-out group-hover:text-primary"> {children} </Text> </Link> @@ -56,8 +56,8 @@ function FileItem({ children, key, isActive }: ItemProps) { } )} > - <Icon name="file" size={12} className="group-hover:text-primary min-w-[12px] duration-100 ease-in-out" /> - <Text size={2} className="group-hover:text-primary truncate text-inherit duration-100 ease-in-out"> + <Icon name="file" size={12} className="min-w-[12px] duration-100 ease-in-out group-hover:text-primary" /> + <Text size={2} className="truncate text-inherit duration-100 ease-in-out group-hover:text-primary"> {children} </Text> </div> diff --git a/packages/playground/src/components/filters/filter-trigger.tsx b/packages/playground/src/components/filters/filter-trigger.tsx index 058cdbfaf..b793ace33 100644 --- a/packages/playground/src/components/filters/filter-trigger.tsx +++ b/packages/playground/src/components/filters/filter-trigger.tsx @@ -1,6 +1,3 @@ -import { FilterOption, SortOption } from './types' -import { UseFiltersReturn } from './use-filters' - import { DropdownMenu, DropdownMenuContent, @@ -10,6 +7,9 @@ import { Input } from '@harnessio/canary' +import { FilterOption, SortOption } from './types' +import { UseFiltersReturn } from './use-filters' + interface BaseFilterTriggerProps { type: 'filter' | 'sort' options: FilterOption[] | SortOption[] @@ -103,10 +103,10 @@ const FilterTrigger = ({ return ( <DropdownMenu> <DropdownMenuTrigger className="flex items-center gap-x-1.5"> - <span className="text-foreground-2 hover:text-foreground-1 text-14 flex items-center gap-x-1"> + <span className="flex items-center gap-x-1 text-14 text-foreground-2 hover:text-foreground-1"> {displayLabel} {!hideCount && activeFilters.length > 0 && ( - <span className="text-foreground-2 bg-background-2 text-11 border-borders-5 flex h-[18px] min-w-[17px] items-center justify-center rounded border px-1"> + <span className="flex h-[18px] min-w-[17px] items-center justify-center rounded border border-borders-5 bg-background-2 px-1 text-11 text-foreground-2"> {activeFilters.length} </span> )} @@ -114,7 +114,7 @@ const FilterTrigger = ({ {!customLabel && <Icon className="chevron-down text-icons-4" name="chevron-fill-down" size={6} />} </DropdownMenuTrigger> <DropdownMenuContent className="min-w-[224px] p-0" align={dropdownAlign}> - <div className="border-borders-4 relative flex items-center justify-between border-b px-3 py-2.5"> + <div className="relative flex items-center justify-between border-b border-borders-4 px-3 py-2.5"> <Input type="text" placeholder={inputPlaceholder} @@ -127,11 +127,12 @@ const FilterTrigger = ({ {searchQueries.menu[type] && ( <div className="absolute right-3"> <button - className="text-foreground-4 hover:text-foreground-1 flex p-1.5 transition-colors duration-200" + className="flex p-1.5 text-foreground-4 transition-colors duration-200 hover:text-foreground-1" onClick={e => { e.preventDefault() onSearchChange(type, '', 'menu') - }}> + }} + > <Icon className="rotate-45" name="plus" size={12} /> </button> </div> @@ -147,13 +148,13 @@ const FilterTrigger = ({ {filteredBySearchOptions.length === 0 && ( <div className="flex items-center justify-center p-4"> - <span className="text-foreground-2 text-14 leading-none">No results</span> + <span className="text-14 leading-none text-foreground-2">No results</span> </div> )} </div> {onReset && ( - <div className="border-borders-4 border-t p-1"> + <div className="border-t border-borders-4 p-1"> <DropdownMenuItem asChild> <button className="w-full font-medium" onClick={onReset}> {buttonLabel} diff --git a/packages/playground/src/components/filters/filters-bar/filter-variants/calendar.tsx b/packages/playground/src/components/filters/filters-bar/filter-variants/calendar.tsx index e16d7e24f..df0f65a75 100644 --- a/packages/playground/src/components/filters/filters-bar/filter-variants/calendar.tsx +++ b/packages/playground/src/components/filters/filters-bar/filter-variants/calendar.tsx @@ -1,5 +1,7 @@ import { useState } from 'react' -import { cn, Calendar as UICalendar, type CalendarDateRange, Input } from '@harnessio/canary' + +import { cn, Input, Calendar as UICalendar, type CalendarDateRange } from '@harnessio/canary' + import { FilterValue } from '../../types' import { UseFiltersReturn } from '../../use-filters' diff --git a/packages/playground/src/components/filters/filters-bar/filter-variants/checkbox.tsx b/packages/playground/src/components/filters/filters-bar/filter-variants/checkbox.tsx index 9e28d63a8..524a35cac 100644 --- a/packages/playground/src/components/filters/filters-bar/filter-variants/checkbox.tsx +++ b/packages/playground/src/components/filters/filters-bar/filter-variants/checkbox.tsx @@ -1,4 +1,5 @@ import { cn, DropdownMenuCheckboxItem, DropdownMenuItem, Icon, Input } from '@harnessio/canary' + import { CheckboxFilterOption, FilterValue } from '../../types' import { UseFiltersReturn } from '../../use-filters' import { getFilteredOptions } from '../../utils' @@ -17,27 +18,29 @@ const Checkbox = ({ filter, filterOption, onUpdateFilter, searchQueries, handleS return ( <> {filter.condition !== 'is_empty' && ( - <div className="border-borders-1 border-b px-3 pb-2.5"> + <div className="border-b border-borders-1 px-3 pb-2.5"> <div className={cn( 'border-border-2 focus-within:border-borders-3 flex min-h-8 justify-between gap-x-1 rounded border px-2.5 py-[3px] outline-none transition-colors duration-200 focus-within:border', { 'px-1': !!filter.selectedValues.length } - )}> + )} + > <div className="flex flex-1 flex-wrap items-center gap-1"> {!!filter.selectedValues.length && filter.selectedValues.map(value => { const label = filterOption.options?.find(opt => opt.value === value)?.label return ( - <div className="bg-background-8 flex h-6 items-center gap-x-1.5 rounded px-2" key={value}> + <div className="flex h-6 items-center gap-x-1.5 rounded bg-background-8 px-2" key={value}> <span className="text-14 text-foreground-8">{label}</span> <button - className="text-icons-1 hover:text-foreground-1 transition-colors duration-200" + className="text-icons-1 transition-colors duration-200 hover:text-foreground-1" onClick={() => { const newValues = filter.selectedValues.filter(v => v !== value) onUpdateFilter(filter.type, newValues) - }}> + }} + > <Icon className="rotate-45" name="plus" size={10} /> </button> </div> @@ -60,11 +63,12 @@ const Checkbox = ({ filter, filterOption, onUpdateFilter, searchQueries, handleS </div> {(!!filter.selectedValues.length || searchQueries.filters[filter.type]) && ( <button - className="text-foreground-4 hover:text-foreground-1 flex p-1.5 transition-colors duration-200" + className="flex p-1.5 text-foreground-4 transition-colors duration-200 hover:text-foreground-1" onClick={() => { onUpdateFilter(filter.type, []) handleSearchChange?.(filter.type, '', 'filters') - }}> + }} + > <Icon className="rotate-45" name="plus" size={12} /> </button> )} @@ -86,7 +90,8 @@ const Checkbox = ({ filter, filterOption, onUpdateFilter, searchQueries, handleS : [...filter.selectedValues, option.value] onUpdateFilter(filter.type, newValues) }} - key={option.value}> + key={option.value} + > {option.label} </DropdownMenuCheckboxItem> ))} diff --git a/packages/playground/src/components/filters/filters-bar/filter-variants/number.tsx b/packages/playground/src/components/filters/filters-bar/filter-variants/number.tsx index d980f3e09..7c60b40e7 100644 --- a/packages/playground/src/components/filters/filters-bar/filter-variants/number.tsx +++ b/packages/playground/src/components/filters/filters-bar/filter-variants/number.tsx @@ -1,5 +1,7 @@ import { useState } from 'react' -import { Input, Icon, DropdownMenuItem } from '@harnessio/canary' + +import { DropdownMenuItem, Icon, Input } from '@harnessio/canary' + import { FilterValue } from '../../types' import { UseFiltersReturn } from '../../use-filters' @@ -59,11 +61,12 @@ const Number = ({ filter, onUpdateFilter }: NumberFilterProps) => { {value && ( <button - className="text-icons-1 hover:text-foreground-1 absolute right-3 transition-colors duration-200" + className="absolute right-3 text-icons-1 transition-colors duration-200 hover:text-foreground-1" onClick={e => { e.stopPropagation() handleClear() - }}> + }} + > <Icon className="rotate-45" name="plus" size={10} /> </button> )} diff --git a/packages/playground/src/components/filters/filters-bar/filter-variants/text.tsx b/packages/playground/src/components/filters/filters-bar/filter-variants/text.tsx index e7a503299..48f4c72ef 100644 --- a/packages/playground/src/components/filters/filters-bar/filter-variants/text.tsx +++ b/packages/playground/src/components/filters/filters-bar/filter-variants/text.tsx @@ -1,5 +1,7 @@ import { useState } from 'react' + import { DropdownMenuItem, Icon, Input } from '@harnessio/canary' + import { FilterValue } from '../../types' import { UseFiltersReturn } from '../../use-filters' @@ -53,11 +55,12 @@ const Text = ({ filter, onUpdateFilter }: TextFilterProps) => { {value && ( <button - className="text-icons-1 hover:text-foreground-1 absolute right-3 transition-colors duration-200" + className="absolute right-3 text-icons-1 transition-colors duration-200 hover:text-foreground-1" onClick={e => { e.stopPropagation() handleClear() - }}> + }} + > <Icon className="rotate-45" name="plus" size={10} /> </button> )} diff --git a/packages/playground/src/components/filters/filters-bar/filters-bar.tsx b/packages/playground/src/components/filters/filters-bar/filters-bar.tsx index fe320cd3d..0f1a67ae8 100644 --- a/packages/playground/src/components/filters/filters-bar/filters-bar.tsx +++ b/packages/playground/src/components/filters/filters-bar/filters-bar.tsx @@ -1,9 +1,10 @@ import { Icon } from '@harnessio/canary' -import { FilterOption, SortOption, SortDirection } from '../types' + +import FilterTrigger from '../filter-trigger' +import { FilterOption, SortDirection, SortOption } from '../types' import { UseFiltersReturn } from '../use-filters' -import Sorts from './sorts' import Filters from './filters' -import FilterTrigger from '../filter-trigger' +import Sorts from './sorts' interface FiltersBarProps { filterOptions: FilterOption[] @@ -80,7 +81,7 @@ const FiltersBar = ({ /> )} - {activeFilters.length > 0 && activeSorts.length > 0 && <div className="bg-borders-1 h-7 w-px" />} + {activeFilters.length > 0 && activeSorts.length > 0 && <div className="h-7 w-px bg-borders-1" />} {activeFilters.map(filter => ( <Filters @@ -103,7 +104,7 @@ const FiltersBar = ({ <FilterTrigger type="filter" customLabel={ - <div className="text-foreground-4 hover:text-foreground-1 flex items-center gap-x-1.5 transition-colors duration-200"> + <div className="flex items-center gap-x-1.5 text-foreground-4 transition-colors duration-200 hover:text-foreground-1"> <Icon name="plus" size={10} /> <span>Add filter</span> </div> @@ -117,11 +118,12 @@ const FiltersBar = ({ options={filterOptions} /> <button - className="text-14 text-foreground-4 hover:text-foreground-danger ring-offset-background flex items-center gap-x-1.5 outline-none ring-offset-2 transition-colors duration-200 focus:ring-2" + className="flex items-center gap-x-1.5 text-14 text-foreground-4 outline-none ring-offset-2 ring-offset-background transition-colors duration-200 hover:text-foreground-danger focus:ring-2" onClick={() => { handleResetAll() handleClearSavedFilters() - }}> + }} + > <Icon className="rotate-45" name="plus" size={12} /> Reset </button> @@ -129,8 +131,9 @@ const FiltersBar = ({ {hasUnsavedChanges && ( <button - className="text-14 text-foreground-4 hover:text-foreground-1 flex items-center gap-x-1.5" - onClick={handleSaveFilters}> + className="flex items-center gap-x-1.5 text-14 text-foreground-4 hover:text-foreground-1" + onClick={handleSaveFilters} + > Save </button> )} diff --git a/packages/playground/src/components/filters/filters-bar/filters.tsx b/packages/playground/src/components/filters/filters-bar/filters.tsx index 7385758aa..8ea3bd7ca 100644 --- a/packages/playground/src/components/filters/filters-bar/filters.tsx +++ b/packages/playground/src/components/filters/filters-bar/filters.tsx @@ -1,14 +1,14 @@ -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, Icon, cn, DropdownMenuTrigger } from '@harnessio/canary' +import { useEffect, useState } from 'react' -import type { FilterValue, FilterOption, FilterSearchQueries, CheckboxFilterOption, FilterAction } from '../types' +import { cn, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Icon } from '@harnessio/canary' +import type { CheckboxFilterOption, FilterAction, FilterOption, FilterSearchQueries, FilterValue } from '../types' +import { UseFiltersReturn } from '../use-filters' +import { getFilterDisplayValue, getFilteredOptions } from '../utils' import Calendar from './filter-variants/calendar' import Checkbox from './filter-variants/checkbox' -import Text from './filter-variants/text' import Number from './filter-variants/number' -import { getFilterDisplayValue, getFilteredOptions } from '../utils' -import { useEffect, useState } from 'react' -import { UseFiltersReturn } from '../use-filters' +import Text from './filter-variants/text' const renderFilterValues = ( filter: FilterValue, @@ -82,8 +82,8 @@ const Filters = ({ return ( <DropdownMenu key={filter.type} open={isOpen} onOpenChange={setIsOpen}> - <DropdownMenuTrigger className="bg-background-3 hover:bg-background-8 flex h-8 items-center gap-x-3 whitespace-nowrap rounded pl-2.5 pr-2 transition-colors duration-200"> - <div className="text-13 flex items-center gap-x-1.5"> + <DropdownMenuTrigger className="flex h-8 items-center gap-x-3 whitespace-nowrap rounded bg-background-3 pl-2.5 pr-2 transition-colors duration-200 hover:bg-background-8"> + <div className="flex items-center gap-x-1.5 text-13"> <span className="text-foreground-1"> {filterOption.label} {!!filter.selectedValues.length && ': '} @@ -97,14 +97,15 @@ const Filters = ({ className={cn('w-[276px] p-0', { 'w-max': filterOption.type === 'calendar' })} - align="start"> + align="start" + > <div className="flex items-center justify-between px-3 py-2.5"> <div className="flex w-full items-center justify-between gap-x-2"> <div className="flex items-center gap-x-2"> - <span className="text-foreground-4 text-14">{filterOption.label}</span> + <span className="text-14 text-foreground-4">{filterOption.label}</span> <DropdownMenu> - <DropdownMenuTrigger className="bg-background-3 text-foreground-2 text-14 flex h-[18px] items-center gap-x-1 rounded pl-1.5 pr-1"> + <DropdownMenuTrigger className="flex h-[18px] items-center gap-x-1 rounded bg-background-3 pl-1.5 pr-1 text-14 text-foreground-2"> {filterOption.conditions?.find(c => c.value === filter.condition)?.label} <Icon className="chevron-down text-icons-1" name="chevron-down" size={10} /> </DropdownMenuTrigger> @@ -112,7 +113,8 @@ const Filters = ({ {filterOption.conditions?.map(condition => ( <DropdownMenuItem onSelect={() => handleUpdateCondition?.(filter.type, condition.value)} - key={condition.value}> + key={condition.value} + > {condition.label} </DropdownMenuItem> ))} @@ -123,16 +125,17 @@ const Filters = ({ <DropdownMenu> <DropdownMenuTrigger className="group flex h-[18px] items-center px-1"> <Icon - className="text-icons-1 group-hover:text-foreground-1 transition-colors duration-200" + className="text-icons-1 transition-colors duration-200 group-hover:text-foreground-1" name="more-dots-fill" size={12} /> </DropdownMenuTrigger> <DropdownMenuContent align="start"> <DropdownMenuItem - className="focus:text-foreground-danger focus:bg-transparent focus:outline-none" - onSelect={() => handleRemoveFilter?.(filter.type)}> - <button className="text-14 text-foreground-4 hover:text-foreground-danger flex items-center gap-x-1.5 transition-colors duration-200"> + className="focus:bg-transparent focus:text-foreground-danger focus:outline-none" + onSelect={() => handleRemoveFilter?.(filter.type)} + > + <button className="flex items-center gap-x-1.5 text-14 text-foreground-4 transition-colors duration-200 hover:text-foreground-danger"> <Icon name="trash" size={12} /> Delete filter </button> @@ -148,7 +151,7 @@ const Filters = ({ {filterOption.type === 'checkbox' && getFilteredOptions(filterOption, filter, searchQueries).length === 0 && ( <div className="flex items-center justify-center p-4"> - <span className="text-foreground-2 text-1 leading-none">No results</span> + <span className="text-1 leading-none text-foreground-2">No results</span> </div> )} </div> diff --git a/packages/playground/src/components/filters/filters-bar/sorts.tsx b/packages/playground/src/components/filters/filters-bar/sorts.tsx index 671f28746..0aa6bd1e1 100644 --- a/packages/playground/src/components/filters/filters-bar/sorts.tsx +++ b/packages/playground/src/components/filters/filters-bar/sorts.tsx @@ -1,23 +1,23 @@ +import { useEffect, useState } from 'react' + +import { closestCenter, DndContext } from '@dnd-kit/core' +import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' + import { + cn, DropdownMenu, DropdownMenuContent, DropdownMenuItem, - Input, + DropdownMenuTrigger, Icon, - cn, - DropdownMenuTrigger + Input } from '@harnessio/canary' -import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable' -import { CSS } from '@dnd-kit/utilities' -import type { SortDirection, FilterSearchQueries, SortOption, SortValue, FilterAction } from '../types' - import useDragAndDrop from '../../../hooks/use-drag-and-drop' -import { DndContext, closestCenter } from '@dnd-kit/core' - -import { getSortTriggerLabel } from '../utils' -import { useState, useEffect } from 'react' +import type { FilterAction, FilterSearchQueries, SortDirection, SortOption, SortValue } from '../types' import { UseFiltersReturn } from '../use-filters' +import { getSortTriggerLabel } from '../utils' interface SortableItemProps { id: string @@ -53,14 +53,15 @@ const SortableItem = ({ <div className="flex items-center justify-between gap-x-2"> <div className="flex items-center gap-x-2"> <div - className="hover:bg-background-3 cursor-grab rounded p-1 active:cursor-grabbing" + className="cursor-grab rounded p-1 hover:bg-background-3 active:cursor-grabbing" {...attributes} - {...listeners}> + {...listeners} + > <Icon className="text-icons-1" name="grid-dots" size={12} /> </div> <DropdownMenu> - <DropdownMenuTrigger className="border-borders-1 text-foreground-8 text-14 flex h-6 items-center gap-x-1.5 rounded border pl-2.5 pr-1.5"> + <DropdownMenuTrigger className="flex h-6 items-center gap-x-1.5 rounded border border-borders-1 pl-2.5 pr-1.5 text-14 text-foreground-8"> {sortOptions.find(opt => opt.value === sort.type)?.label} <Icon className="chevron-down text-icons-1" name="chevron-down" size={10} /> </DropdownMenuTrigger> @@ -68,7 +69,8 @@ const SortableItem = ({ {sortOptions.map(option => ( <DropdownMenuItem onSelect={() => onUpdateSort?.(index, { ...sort, type: option.value })} - key={option.value}> + key={option.value} + > {option.label} </DropdownMenuItem> ))} @@ -76,7 +78,7 @@ const SortableItem = ({ </DropdownMenu> <DropdownMenu> - <DropdownMenuTrigger className="border-borders-1 text-foreground-8 text-14 flex h-6 items-center gap-x-1.5 rounded border pl-2.5 pr-1.5"> + <DropdownMenuTrigger className="flex h-6 items-center gap-x-1.5 rounded border border-borders-1 pl-2.5 pr-1.5 text-14 text-foreground-8"> {sortDirections.find(dir => dir.value === sort.direction)?.label} <Icon className="chevron-down text-icons-1" name="chevron-down" size={10} /> </DropdownMenuTrigger> @@ -84,7 +86,8 @@ const SortableItem = ({ {sortDirections.map(direction => ( <DropdownMenuItem onSelect={() => onUpdateSort?.(index, { ...sort, direction: direction.value })} - key={direction.value}> + key={direction.value} + > {direction.label} </DropdownMenuItem> ))} @@ -94,11 +97,12 @@ const SortableItem = ({ <DropdownMenuItem className="p-0" asChild> <button - className="text-foreground-4 hover:text-foreground-1 p-1 transition-colors duration-200 focus:bg-transparent" + className="p-1 text-foreground-4 transition-colors duration-200 hover:text-foreground-1 focus:bg-transparent" onClick={e => { e.preventDefault() onRemoveSort?.(index) - }}> + }} + > <Icon className="rotate-45" name="plus" size={12} /> </button> </DropdownMenuItem> @@ -156,7 +160,7 @@ const Sorts = ({ return ( <DropdownMenu open={isOpen} onOpenChange={setIsOpen}> - <DropdownMenuTrigger className="bg-background-3 hover:bg-background-8 flex h-8 items-center gap-x-3 whitespace-nowrap rounded px-2.5 transition-colors duration-200"> + <DropdownMenuTrigger className="flex h-8 items-center gap-x-3 whitespace-nowrap rounded bg-background-3 px-2.5 transition-colors duration-200 hover:bg-background-8"> <div className="flex items-center gap-x-1"> <Icon className={cn('text-icons-1', getSortTriggerLabel(activeSorts, sortOptions).isDescending && 'rotate-180')} @@ -172,7 +176,8 @@ const Sorts = ({ <DndContext onDragEnd={handleDragEnd} collisionDetection={closestCenter}> <SortableContext items={activeSorts.map((_, index) => getItemId(index))} - strategy={verticalListSortingStrategy}> + strategy={verticalListSortingStrategy} + > <div className="flex flex-col gap-y-2.5"> {activeSorts.map((sort, index) => ( <SortableItem @@ -193,12 +198,12 @@ const Sorts = ({ <div className="mt-3 flex flex-col gap-y-2.5"> {sortOptions.some(option => !activeSorts.some(sort => sort.type === option.value)) && ( <DropdownMenu> - <DropdownMenuTrigger className="text-14 text-foreground-4 hover:text-foreground-1 flex w-full items-center gap-x-1.5 transition-colors duration-200"> + <DropdownMenuTrigger className="flex w-full items-center gap-x-1.5 text-14 text-foreground-4 transition-colors duration-200 hover:text-foreground-1"> <Icon name="plus" size={12} /> Add sort </DropdownMenuTrigger> <DropdownMenuContent className="min-w-[224px] p-0" align="start"> - <div className="border-borders-4 relative flex items-center justify-between border-b px-3 py-2.5"> + <div className="relative flex items-center justify-between border-b border-borders-4 px-3 py-2.5"> <DropdownMenuItem className="hover:bg-transparent focus:bg-transparent" asChild> <Input type="text" @@ -213,11 +218,12 @@ const Sorts = ({ {searchQueries.menu['sort'] && ( <DropdownMenuItem className="absolute right-3 hover:bg-transparent focus:bg-transparent" asChild> <button - className="text-foreground-4 hover:text-foreground-1 flex transition-colors duration-200" + className="flex text-foreground-4 transition-colors duration-200 hover:text-foreground-1" onClick={e => { e.preventDefault() handleSearchChange('sort', '', 'menu') - }}> + }} + > <Icon className="rotate-45" name="plus" size={12} /> </button> </DropdownMenuItem> @@ -233,14 +239,15 @@ const Sorts = ({ .map(option => ( <DropdownMenuItem onSelect={() => handleSortChange({ type: option.value, direction: 'desc' })} - key={option.value}> + key={option.value} + > {option.label} </DropdownMenuItem> ))} {filteredBySearchSortOptions.length === 0 && ( <div className="flex items-center justify-center p-4"> - <span className="text-foreground-2 text-1 leading-none">No results</span> + <span className="text-1 leading-none text-foreground-2">No results</span> </div> )} </div> @@ -249,11 +256,13 @@ const Sorts = ({ )} <DropdownMenuItem - className="focus:text-foreground-danger p-0 focus:bg-transparent focus:outline-none" - asChild> + className="p-0 focus:bg-transparent focus:text-foreground-danger focus:outline-none" + asChild + > <button - className="text-14 text-foreground-4 hover:text-foreground-danger flex items-center gap-x-1.5 transition-colors duration-200" - onClick={handleResetSorts}> + className="flex items-center gap-x-1.5 text-14 text-foreground-4 transition-colors duration-200 hover:text-foreground-danger" + onClick={handleResetSorts} + > <Icon name="trash" size={12} /> Delete sort </button> diff --git a/packages/playground/src/components/filters/filters.tsx b/packages/playground/src/components/filters/filters.tsx index 2eb25fbe9..1902a4e2c 100644 --- a/packages/playground/src/components/filters/filters.tsx +++ b/packages/playground/src/components/filters/filters.tsx @@ -1,5 +1,5 @@ -import { FilterOption, SortOption } from './types' import FilterTrigger from './filter-trigger' +import { FilterOption, SortOption } from './types' import { UseFiltersReturn } from './use-filters' interface FiltersProps { diff --git a/packages/playground/src/components/filters/index.ts b/packages/playground/src/components/filters/index.ts index 4c243937a..6669f831f 100644 --- a/packages/playground/src/components/filters/index.ts +++ b/packages/playground/src/components/filters/index.ts @@ -1,9 +1,8 @@ import Filters from './filters' import FiltersBar from './filters-bar/filters-bar' +import { FilterCondition, FilterOption, FilterValue, SortDirection, SortOption, SortValue } from './types' import useFilters from './use-filters' -import { FilterCondition, FilterOption, SortDirection, SortOption, FilterValue, SortValue } from './types' - export { Filters, FiltersBar, useFilters } export type { FilterOption, FilterCondition, SortOption, SortDirection, FilterValue, SortValue } diff --git a/packages/playground/src/components/filters/use-filters.tsx b/packages/playground/src/components/filters/use-filters.tsx index 2d318c85a..caeec1687 100644 --- a/packages/playground/src/components/filters/use-filters.tsx +++ b/packages/playground/src/components/filters/use-filters.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from 'react' -import { FilterValue, SortValue, FilterSearchQueries, FilterAction } from './types' +import { FilterAction, FilterSearchQueries, FilterValue, SortValue } from './types' export interface UseFiltersReturn { // State values diff --git a/packages/playground/src/components/filters/utils.ts b/packages/playground/src/components/filters/utils.ts index 330b40a78..c95d9310b 100644 --- a/packages/playground/src/components/filters/utils.ts +++ b/packages/playground/src/components/filters/utils.ts @@ -1,11 +1,12 @@ import { format } from 'date-fns' + import { CheckboxFilterOption, - type FilterValue, - type FilterOption, + FilterSearchQueries, SortOption, SortValue, - FilterSearchQueries + type FilterOption, + type FilterValue } from './types' /** diff --git a/packages/playground/src/components/form-field-set.tsx b/packages/playground/src/components/form-field-set.tsx index 8e3548855..a3d03adb1 100644 --- a/packages/playground/src/components/form-field-set.tsx +++ b/packages/playground/src/components/form-field-set.tsx @@ -109,7 +109,7 @@ function Label({ htmlFor, required, children, className }: LabelProps) { return ( <ShadLabel htmlFor={htmlFor} variant="sm" className={cn('text-primary/80 font-normal', className)}> {children} - {required && <span className="text-destructive pl-0.5 align-top">*</span>} + {required && <span className="pl-0.5 align-top text-destructive">*</span>} </ShadLabel> ) } diff --git a/packages/playground/src/components/form-inputs/GroupInput.tsx b/packages/playground/src/components/form-inputs/GroupInput.tsx index 4e353bd39..661e7fbf3 100644 --- a/packages/playground/src/components/form-inputs/GroupInput.tsx +++ b/packages/playground/src/components/form-inputs/GroupInput.tsx @@ -40,7 +40,7 @@ function GroupInputInternal(props: InputProps<AnyFormikValue>): JSX.Element { <Accordion type="single" collapsible - className="bg-muted/30 w-full px-3" + className="w-full bg-muted/30 px-3" // onValueChange={value => setIsOpen(!!value)} > <AccordionItem value={'group'} className="border-b-0"> diff --git a/packages/playground/src/components/image-carousel.tsx b/packages/playground/src/components/image-carousel.tsx index 51cfdccee..05ee97ccd 100644 --- a/packages/playground/src/components/image-carousel.tsx +++ b/packages/playground/src/components/image-carousel.tsx @@ -32,7 +32,7 @@ const ImageCarousel = (props: ImageCarouselProps) => { setZoomLevel(1) }} > - <DialogContent className="border-border bg-primary-background h-[600px] max-w-[800px]"> + <DialogContent className="h-[600px] max-w-[800px] border-border bg-primary-background"> <DialogHeader> <DialogTitle> {imgTitle ? imgTitle.substring(imgTitle.lastIndexOf('/') + 1, imgTitle.length) : 'image'} diff --git a/packages/playground/src/components/loaders/skeleton-list.tsx b/packages/playground/src/components/loaders/skeleton-list.tsx index 83049c194..595a65033 100644 --- a/packages/playground/src/components/loaders/skeleton-list.tsx +++ b/packages/playground/src/components/loaders/skeleton-list.tsx @@ -54,7 +54,7 @@ export const SkeletonList = ({ className }: SkeletonListProps) => { ))} </StackedList.Root> )} - <div className="to-background absolute bottom-0 z-10 h-1/2 w-full bg-gradient-to-b from-transparent" /> + <div className="absolute bottom-0 z-10 h-1/2 w-full bg-gradient-to-b from-transparent to-background" /> </div> ) } diff --git a/packages/playground/src/components/manage-navigation/draggable-item.tsx b/packages/playground/src/components/manage-navigation/draggable-item.tsx new file mode 100644 index 000000000..98d822bf1 --- /dev/null +++ b/packages/playground/src/components/manage-navigation/draggable-item.tsx @@ -0,0 +1,37 @@ +import { DraggableAttributes } from '@dnd-kit/core' +import { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities' +import { useSortable } from '@dnd-kit/sortable' +import { CSS } from '@dnd-kit/utilities' + +import { cn } from '@harnessio/canary' + +interface DraggableItemProps { + id: string + children: (props: { attributes: DraggableAttributes; listeners: SyntheticListenerMap }) => React.ReactNode + tag: 'button' | 'div' | 'li' + className?: string +} + +export const DraggableItem = ({ id, children, tag: Tag = 'div', className }: DraggableItemProps) => { + const { + attributes, + listeners = {}, + setNodeRef, + transform, + transition, + isDragging + } = useSortable({ + id + }) + + const style = { + transform: CSS.Transform.toString(transform), + transition, + opacity: isDragging ? 0.5 : 1 + } + return ( + <Tag className={cn('relative', isDragging && 'z-10', className)} ref={setNodeRef} style={style}> + {children({ attributes, listeners })} + </Tag> + ) +} diff --git a/packages/playground/src/components/manage-navigation/index.tsx b/packages/playground/src/components/manage-navigation/index.tsx new file mode 100644 index 000000000..219717173 --- /dev/null +++ b/packages/playground/src/components/manage-navigation/index.tsx @@ -0,0 +1,224 @@ +import { useState } from 'react' + +import { closestCenter, DndContext } from '@dnd-kit/core' +import { SortableContext } from '@dnd-kit/sortable' + +import { + AlertDialog, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + Button, + ButtonGroup, + Icon, + ScrollArea, + Text +} from '@harnessio/canary' + +import useDragAndDrop from '../../hooks/use-drag-and-drop' +import { MenuGroupType, NavbarItemType } from '../navbar/types' +import { DraggableItem } from './draggable-item' +import { ManageNavigationSearch } from './manage-navigation-search' + +interface ManageNavigationProps { + pinnedItems: NavbarItemType[] + navbarMenuData: MenuGroupType[] + showManageNavigation: boolean + recentItems: NavbarItemType[] + onSave: (recentItems: NavbarItemType[], currentPinnedItems: NavbarItemType[]) => void + onClose: () => void + isSubmitting: boolean + submitted: boolean +} + +const filterRecentItems = (pinnedItems: NavbarItemType[], recentItems: NavbarItemType[]) => { + return recentItems.filter(item => !pinnedItems.some(pinnedItem => pinnedItem.id === item.id)) +} + +const filterMenuData = (menuData: MenuGroupType[], pinnedItems: NavbarItemType[]): MenuGroupType[] => { + return menuData + .map(group => ({ + ...group, + items: group.items.filter(item => !pinnedItems.some(pinnedItem => pinnedItem.id === item.id)) + })) + .filter(group => group.items.length > 0) +} + +export const ManageNavigation = ({ + pinnedItems, + recentItems, + navbarMenuData, + showManageNavigation, + onSave, + onClose, + isSubmitting, + submitted +}: ManageNavigationProps) => { + const [currentPinnedItems, setCurrentPinnedItems] = useState<NavbarItemType[]>(pinnedItems) + const [currentFilteredRecentItems, setCurrentFilteredRecentItems] = useState<NavbarItemType[]>( + filterRecentItems(pinnedItems, recentItems) + ) + const [isRecentCleared, setIsRecentCleared] = useState(false) + + const { handleDragEnd, getItemId } = useDragAndDrop({ + items: currentPinnedItems, + onReorder: setCurrentPinnedItems + }) + + const handleCancel = () => { + setCurrentPinnedItems(pinnedItems) + setCurrentFilteredRecentItems(filterRecentItems(pinnedItems, recentItems)) + onClose() + } + + const handleClearRecent = () => { + setCurrentFilteredRecentItems([]) + setIsRecentCleared(true) + } + + const onSubmit = () => { + onSave(currentFilteredRecentItems, currentPinnedItems) + onClose() + } + + const updatePinnedItems = (items: NavbarItemType[]) => { + setCurrentPinnedItems(items) + setCurrentFilteredRecentItems(prevRecentItems => { + if (isRecentCleared) { + const unpinnedItems = currentPinnedItems + .filter(item => !items.some(newItem => newItem.id === item.id)) + .filter(item => recentItems.some(recentItem => recentItem.id === item.id)) + return [...prevRecentItems, ...unpinnedItems] + } else { + return filterRecentItems(items, recentItems) + } + }) + } + + const addToPinnedItems = (item: NavbarItemType) => { + const isAlreadyPinned = currentPinnedItems.some(pinnedItem => pinnedItem.id === item.id) + + if (!isAlreadyPinned) { + updatePinnedItems([...currentPinnedItems, item]) + } + } + + const removeFromPinnedItems = (item: NavbarItemType) => { + updatePinnedItems(currentPinnedItems.filter(pinnedItem => pinnedItem.id !== item.id)) + } + + return ( + <AlertDialog open={showManageNavigation} onOpenChange={handleCancel}> + <AlertDialogContent className="h-[574px] max-h-[70vh] max-w-[410px]" onOverlayClick={handleCancel}> + <AlertDialogHeader> + <AlertDialogTitle className="mb-4">Manage navigation</AlertDialogTitle> + <ManageNavigationSearch + navbarMenuData={filterMenuData(navbarMenuData, currentPinnedItems)} + addToPinnedItems={addToPinnedItems} + /> + </AlertDialogHeader> + <ScrollArea className="-mx-5 -mb-5 mt-1"> + <div className="px-5"> + <Text className="inline-block leading-none text-foreground-7" size={1}> + Pinned + </Text> + {!currentPinnedItems.length ? ( + <Text className="mt-3 block text-foreground-5" size={1}> + No pinned items + </Text> + ) : ( + <DndContext onDragEnd={handleDragEnd} collisionDetection={closestCenter}> + <SortableContext items={currentPinnedItems.map((_, index) => getItemId(index))}> + <ul className="-mx-3 mt-3.5 flex flex-col gap-y-0.5"> + {currentPinnedItems.map((item, index) => ( + <DraggableItem id={getItemId(index)} tag="li" key={item.title}> + {({ attributes, listeners }) => ( + <> + <Button + className="w-full grow cursor-grab gap-x-2.5 rounded p-1 px-3 active:cursor-grabbing" + variant="ghost" + {...attributes} + {...listeners} + > + <Icon className="w-3.5" name="grid-dots" size={14} /> + <Text className="w-full text-left text-[inherit]">{item.title}</Text> + </Button> + <Button + className="absolute right-1 top-0.5 z-20 text-icons-4 hover:text-icons-2" + size="sm_icon" + variant="custom" + onClick={() => removeFromPinnedItems(item)} + > + <Icon className="w-3.5" name="x-mark" size={14} /> + </Button> + </> + )} + </DraggableItem> + ))} + </ul> + </SortableContext> + </DndContext> + )} + {currentFilteredRecentItems.length > 0 && ( + <> + <div className="mt-4 flex items-center justify-between"> + <Text className="inline-block leading-none text-foreground-7" size={1}> + Recent + </Text> + <Button className="-mr-1.5" variant="link_accent" size="xs" onClick={handleClearRecent}> + Clear all + </Button> + </div> + <ul className="mt-3 flex flex-col gap-y-0.5 pb-5"> + {currentFilteredRecentItems.map((item, index) => ( + <li className="relative flex h-8 items-center" key={`recent-${item.id}-${index}`}> + <div className="flex w-full grow items-center gap-x-2.5"> + <Icon className="text-icons-4" name="clock-icon" size={14} /> + <Text className="w-full text-left text-foreground-8">{item.title}</Text> + </div> + <Button + className="absolute -right-2 top-0.5 text-icons-4 hover:text-icons-2" + size="sm_icon" + variant="custom" + onClick={() => addToPinnedItems(item)} + > + <Icon name="pin" size={14} /> + </Button> + </li> + ))} + </ul> + </> + )} + </div> + </ScrollArea> + <AlertDialogFooter> + <ButtonGroup.Root> + {!submitted ? ( + <> + <Button variant="outline" onClick={handleCancel} disabled={isSubmitting}> + Cancel + </Button> + <Button type="button" theme="primary" onClick={onSubmit} disabled={isSubmitting}> + {isSubmitting ? 'Saving...' : 'Save'} + </Button> + </> + ) : ( + <Button + variant="ghost" + type="button" + size="sm" + theme="success" + className="pointer-events-none flex gap-2" + disabled={submitted} + > + Saved + <Icon name="tick" size={14} /> + </Button> + )} + </ButtonGroup.Root> + </AlertDialogFooter> + </AlertDialogContent> + </AlertDialog> + ) +} diff --git a/packages/playground/src/components/manage-navigation/manage-navigation-search.tsx b/packages/playground/src/components/manage-navigation/manage-navigation-search.tsx new file mode 100644 index 000000000..ec73f8c95 --- /dev/null +++ b/packages/playground/src/components/manage-navigation/manage-navigation-search.tsx @@ -0,0 +1,156 @@ +import { useCallback, useEffect, useRef, useState } from 'react' + +import { Button, cn, Popover, PopoverContent, PopoverTrigger, ScrollArea, SearchBox, Text } from '@harnessio/canary' + +import { debounce } from '../../utils/debaunce' +import { MenuGroupType, NavbarItemType } from '../navbar/types' + +const filterItems = (categories: MenuGroupType[], query: string): MenuGroupType[] => { + if (!query.trim()) return categories + + return categories.reduce<MenuGroupType[]>((acc, category) => { + const filteredItems = category.items.filter(item => item.title.toLowerCase().includes(query.toLowerCase())) + if (filteredItems.length > 0) { + acc.push({ + ...category, + items: filteredItems + }) + } + return acc + }, []) +} + +interface ManageNavigationSearchProps { + navbarMenuData: MenuGroupType[] + addToPinnedItems: (item: NavbarItemType) => void +} + +export const ManageNavigationSearch = ({ navbarMenuData, addToPinnedItems }: ManageNavigationSearchProps) => { + const [filteredItems, setFilteredItems] = useState<MenuGroupType[]>(navbarMenuData) + const [searchQuery, setSearchQuery] = useState('') + const [isSearchDialogOpen, setSearchDialogOpen] = useState(false) + const inputRef = useRef<HTMLInputElement | null>(null) + const popoverRef = useRef<HTMLDivElement | null>(null) + + const debouncedSearch = useCallback( + debounce((query: string) => { + const filtered = filterItems(navbarMenuData, query) + setFilteredItems(filtered) + }, 300), + [navbarMenuData] + ) + + const handleSearchChange = (event: React.ChangeEvent) => { + event.preventDefault() + const query = (event.target as HTMLInputElement).value + setSearchQuery(query) + debouncedSearch(query) + } + + const handleItemClick = (item: NavbarItemType) => { + addToPinnedItems(item) + setSearchQuery('') + setSearchDialogOpen(false) + } + + const handleInputFocus = () => { + setSearchDialogOpen(true) + if (searchQuery === '') { + setFilteredItems(navbarMenuData) + } + } + + useEffect(() => { + const handleTabKey = (e: KeyboardEvent) => { + if (e.key.toLowerCase() === 'tab') { + const isShift = e.shiftKey + const activeElement = document.activeElement + + if (popoverRef.current) { + const focusableElements = popoverRef.current!.querySelectorAll<HTMLElement>('button:not([disabled])') + const firstFocusableElement = focusableElements[0] + + if (!isShift && activeElement === inputRef.current) { + e.preventDefault() + firstFocusableElement && firstFocusableElement.focus() + } + } + } + } + + window.addEventListener('keydown', handleTabKey) + + return () => { + window.removeEventListener('keydown', handleTabKey) + } + }, []) + + const countFilteredItems = + filteredItems.length + filteredItems.reduce((acc, category) => acc + category.items.length, 0) + + return ( + <Popover open={isSearchDialogOpen} onOpenChange={setSearchDialogOpen}> + <PopoverTrigger asChild> + <SearchBox.Root + className="w-full" + inputClassName="h-9 placeholder:text-foreground-5" + ref={inputRef} + placeholder="Add menu element" + value={searchQuery} + handleChange={handleSearchChange} + hasSearchIcon={false} + onFocus={handleInputFocus} + /> + </PopoverTrigger> + <PopoverContent + className="w-[368px] overflow-hidden !rounded border-borders-1 bg-background-2 !p-0" + ref={popoverRef} + align="start" + onWheel={e => e.stopPropagation()} + onOpenAutoFocus={e => e.preventDefault()} + onCloseAutoFocus={e => e.preventDefault()} + > + <ScrollArea className={cn('relative max-h-[50vh]', countFilteredItems > 10 && 'h-[404px]')}> + <div className="px-1 pb-2 pt-1"> + <span + className="pointer-events-none absolute inset-x-0 top-0 h-3 w-full bg-gradient-to-b from-background-2 to-transparent" + aria-hidden + /> + <span + className="pointer-events-none absolute inset-x-0 bottom-0 h-3 w-full bg-gradient-to-t from-background-2 to-transparent" + aria-hidden + /> + {countFilteredItems === 0 ? ( + <Text className="block w-full px-2 py-4 text-foreground-5">No results found</Text> + ) : ( + filteredItems.map((category, index) => ( + <div + className={cn(index > 0 ? 'border-borders-4 mt-0.5 border-t pt-2' : 'pt-1')} + key={`category-${category.groupId}-${index}`} + > + <Text className="inline-block px-2 leading-none text-foreground-7" size={1}> + {category.title} + </Text> + <div className="mt-2.5 flex flex-col"> + {category.items.map(item => ( + <Button + className="h-9 cursor-pointer rounded-sm px-2 focus-visible:ring-offset-0" + variant="ghost" + key={`item-${item.id}`} + onClick={() => handleItemClick(item)} + > + <div className="flex w-full items-center gap-x-2"> + <Text className="truncate leading-tight text-foreground-8">{item.title}</Text> + </div> + </Button> + ))} + </div> + </div> + )) + )} + </div> + </ScrollArea> + </PopoverContent> + </Popover> + ) +} diff --git a/packages/playground/src/components/markdown-viewer.tsx b/packages/playground/src/components/markdown-viewer.tsx index cf0d4dfd6..8e5c2d285 100644 --- a/packages/playground/src/components/markdown-viewer.tsx +++ b/packages/playground/src/components/markdown-viewer.tsx @@ -87,7 +87,7 @@ export function MarkdownViewer({ > <MarkdownPreview source={source} - className="prose prose-invert !bg-background !max-w-full" + className="prose prose-invert !max-w-full !bg-background" // warpperElement={{ 'data-color-mode': darkMode ? 'dark' : 'light' }} rehypeRewrite={(node, _index, parent) => { if ((node as unknown as HTMLDivElement).tagName === 'a') { diff --git a/packages/playground/src/components/more-submenu.tsx b/packages/playground/src/components/more-submenu.tsx index 9b2c94c0a..c904ecdd9 100644 --- a/packages/playground/src/components/more-submenu.tsx +++ b/packages/playground/src/components/more-submenu.tsx @@ -1,44 +1,47 @@ import { NavLink } from 'react-router-dom' -import { Icon, Navbar, Sheet, SheetContent, SheetTitle, Spacer } from '@harnessio/canary' +import { Icon, Navbar, ScrollArea, Sheet, SheetContent, SheetTitle, Spacer } from '@harnessio/canary' -import { navbarSubmenuData } from '../data/mockNavbarSubmenuData' +import { MenuGroupType } from './navbar/types' interface MoreSubmenuProps { - showMore: boolean - handleMore: () => void + showMoreMenu: boolean + handleMoreMenu: () => void + items: MenuGroupType[] } -export function MoreSubmenu({ showMore, handleMore }: MoreSubmenuProps) { +export function MoreSubmenu({ showMoreMenu, handleMoreMenu, items }: MoreSubmenuProps) { return ( - <Sheet modal={false} open={showMore}> + <Sheet modal={false} open={showMoreMenu}> <SheetContent className="inset-y-0 left-[220px] z-40 h-screen w-[328px] bg-transparent p-0" side="left" - onClick={handleMore} + onClick={handleMoreMenu} modal={false} > <SheetTitle className="sr-only">More Menu</SheetTitle> <Navbar.Root className="w-[328px]" isSubMenu> - <Navbar.Content> - <Spacer size={9} /> - {navbarSubmenuData.map((group, group_idx) => ( - <Navbar.Group key={group.groupId} topBorder={group_idx > 0} title={group.title} isSubMenu> - {group.items.map(item => ( - <NavLink key={item.id} to={item.to || ''}> - {({ isActive }) => ( - <Navbar.Item - text={item.title || ''} - description={item.description || ''} - submenuItem - icon={<Icon name={item.iconName} size={18} />} - active={isActive} - /> - )} - </NavLink> - ))} - </Navbar.Group> - ))} + <Navbar.Content className="overflow-hidden"> + <ScrollArea> + <Spacer size={9} /> + {items.map((group, group_idx) => ( + <Navbar.Group key={group.groupId} topBorder={group_idx > 0} title={group.title} isSubMenu> + {group.items.map(item => ( + <NavLink key={item.id} to={item.to || ''}> + {({ isActive }) => ( + <Navbar.Item + text={item.title || ''} + description={item.description || ''} + submenuItem + icon={<Icon name={item.iconName} size={18} />} + active={isActive} + /> + )} + </NavLink> + ))} + </Navbar.Group> + ))} + </ScrollArea> </Navbar.Content> </Navbar.Root> </SheetContent> diff --git a/packages/playground/src/components/navbar.tsx b/packages/playground/src/components/navbar.tsx deleted file mode 100644 index 40444d7dc..000000000 --- a/packages/playground/src/components/navbar.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { useMemo, useState } from 'react' -import { Link, NavLink, useLocation } from 'react-router-dom' -import type { IconProps } from '@harnessio/canary' -import { Navbar as NavbarComp, Icon, NavbarProjectChooser, NavbarUser, Button, Text } from '@harnessio/canary' -import type { TypesUser } from '../layouts/types' - -const NavBarLink = (item: NavbarItem | NavbarItemStatic) => { - return ( - <NavLink to={item.to || ''}> - {({ isActive }) => ( - <NavbarComp.Item text={item.title} icon={<Icon name={item.iconName} size={12} />} active={isActive} /> - )} - </NavLink> - ) -} - -const hideNavbarPaths = ['/signin', '/signup'] - -interface NavbarItem { - id: number - title: string - iconName: IconProps['name'] - description: string - to?: string -} - -type NavbarItemStatic = Pick<NavbarItem, 'title' | 'iconName' | 'to'> - -const adminMenuItem: Omit<NavbarItemStatic, 'to'> = { - title: 'Settings', - iconName: 'settings-1' -} - -const primaryMenuItems: NavbarItemStatic[] = [ - { - title: 'Repositories', - iconName: 'repositories', - to: '/repos' - }, - { - title: 'Pipelines', - iconName: 'pipelines', - to: '/pipelines' - }, - { - title: 'Executions', - iconName: 'execution', - to: '/executions' - }, - { - title: 'Featured Flags', - iconName: 'featured-flags', - to: '/feature-flags' - } -] - -const initialPinnedMenuItems: NavbarItem[] = [ - { - id: 4, - title: 'Chaos Engineering', - iconName: 'chaos-engineering', - description: 'Manage chaos experiments', - to: '/chaos-engineering' - }, - { - id: 12, - title: 'Environment', - iconName: 'environment', - description: 'Manage your environments', - to: '/environment' - }, - { - id: 13, - title: 'Secrets', - iconName: 'key', - description: 'Store your secrets securely', - to: '/secrets' - }, - { - id: 14, - title: 'Connectors', - iconName: 'connectors', - description: 'Manage your connectors', - to: '/connectors' - } -] - -interface NavbarProps { - showMore: boolean - showSystemAdmin: boolean - handleMore: () => void - handleSystemAdmin: () => void - currentUser: TypesUser | undefined -} - -export const Navbar = ({ showMore, showSystemAdmin, handleMore, handleSystemAdmin, currentUser }: NavbarProps) => { - const location = useLocation() - const [pinnedItems, setPinnedItems] = useState<NavbarItem[]>(initialPinnedMenuItems) - - const showNavbar = useMemo(() => { - return !hideNavbarPaths.includes(location.pathname) - }, [location.pathname]) - - if (!showNavbar) return null - - return ( - <NavbarComp.Root className="fixed inset-y-0 left-0 z-50 max-md:hidden"> - <NavbarComp.Header> - <NavbarProjectChooser.Root - logo={ - <Link className="flex items-center gap-1.5" to="/"> - <Icon name="harness" size={18} className="text-foreground-1" /> - <Icon name="harness-logo-text" width={65} height={15} className="text-foreground-1 mb-0.5" /> - </Link> - } - /> - </NavbarComp.Header> - - <NavbarComp.Content> - <NavbarComp.Group> - {primaryMenuItems.map((item, idx) => ( - <NavBarLink key={idx} {...item} /> - ))} - <button onClick={handleMore}> - <NavbarComp.Item text="More" icon={<Icon name="ellipsis" size={12} />} active={showMore} /> - </button> - </NavbarComp.Group> - <NavbarComp.Group title="Recent" topBorder> - {pinnedItems.map(item => ( - <NavBarLink key={item.id} {...item} /> - ))} - </NavbarComp.Group> - <NavbarComp.Group topBorder> - <button onClick={handleSystemAdmin}> - <NavbarComp.Item - text={adminMenuItem.title} - icon={<Icon name={adminMenuItem.iconName} size={12} />} - active={showSystemAdmin} - /> - </button> - </NavbarComp.Group> - - <div className="mx-auto mb-11 mt-auto flex max-w-[160px] flex-col items-center gap-2.5 text-center"> - <div className="flex flex-col items-center gap-1"> - <div className="relative mb-2"> - <div className="absolute bottom-2 left-2 z-[-1] size-[42px]"> - <Icon - className="absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 opacity-20 mix-blend-plus-lighter blur-[15px]" - name="harness-gradient-ellipse" - size={102} - /> - </div> - <Icon name="harness-gradient" size={44} /> - </div> - <Text className="leading-none" size={1} weight="medium"> - AI Assistant - </Text> - <Text className="text-foreground-5 leading-[1.0625rem]" size={0}> - Create, analyze or debug your pipelines faster. - </Text> - </div> - <Button - className="bg-background-7 text-12 font-medium" - borderRadius="full" - size="sm" - padding="sm" - variant="gradient-border" - gradientType="ai-button"> - <Icon className="mr-1.5" name="sparks" size={12} /> - Make with AI - </Button> - </div> - </NavbarComp.Content> - - <NavbarComp.Footer> - <NavbarUser.Root - username={currentUser?.display_name || currentUser?.uid || ''} - email={currentUser?.email} - url={currentUser?.url} - menuItems={[ - { - key: 0, - element: <Link to="/sandbox/settings/profile/general">Settings</Link> - }, - { - key: 1, - element: <Link to="/logout">Log out</Link> - } - ]} - /> - </NavbarComp.Footer> - </NavbarComp.Root> - ) -} diff --git a/packages/playground/src/components/navbar/data.ts b/packages/playground/src/components/navbar/data.ts new file mode 100644 index 000000000..49fbd1d7b --- /dev/null +++ b/packages/playground/src/components/navbar/data.ts @@ -0,0 +1,44 @@ +import { NavbarItemType, UserMenuItemType, UserMenuKeys } from './types' + +export const adminMenuItem: Pick<NavbarItemType, 'title' | 'iconName'> = { + title: 'Settings', + iconName: 'settings-1' +} + +export const userMenuItems: UserMenuItemType[] = [ + { + key: UserMenuKeys.ACCOUNT, + iconName: 'user', + title: 'Account', + to: '/account', + isSeparated: false + }, + { + key: UserMenuKeys.THEME, + iconName: 'paint', + title: 'Theme', + to: '/theme', + isSeparated: false + }, + { + key: UserMenuKeys.CUSTOM_NAV, + iconName: 'navigation', + title: 'Customize navigation', + to: null, + isSeparated: false + }, + { + key: UserMenuKeys.ADMINISTRATION, + iconName: 'settings-1', + title: 'Administration', + to: '/sandbox/settings/profile/general', + isSeparated: true + }, + { + key: UserMenuKeys.LOG_OUT, + iconName: 'logOut', + title: 'Log out', + to: null, + isSeparated: true + } +] diff --git a/packages/playground/src/components/navbar/index.tsx b/packages/playground/src/components/navbar/index.tsx new file mode 100644 index 000000000..791fc8f8e --- /dev/null +++ b/packages/playground/src/components/navbar/index.tsx @@ -0,0 +1,114 @@ +import { useMemo } from 'react' +import { Link, useLocation } from 'react-router-dom' + +import { Icon, Navbar as NavbarComp, NavbarProjectChooser, ScrollArea } from '@harnessio/canary' + +import type { TypesUser } from '../../layouts/types' +import { adminMenuItem } from './data' +import { NavbarAi } from './navbar-ai' +import { NavbarItem } from './navbar-item' +import { NavbarUser } from './navbar-user' +import { NavbarItemType } from './types' + +const hideNavbarPaths = ['/signin', '/signup'] + +interface NavbarProps { + recentMenuItems: NavbarItemType[] + pinnedMenuItems: NavbarItemType[] + showMoreMenu: boolean + showSettingMenu: boolean + handleMoreMenu: () => void + handleSettingsMenu: () => void + currentUser: TypesUser | undefined + handleCustomNav: () => void + handleLogOut: () => void + handleChangePinnedMenuItem: (item: NavbarItemType) => void + handleRemoveRecentMenuItem: (item: NavbarItemType) => void +} + +export const Navbar = ({ + recentMenuItems, + pinnedMenuItems, + showMoreMenu, + showSettingMenu, + handleMoreMenu, + handleSettingsMenu, + currentUser, + handleCustomNav, + handleLogOut, + handleChangePinnedMenuItem, + handleRemoveRecentMenuItem +}: NavbarProps) => { + const location = useLocation() + + const showNavbar = useMemo(() => { + return !hideNavbarPaths.includes(location.pathname) + }, [location.pathname]) + + if (!showNavbar) return null + + return ( + <NavbarComp.Root className="fixed inset-y-0 left-0 z-50 overflow-hidden max-md:hidden"> + <NavbarComp.Header> + <NavbarProjectChooser.Root + logo={ + <Link className="flex items-center gap-1.5" to="/"> + <Icon name="harness" size={18} className="text-foreground-1" /> + <Icon name="harness-logo-text" width={65} height={15} className="mb-0.5 text-foreground-1" /> + </Link> + } + /> + </NavbarComp.Header> + + <NavbarComp.Content className="overflow-hidden"> + <ScrollArea className="mb-[1.375rem] flex-1"> + <NavbarComp.Group> + {pinnedMenuItems.map((item, idx) => ( + <NavbarItem + key={idx} + item={item} + handleChangePinnedMenuItem={handleChangePinnedMenuItem} + handleRemoveRecentMenuItem={handleRemoveRecentMenuItem} + handleCustomNav={handleCustomNav} + /> + ))} + <button onClick={handleMoreMenu}> + <NavbarComp.Item text="More" icon={<Icon name="ellipsis" size={12} />} active={showMoreMenu} /> + </button> + </NavbarComp.Group> + + {!!recentMenuItems.length && ( + <NavbarComp.Group title="Recent" topBorder> + {recentMenuItems.map(item => ( + <NavbarItem + key={item.id} + item={item} + isRecent + handleChangePinnedMenuItem={handleChangePinnedMenuItem} + handleRemoveRecentMenuItem={handleRemoveRecentMenuItem} + handleCustomNav={handleCustomNav} + /> + ))} + </NavbarComp.Group> + )} + + <NavbarComp.Group topBorder> + <button onClick={handleSettingsMenu}> + <NavbarComp.Item + text={adminMenuItem.title} + icon={<Icon name={adminMenuItem.iconName} size={12} />} + active={showSettingMenu} + /> + </button> + </NavbarComp.Group> + </ScrollArea> + + <NavbarAi /> + </NavbarComp.Content> + + <NavbarComp.Footer> + <NavbarUser currentUser={currentUser} handleCustomNav={handleCustomNav} handleLogOut={handleLogOut} /> + </NavbarComp.Footer> + </NavbarComp.Root> + ) +} diff --git a/packages/playground/src/components/navbar/navbar-ai/index.tsx b/packages/playground/src/components/navbar/navbar-ai/index.tsx new file mode 100644 index 000000000..08dd99c85 --- /dev/null +++ b/packages/playground/src/components/navbar/navbar-ai/index.tsx @@ -0,0 +1,37 @@ +import { Button, Icon, Text } from '@harnessio/canary' + +export const NavbarAi = () => { + return ( + <div className="mx-auto mb-11 mt-auto flex max-w-[160px] flex-col items-center gap-2.5 text-center"> + <div className="flex flex-col items-center gap-1"> + <div className="relative mb-2"> + <div className="absolute bottom-2 left-2 z-[-1] size-[42px]"> + <Icon + className="absolute inset-1/2 -translate-x-1/2 -translate-y-1/2 opacity-20 mix-blend-plus-lighter blur-[15px]" + name="harness-gradient-ellipse" + size={102} + /> + </div> + <Icon name="harness-gradient" size={44} /> + </div> + <Text className="leading-none" size={1} weight="medium"> + AI Assistant + </Text> + <Text className="leading-[1.0625rem] text-foreground-5" size={0}> + Create, analyze or debug your pipelines faster. + </Text> + </div> + <Button + className="bg-background-7 text-12 font-medium" + borderRadius="full" + size="sm" + padding="sm" + variant="gradient-border" + gradientType="ai-button" + > + <Icon className="mr-1.5" name="sparks" size={12} /> + Make with AI + </Button> + </div> + ) +} diff --git a/packages/playground/src/components/navbar/navbar-item/index.tsx b/packages/playground/src/components/navbar/navbar-item/index.tsx new file mode 100644 index 000000000..9cf7e7494 --- /dev/null +++ b/packages/playground/src/components/navbar/navbar-item/index.tsx @@ -0,0 +1,93 @@ +import { NavLink } from 'react-router-dom' + +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + Icon, + IconProps, + Navbar as NavbarComp, + Text +} from '@harnessio/canary' + +import { NavbarItemType } from '../types' + +interface NavbarItemProps { + item: NavbarItemType + isRecent?: boolean + handleChangePinnedMenuItem: (item: NavbarItemType) => void + handleRemoveRecentMenuItem: (item: NavbarItemType) => void + handleCustomNav: () => void +} + +export const NavbarItem = ({ + item, + isRecent = false, + handleChangePinnedMenuItem, + handleRemoveRecentMenuItem, + handleCustomNav +}: NavbarItemProps) => { + const iconName = item.iconName.replace('-gradient', '') as IconProps['name'] + + const handlePin = () => { + handleChangePinnedMenuItem(item) + } + + const handleRemoveRecent = () => { + handleRemoveRecentMenuItem(item) + } + + const dropdownItems = isRecent ? ( + <> + <DropdownMenuItem onSelect={handlePin}> + <Text size={2} truncate> + Pin + </Text> + </DropdownMenuItem> + <DropdownMenuItem onSelect={handleRemoveRecent}> + <Text size={2} truncate> + Remove + </Text> + </DropdownMenuItem> + </> + ) : ( + <> + <DropdownMenuItem onSelect={handleCustomNav}> + <Text size={2} truncate> + Reorder + </Text> + </DropdownMenuItem> + <DropdownMenuItem onSelect={handlePin}> + <Text size={2} truncate> + Unpin + </Text> + </DropdownMenuItem> + </> + ) + + return ( + <div className="group relative"> + <NavLink className="block pr-6" to={item.to || ''}> + {({ isActive }) => ( + <NavbarComp.Item text={item.title} icon={<Icon name={iconName} size={12} />} active={isActive} /> + )} + </NavLink> + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button + className="absolute -right-[0.8125rem] top-0 text-icons-4 opacity-0 hover:text-icons-2 group-hover:opacity-100 data-[state=open]:opacity-100" + size="sm_icon" + variant="custom" + > + <Icon name="menu-dots" size={12} /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent className="w-[128px]" align="end" sideOffset={-1} alignOffset={8}> + {dropdownItems} + </DropdownMenuContent> + </DropdownMenu> + </div> + ) +} diff --git a/packages/playground/src/components/navbar/navbar-link/index.tsx b/packages/playground/src/components/navbar/navbar-link/index.tsx new file mode 100644 index 000000000..0a33c20d9 --- /dev/null +++ b/packages/playground/src/components/navbar/navbar-link/index.tsx @@ -0,0 +1,17 @@ +import { NavLink } from 'react-router-dom' + +import { Icon, IconProps, Navbar as NavbarComp } from '@harnessio/canary' + +import { NavbarItem, NavbarItemStatic } from '../types' + +export const NavBarLink = (item: NavbarItem | NavbarItemStatic) => { + const iconName = item.iconName.replace('-gradient', '') as IconProps['name'] + + return ( + <NavLink to={item.to || ''}> + {({ isActive }) => ( + <NavbarComp.Item text={item.title} icon={<Icon name={iconName} size={12} />} active={isActive} /> + )} + </NavLink> + ) +} diff --git a/packages/playground/src/components/navbar/navbar-user/index.tsx b/packages/playground/src/components/navbar/navbar-user/index.tsx new file mode 100644 index 000000000..e2e1ef907 --- /dev/null +++ b/packages/playground/src/components/navbar/navbar-user/index.tsx @@ -0,0 +1,67 @@ +import { useMemo } from 'react' +import { Link } from 'react-router-dom' + +import { cn, Icon, NavbarUser as NavbarUserComp, Text } from '@harnessio/canary' + +import { TypesUser } from '../../../layouts/types' +import { userMenuItems } from '../data' +import { UserMenuKeys } from '../types' + +interface NavbarUserProps { + currentUser: TypesUser | undefined + handleCustomNav: () => void + handleLogOut: () => void +} + +export const NavbarUser = ({ currentUser, handleCustomNav, handleLogOut }: NavbarUserProps) => { + const menuItems = useMemo(() => { + return userMenuItems.map(({ key, iconName, title, to, isSeparated }) => { + const className = 'relative grid grid-cols-[auto_1fr] items-center gap-2.5' + + const handleClick = () => { + switch (key) { + case UserMenuKeys.CUSTOM_NAV: + return handleCustomNav() + case UserMenuKeys.LOG_OUT: + return handleLogOut + default: + return + } + } + + const elementChild = ( + <> + <Icon className={cn('text-icons-4 ml-[3px] transition-colors')} size={12} name={iconName} /> + <Text size={2} truncate> + {title} + </Text> + </> + ) + + const element = to ? ( + <Link className={className} to={to}> + {elementChild} + </Link> + ) : ( + <button className={cn(className, 'w-full text-left')} onClick={handleClick}> + {elementChild} + </button> + ) + + return { + key, + element, + isSeparated + } + }) + }, [handleCustomNav, handleLogOut]) + + return ( + <NavbarUserComp.Root + username={currentUser?.display_name || currentUser?.uid || ''} + role={currentUser?.role} + url={currentUser?.url} + menuItems={menuItems} + /> + ) +} diff --git a/packages/playground/src/components/navbar/types.ts b/packages/playground/src/components/navbar/types.ts new file mode 100644 index 000000000..e8a6e74e0 --- /dev/null +++ b/packages/playground/src/components/navbar/types.ts @@ -0,0 +1,37 @@ +import { IconProps } from '@harnessio/canary' + +export enum MenuGroupTypes { + GENERAL = 'general', + SETTINGS = 'settings' +} + +export interface MenuGroupType { + groupId: number | string + title: string + type: MenuGroupTypes + items: NavbarItemType[] +} + +export interface NavbarItemType { + id: number | string + title: string + iconName: IconProps['name'] + description?: string + to: string +} + +export enum UserMenuKeys { + ACCOUNT = 'account', + THEME = 'theme', + CUSTOM_NAV = 'customNavigation', + ADMINISTRATION = 'administration', + LOG_OUT = 'logOut' +} + +export interface UserMenuItemType { + key: UserMenuKeys + iconName: IconProps['name'] + title: string + to: string | null + isSeparated: boolean +} diff --git a/packages/playground/src/components/no-search-results.tsx b/packages/playground/src/components/no-search-results.tsx index 1304974a7..566aa936f 100644 --- a/packages/playground/src/components/no-search-results.tsx +++ b/packages/playground/src/components/no-search-results.tsx @@ -1,6 +1,6 @@ import React from 'react' -import type { NoDataProps } from './no-data' -import { NoData } from './no-data' + +import { NoData, type NoDataProps } from './no-data' interface NoSearchResultsProps extends Omit<NoDataProps, 'iconSize'> { iconSize?: number diff --git a/packages/playground/src/components/pipeline-list.tsx b/packages/playground/src/components/pipeline-list.tsx index 33c6e6877..e73fb57db 100644 --- a/packages/playground/src/components/pipeline-list.tsx +++ b/packages/playground/src/components/pipeline-list.tsx @@ -42,7 +42,7 @@ const Description = ({ sha, description, version }: { sha: string; description: return ( <div className="inline-flex max-w-full items-center gap-2 overflow-hidden pl-[24px]"> {sha && ( - <div className="bg-tertiary-background/10 flex items-center gap-1 rounded-md px-1.5"> + <div className="flex items-center gap-1 rounded-md bg-tertiary-background/10 px-1.5"> <Icon size={11} name={'tube-sign'} /> {sha?.slice(0, 7)} </div> diff --git a/packages/playground/src/components/pipeline-studio/pipeline-studio-footer-bar/pipeline-studio-footer-bar.tsx b/packages/playground/src/components/pipeline-studio/pipeline-studio-footer-bar/pipeline-studio-footer-bar.tsx index 144ef9360..ed9488452 100644 --- a/packages/playground/src/components/pipeline-studio/pipeline-studio-footer-bar/pipeline-studio-footer-bar.tsx +++ b/packages/playground/src/components/pipeline-studio/pipeline-studio-footer-bar/pipeline-studio-footer-bar.tsx @@ -39,7 +39,7 @@ const PipelineStudioFooterBar: React.FC<PipelineStudioFooterBarProps> = (props: return ( <footer className={ - 'bg-grey-6 text-grey-60 text-tiny flex h-10 shrink-0 items-center justify-between border-t border-[#1d1d20] px-4 font-normal not-italic leading-[15px]' + 'bg-grey-6 text-grey-60 flex h-10 shrink-0 items-center justify-between border-t border-[#1d1d20] px-4 text-tiny font-normal not-italic leading-[15px]' } > <div className="flex items-center gap-2"> @@ -49,7 +49,7 @@ const PipelineStudioFooterBar: React.FC<PipelineStudioFooterBarProps> = (props: onClick={() => { props.togglePane?.() }} - className="hover:bg-primary/10 flex h-full cursor-pointer gap-2 rounded-md px-2 py-1.5 duration-150 ease-in-out" + className="flex h-full cursor-pointer gap-2 rounded-md px-2 py-1.5 duration-150 ease-in-out hover:bg-primary/10" > <div className="flex items-center gap-1.5"> <Icon name="x-mark" className="text-tertiary-background" /> @@ -82,7 +82,7 @@ const PipelineStudioFooterBar: React.FC<PipelineStudioFooterBarProps> = (props: <div className={'flex items-baseline'}> <span className="text-tiny text-tertiary-background">Branch:</span> <Select value={currentBranch} disabled={branchesLoading} onValueChange={onBranchChange}> - <SelectTrigger className="text-primary w-fit border-none px-1 text-[12px] focus:ring-0"> + <SelectTrigger className="w-fit border-none px-1 text-[12px] text-primary focus:ring-0"> <SelectValue placeholder={branchesLoading ? 'Loading...' : 'Select branch'} /> </SelectTrigger> <SelectContent> @@ -99,7 +99,7 @@ const PipelineStudioFooterBar: React.FC<PipelineStudioFooterBarProps> = (props: {committedTimeAgo && authorName && ( <Popover> <PopoverTrigger> - <div className="text-tiny text-tertiary-background flex"> + <div className="flex text-tiny text-tertiary-background"> Last edited <span className="text-primary"> {committedTimeAgo} </span> by <span className="text-primary"> {authorName} </span> diff --git a/packages/playground/src/components/pipeline-studio/pipeline-studio-toolbar-actions.tsx b/packages/playground/src/components/pipeline-studio/pipeline-studio-toolbar-actions.tsx index a8916883d..ae8ba594c 100644 --- a/packages/playground/src/components/pipeline-studio/pipeline-studio-toolbar-actions.tsx +++ b/packages/playground/src/components/pipeline-studio/pipeline-studio-toolbar-actions.tsx @@ -21,11 +21,11 @@ export const PipelineStudioToolbarActions = (props: PipelineStudioToolbarActions </ToggleGroupItem> {showEdit && ( <ToggleGroupItem value="edit" onClick={onEditClick} title="Edit"> - <Icon name="edit-pen" className="text-foreground size-5" /> + <Icon name="edit-pen" className="size-5 text-foreground" /> </ToggleGroupItem> )} <ToggleGroupItem value="download" onClick={onDownloadClick} title="Download"> - <Icon name="download" className="text-foreground size-5" /> + <Icon name="download" className="size-5 text-foreground" /> </ToggleGroupItem> </ToggleGroup> ) diff --git a/packages/playground/src/components/pipeline-studio/step-form/step-form-section.tsx b/packages/playground/src/components/pipeline-studio/step-form/step-form-section.tsx index e695072eb..c1f31b3ce 100644 --- a/packages/playground/src/components/pipeline-studio/step-form/step-form-section.tsx +++ b/packages/playground/src/components/pipeline-studio/step-form/step-form-section.tsx @@ -8,11 +8,11 @@ const StepFormSection = { }, Title: function Title({ children }: { children: React.ReactNode }) { - return <div className="text-accent-foreground my-3 text-lg">{children}</div> + return <div className="my-3 text-lg text-accent-foreground">{children}</div> }, Description: function Description({ children }: { children: React.ReactNode }) { - return <div className="text-muted-foreground mt-3">{children}</div> + return <div className="mt-3 text-muted-foreground">{children}</div> }, Form: function Form({ children }: { children: React.ReactNode }) { diff --git a/packages/playground/src/components/pipeline-studio/step-form/step-form.tsx b/packages/playground/src/components/pipeline-studio/step-form/step-form.tsx index 53e7f7721..f9a059f81 100644 --- a/packages/playground/src/components/pipeline-studio/step-form/step-form.tsx +++ b/packages/playground/src/components/pipeline-studio/step-form/step-form.tsx @@ -8,11 +8,11 @@ const StepForm = { }, Title: function Title({ children }: { children: React.ReactNode }) { - return <div className="text-accent-foreground mb-3 text-lg capitalize">{children}</div> + return <div className="mb-3 text-lg capitalize text-accent-foreground">{children}</div> }, Description: function Title({ children }: { children: React.ReactNode }) { - return <div className="text-muted-foreground my-3">{children}</div> + return <div className="my-3 text-muted-foreground">{children}</div> }, Actions: function Title({ children }: { children: React.ReactNode }) { diff --git a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-content.tsx b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-content.tsx index b8cb6a63a..910014118 100644 --- a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-content.tsx +++ b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-content.tsx @@ -8,7 +8,7 @@ const StepsPaletteContent = { }, SectionHeader: function SectionHeader({ children }: { children: React.ReactNode }) { - return <div className="text-accent-foreground mb-3 flex flex-row justify-between">{children}</div> + return <div className="mb-3 flex flex-row justify-between text-accent-foreground">{children}</div> }, SectionItem: function SectionHeader({ children }: { children: React.ReactNode }) { diff --git a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-filters.tsx b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-filters.tsx index 5122e7698..875ce795b 100644 --- a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-filters.tsx +++ b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-filters.tsx @@ -13,7 +13,7 @@ const StepPaletteFilters = (): JSX.Element => { <Icon name="x-mark" className="mr-2" /> Filters </Button> - <Toggle variant={'outline'} className="text-muted-foreground data-[state=on]:text-muted-foreground font-normal"> + <Toggle variant={'outline'} className="font-normal text-muted-foreground data-[state=on]:text-muted-foreground"> Recommended <Icon name="x-mark" className="ml-2" /> </Toggle> </StepPaletteFiltersLayout.Root> diff --git a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-item.tsx b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-item.tsx index 4fb495b5c..d819ee109 100644 --- a/packages/playground/src/components/pipeline-studio/step-palette/step-palette-item.tsx +++ b/packages/playground/src/components/pipeline-studio/step-palette/step-palette-item.tsx @@ -19,12 +19,12 @@ const StepsPaletteItem = { return <div className="font-medium">{children}</div> }, Description: function Description({ children }: { children: React.ReactNode }) { - return <div className="text-muted-foreground mt-2 line-clamp-2 overflow-hidden text-sm">{children}</div> + return <div className="mt-2 line-clamp-2 overflow-hidden text-sm text-muted-foreground">{children}</div> }, BadgeWrapper: function BadgeWrapper({ children }: { children: React.ReactNode }) { return ( <div className="self-start rounded-full bg-gradient-to-r from-[#B1CBFF] via-[#6D6B75] to-[#B1CBFF] p-0.5"> - <div className="bg-background rounded-full px-2 text-sm">{children}</div> + <div className="rounded-full bg-background px-2 text-sm">{children}</div> </div> ) } diff --git a/packages/playground/src/components/pipeline-studio/step-palette/step-palette.tsx b/packages/playground/src/components/pipeline-studio/step-palette/step-palette.tsx index 57e2c5d6f..3cb3aab9b 100644 --- a/packages/playground/src/components/pipeline-studio/step-palette/step-palette.tsx +++ b/packages/playground/src/components/pipeline-studio/step-palette/step-palette.tsx @@ -8,7 +8,7 @@ const StepsPalette = { }, Title: function Title({ children }: { children: React.ReactNode }) { - return <div className="text-accent-foreground mb-3 text-lg">{children}</div> + return <div className="mb-3 text-lg text-accent-foreground">{children}</div> } } diff --git a/packages/playground/src/components/pipeline-studio/visual-yaml-toggle.tsx b/packages/playground/src/components/pipeline-studio/visual-yaml-toggle.tsx index 1af329ad2..60d03ed8a 100644 --- a/packages/playground/src/components/pipeline-studio/visual-yaml-toggle.tsx +++ b/packages/playground/src/components/pipeline-studio/visual-yaml-toggle.tsx @@ -20,19 +20,19 @@ export const VisualYamlToggle = (props: VisualYamlToggleProps): JSX.Element => { value={view} type="single" unselectable={'on'} - className={'border-primary/10 bg-primary-foreground rounded-lg border p-0.5'} + className={'rounded-lg border border-primary/10 bg-primary-foreground p-0.5'} > <ToggleGroupItem disabled={!isYamlValid} value={'visual'} - className="data-[state=on]:border-primary/10 h-7 rounded-md border border-transparent text-xs font-medium disabled:opacity-100" + className="h-7 rounded-md border border-transparent text-xs font-medium disabled:opacity-100 data-[state=on]:border-primary/10" > - {!isYamlValid && <Icon name="x-mark" className="text-destructive mr-1" />} + {!isYamlValid && <Icon name="x-mark" className="mr-1 text-destructive" />} Visual </ToggleGroupItem> <ToggleGroupItem value={'yaml'} - className="text-tertiary-background data-[state=on]:text-primary h-7 rounded-md border border-transparent text-xs font-medium data-[state=on]:border-white/10" + className="h-7 rounded-md border border-transparent text-xs font-medium text-tertiary-background data-[state=on]:border-white/10 data-[state=on]:text-primary" > YAML </ToggleGroupItem> diff --git a/packages/playground/src/components/profile-settings/profile-settings-keys-list.tsx b/packages/playground/src/components/profile-settings/profile-settings-keys-list.tsx index 8f7110d9e..4f84d2222 100644 --- a/packages/playground/src/components/profile-settings/profile-settings-keys-list.tsx +++ b/packages/playground/src/components/profile-settings/profile-settings-keys-list.tsx @@ -1,7 +1,7 @@ import { Icon, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Text } from '@harnessio/canary' import { timeAgo } from '../../utils/utils' -import { KeysList } from './types' +import type { KeysList } from './types' interface PageProps { publicKeys: KeysList[] diff --git a/packages/playground/src/components/profile-settings/profile-settings-tokens-list.tsx b/packages/playground/src/components/profile-settings/profile-settings-tokens-list.tsx index 1d9bb1b9b..8a1bbe551 100644 --- a/packages/playground/src/components/profile-settings/profile-settings-tokens-list.tsx +++ b/packages/playground/src/components/profile-settings/profile-settings-tokens-list.tsx @@ -1,7 +1,7 @@ import { Icon, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Text } from '@harnessio/canary' import { timeAgo } from '../../utils/utils' -import { TokensList } from './types' +import type { TokensList } from './types' interface PageProps { tokens: TokensList[] diff --git a/packages/playground/src/components/profile-settings/ssh-key-create-dialog.tsx b/packages/playground/src/components/profile-settings/ssh-key-create-dialog.tsx index c41726f82..127c5f6ac 100644 --- a/packages/playground/src/components/profile-settings/ssh-key-create-dialog.tsx +++ b/packages/playground/src/components/profile-settings/ssh-key-create-dialog.tsx @@ -10,7 +10,7 @@ interface SshKeyCreateDialogProps { export const SshKeyCreateDialog: React.FC<SshKeyCreateDialogProps> = ({ open, onClose }) => { return ( <Dialog open={open} onOpenChange={onClose}> - <DialogContent className="border-border bg-primary-background max-w-[500px]"> + <DialogContent className="max-w-[500px] border-border bg-primary-background"> <DialogHeader> <DialogTitle className="text-left">New SSH key</DialogTitle> </DialogHeader> diff --git a/packages/playground/src/components/profile-settings/token-create-dialog.tsx b/packages/playground/src/components/profile-settings/token-create-dialog.tsx index 5940cb8f0..56453dd74 100644 --- a/packages/playground/src/components/profile-settings/token-create-dialog.tsx +++ b/packages/playground/src/components/profile-settings/token-create-dialog.tsx @@ -10,7 +10,7 @@ interface TokenCreateDialogProps { export const TokenCreateDialog: React.FC<TokenCreateDialogProps> = ({ open, onClose }) => { return ( <Dialog open={open} onOpenChange={onClose}> - <DialogContent className="border-border bg-primary-background max-w-[500px]"> + <DialogContent className="max-w-[500px] border-border bg-primary-background"> <DialogHeader> <DialogTitle className="text-left">Create a token</DialogTitle> </DialogHeader> diff --git a/packages/playground/src/components/project-settings/members-list.tsx b/packages/playground/src/components/project-settings/members-list.tsx index 2cb76c47a..516f70c87 100644 --- a/packages/playground/src/components/project-settings/members-list.tsx +++ b/packages/playground/src/components/project-settings/members-list.tsx @@ -82,23 +82,23 @@ export const MembersList = ({ members, onDelete, onEdit }: PageProps) => { <SelectContent className="w-[300px]"> <SelectItem value="Owner"> <Text className="inline-block w-full text-left">Owner</Text> - <Text className="text-muted-foreground mt-1.5 inline-block w-full"> + <Text className="mt-1.5 inline-block w-full text-muted-foreground"> Admin-level access to all resources. </Text> </SelectItem> <SelectItem value="Contributor"> <Text className="inline-block w-full text-left">Contributor</Text> - <Text className="text-muted-foreground mt-1.5 inline-block w-full"> + <Text className="mt-1.5 inline-block w-full text-muted-foreground"> Can view, comment, and edit resources. </Text> </SelectItem> <SelectItem value="Reader"> <Text className="inline-block w-full text-left">Reader</Text> - <Text className="text-muted-foreground mt-1.5 inline-block w-full">Can view and comment.</Text> + <Text className="mt-1.5 inline-block w-full text-muted-foreground">Can view and comment.</Text> </SelectItem> <SelectItem value="Executor"> <Text className="inline-block w-full text-left">Executor</Text> - <Text className="text-muted-foreground mt-1.5 inline-block w-full"> + <Text className="mt-1.5 inline-block w-full text-muted-foreground"> Can view but cannot make changes or leave comments. </Text> </SelectItem> diff --git a/packages/playground/src/components/project-settings/moreActionsDropdown.tsx b/packages/playground/src/components/project-settings/moreActionsDropdown.tsx index 5175f89bc..5bee768e2 100644 --- a/packages/playground/src/components/project-settings/moreActionsDropdown.tsx +++ b/packages/playground/src/components/project-settings/moreActionsDropdown.tsx @@ -20,11 +20,11 @@ export const moreActionsDropdown = ({ member, onDelete }: moreActionsProps) => { <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" size="xs"> - <Icon name="vertical-ellipsis" size={14} className="text-tertiary-background cursor-pointer" /> + <Icon name="vertical-ellipsis" size={14} className="cursor-pointer text-tertiary-background" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent - className="bg-primary-background w-[180px] rounded-[10px] border border-gray-800 py-2 shadow-sm" + className="w-[180px] rounded-[10px] border border-gray-800 bg-primary-background py-2 shadow-sm" onCloseAutoFocus={event => event.preventDefault()} // Prevent focus on hidden content > <DropdownMenuGroup> diff --git a/packages/playground/src/components/pull-request/pull-request-commits.tsx b/packages/playground/src/components/pull-request/pull-request-commits.tsx index b723725a1..de84f2a7f 100644 --- a/packages/playground/src/components/pull-request/pull-request-commits.tsx +++ b/packages/playground/src/components/pull-request/pull-request-commits.tsx @@ -48,7 +48,7 @@ export const PullRequestCommits = ({ ...props }: CommitProps) => { <div className="flex flex-col"> <div className="max-w-[500px] truncate">{commit.title}</div> <div className="flex items-center pt-1"> - <div className="bg-tertiary-background size-5 rounded-full bg-cover"> + <div className="size-5 rounded-full bg-tertiary-background bg-cover"> <Avatar className="size-5 rounded-full p-0"> <AvatarFallback> <Text size={1} color="tertiaryBackground"> @@ -58,7 +58,7 @@ export const PullRequestCommits = ({ ...props }: CommitProps) => { </AvatarFallback> </Avatar> </div> - <Text className="text-tertiary-background pl-2 text-xs">{`${commit.author?.identity?.name} commited on ${date}`}</Text> + <Text className="pl-2 text-xs text-tertiary-background">{`${commit.author?.identity?.name} commited on ${date}`}</Text> </div> </div> } diff --git a/packages/playground/src/components/pull-request/pull-request-conversation-header.tsx b/packages/playground/src/components/pull-request/pull-request-conversation-header.tsx index 48df4fa09..e27acb30a 100644 --- a/packages/playground/src/components/pull-request/pull-request-conversation-header.tsx +++ b/packages/playground/src/components/pull-request/pull-request-conversation-header.tsx @@ -53,11 +53,11 @@ export const PullRequestHeader: React.FC<PullRequestTitleProps> = ({ <Text size={5} weight={'medium'} className="text-primary"> {original} - <span className="text-tertiary-background font-normal">#{number}</span> + <span className="font-normal text-tertiary-background">#{number}</span> </Text> </div> <div className=""> - <div className="text-tertiary-background flex space-x-2"> + <div className="flex space-x-2 text-tertiary-background"> <div className="flex items-center gap-2.5 text-center align-middle"> <Badge disableHover borderRadius="full" theme={stateObject.theme} className={`select-none justify-center`}> <Layout.Horizontal gap="space-x-1" className="flex items-center align-middle"> @@ -68,7 +68,7 @@ export const PullRequestHeader: React.FC<PullRequestTitleProps> = ({ <div className="flex gap-2"> <Text size={2} - className="text-tertiary-background inline-flex flex-wrap items-center gap-1" + className="inline-flex flex-wrap items-center gap-1 text-tertiary-background" weight="normal" > <span className="text-primary">{author?.display_name || author?.email || ''}</span> @@ -78,12 +78,12 @@ export const PullRequestHeader: React.FC<PullRequestTitleProps> = ({ </span> <span>into</span> <Button variant="secondary" size="xs"> - <Icon name="branch" size={12} className="text-tertiary-background mr-1" /> + <Icon name="branch" size={12} className="mr-1 text-tertiary-background" /> {target_branch} </Button> <span>from</span> <Button variant="secondary" size="xs"> - <Icon name="branch" size={12} className="text-tertiary-background mr-1" /> + <Icon name="branch" size={12} className="mr-1 text-tertiary-background" /> {source_branch} </Button> <span> | </span> diff --git a/packages/playground/src/components/pull-request/pull-request-diff-viewer.tsx b/packages/playground/src/components/pull-request/pull-request-diff-viewer.tsx index fe28b0592..456ed8576 100644 --- a/packages/playground/src/components/pull-request/pull-request-diff-viewer.tsx +++ b/packages/playground/src/components/pull-request/pull-request-diff-viewer.tsx @@ -220,7 +220,7 @@ const PullRequestDiffViewer = ({ {diffFileInstance && !renderCustomContent && ( <DiffView<string> ref={ref} - className="bg-tr text-tertiary-background w-full" + className="bg-tr w-full text-tertiary-background" // renderWidgetLine={({ onClose }) => { // console.log('render widget') // return <></> @@ -274,7 +274,7 @@ const PullRequestDiffViewer = ({ <Card className="rounded-md bg-transparent"> <div className="flex flex-col p-4"> <div className="flex items-center space-x-2"> - <div className='bg-tertiary-background size-6 rounded-full bg-[url("../images/user-avatar.svg")] bg-cover'></div> + <div className='size-6 rounded-full bg-tertiary-background bg-[url("../images/user-avatar.svg")] bg-cover'></div> <Text color="primary">adam </Text> <Text size={1} color="tertiaryBackground"> 4 hours ago @@ -285,7 +285,7 @@ const PullRequestDiffViewer = ({ </Text> </div> <div className="flex items-center gap-3 border-t p-4"> - <div className='bg-tertiary-background size-6 rounded-full bg-[url("../images/user-avatar.svg")] bg-cover'></div> + <div className='size-6 rounded-full bg-tertiary-background bg-[url("../images/user-avatar.svg")] bg-cover'></div> <Input placeholder={'Reply here'} /> </div> </Card> diff --git a/packages/playground/src/components/pull-request/pull-request-panel.tsx b/packages/playground/src/components/pull-request/pull-request-panel.tsx index f8ca2dcd5..78aa61edf 100644 --- a/packages/playground/src/components/pull-request/pull-request-panel.tsx +++ b/packages/playground/src/components/pull-request/pull-request-panel.tsx @@ -79,12 +79,12 @@ const HeaderTitle = ({ ...props }: HeaderProps) => { <Text className="items-center gap-2 space-x-2" weight="medium"> <Text>{`${props?.pullReqMetadata?.merger?.display_name} merged branch`}</Text> <Button variant="secondary" size="xs"> - <Icon name="branch" size={12} className="text-tertiary-background mr-1" /> + <Icon name="branch" size={12} className="mr-1 text-tertiary-background" /> {props?.pullReqMetadata?.source_branch} </Button> <Text>{'into'}</Text> <Button variant="secondary" size="xs"> - <Icon name="branch" size={12} className="text-tertiary-background mr-1" /> + <Icon name="branch" size={12} className="mr-1 text-tertiary-background" /> {props?.pullReqMetadata?.target_branch} </Button> <Text>{formattedTime}</Text> diff --git a/packages/playground/src/components/pull-request/pull-request-side-bar.tsx b/packages/playground/src/components/pull-request/pull-request-side-bar.tsx index 99f94e34e..f17ea8f18 100644 --- a/packages/playground/src/components/pull-request/pull-request-side-bar.tsx +++ b/packages/playground/src/components/pull-request/pull-request-side-bar.tsx @@ -162,7 +162,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => { </Text> <Popover open={isOpen} onOpenChange={setIsOpen}> <PopoverTrigger asChild> - <Button size="sm" variant="ghost" className="text-tertiary-background px-2 py-1"> + <Button size="sm" variant="ghost" className="px-2 py-1 text-tertiary-background"> <Icon name="vertical-ellipsis" size={12} /> </Button> </PopoverTrigger> diff --git a/packages/playground/src/components/pull-request/pull-request-status-select-button.tsx b/packages/playground/src/components/pull-request/pull-request-status-select-button.tsx index 7233868b0..c965bdb16 100644 --- a/packages/playground/src/components/pull-request/pull-request-status-select-button.tsx +++ b/packages/playground/src/components/pull-request/pull-request-status-select-button.tsx @@ -3,8 +3,7 @@ import { memo, useEffect, useMemo, useState } from 'react' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@harnessio/canary' import { useEmitCodeCommentStatus } from './hooks/useEmitCodeCommentStatus' -import type { CommentItem, TypesPullReq, TypesPullReqActivity } from './interfaces' -import { CodeCommentState } from './interfaces' +import { CodeCommentState, type CommentItem, type TypesPullReq, type TypesPullReqActivity } from './interfaces' interface CodeCommentStatusSelectProps { comment: { commentItems: CommentItem<TypesPullReqActivity>[] } diff --git a/packages/playground/src/components/pull-request/sections/pull-request-changes-section.tsx b/packages/playground/src/components/pull-request/sections/pull-request-changes-section.tsx index d4d381896..6729fb0a5 100644 --- a/packages/playground/src/components/pull-request/sections/pull-request-changes-section.tsx +++ b/packages/playground/src/components/pull-request/sections/pull-request-changes-section.tsx @@ -258,7 +258,7 @@ const PullRequestChangesSection = ({ </div> )} <div className="rounded-full border bg-transparent"> - <Text className="text-tertiary-background px-2 py-1.5 text-xs">required</Text> + <Text className="px-2 py-1.5 text-xs text-tertiary-background">required</Text> </div> </div> </div> @@ -283,7 +283,7 @@ const PullRequestChangesSection = ({ </div> )} <div className="rounded-full border bg-transparent"> - <Text className="text-tertiary-background px-2 py-1.5 text-xs">required</Text> + <Text className="px-2 py-1.5 text-xs text-tertiary-background">required</Text> </div> </div> </div> @@ -304,7 +304,7 @@ const PullRequestChangesSection = ({ </Text> {reqNoChangeReq && ( <div className="rounded-full border bg-transparent"> - <Text className="text-tertiary-background px-2 py-1.5 text-xs">required</Text> + <Text className="px-2 py-1.5 text-xs text-tertiary-background">required</Text> </div> )} </div> @@ -329,7 +329,7 @@ const PullRequestChangesSection = ({ )} {(reqCodeOwnerApproval || reqCodeOwnerLatestApproval) && ( <div className="rounded-full border bg-transparent"> - <Text className="text-tertiary-background px-2 py-1.5 text-xs">required</Text> + <Text className="px-2 py-1.5 text-xs text-tertiary-background">required</Text> </div> )} </div> @@ -342,7 +342,7 @@ const PullRequestChangesSection = ({ <StackedList.Item isHeader disableHover - className="text-tertiary-background cursor-default !bg-transparent px-0" + className="cursor-default !bg-transparent px-0 text-tertiary-background" > <StackedList.Field title={<HeaderItem header="Code" />} /> <StackedList.Field title={<HeaderItem header="Owners" />} /> diff --git a/packages/playground/src/components/repo-clone/clone-repo-dialog.tsx b/packages/playground/src/components/repo-clone/clone-repo-dialog.tsx index c40487dfb..e4bf98fb6 100644 --- a/packages/playground/src/components/repo-clone/clone-repo-dialog.tsx +++ b/packages/playground/src/components/repo-clone/clone-repo-dialog.tsx @@ -18,7 +18,7 @@ export const CloneRepoDialog: React.FC<CloneRepoDialogProps> = ({ httpsUrl, sshU <PopoverTrigger asChild> <Button variant="default">Clone repository</Button> </PopoverTrigger> - <PopoverContent className="border-border bg-primary-background min-w-[400px]" side="bottom" align="end"> + <PopoverContent className="min-w-[400px] border-border bg-primary-background" side="bottom" align="end"> <Text className="mb-2 text-left text-lg">Git clone URL</Text> <Tabs variant="underline" value={currentTab} onValueChange={setCurrentTab} className="mb-2"> <TabsList> diff --git a/packages/playground/src/components/repo-clone/clone-repo-form.tsx b/packages/playground/src/components/repo-clone/clone-repo-form.tsx index 17981015f..1781532d3 100644 --- a/packages/playground/src/components/repo-clone/clone-repo-form.tsx +++ b/packages/playground/src/components/repo-clone/clone-repo-form.tsx @@ -56,7 +56,7 @@ export const CloneRepoForm: React.FC<CloneRepoFormProps> = ({ httpsUrl, sshUrl, </Button> <div className="flex items-center"> <Icon name="x-mark" size={15} className="text-tertiary-background" /> - <Text size={1} className="text-tertiary-background ml-1"> + <Text size={1} className="ml-1 text-tertiary-background"> Please generate a clone credential if its your first time. </Text> </div> diff --git a/packages/playground/src/components/repo-create-form.tsx b/packages/playground/src/components/repo-create-form.tsx index 10f0e6473..596034796 100644 --- a/packages/playground/src/components/repo-create-form.tsx +++ b/packages/playground/src/components/repo-create-form.tsx @@ -107,7 +107,7 @@ const RepoCreatePageForm: React.FC<RepoCreatePageFormProps> = ({ Create a new repository </Text> <Spacer size={3} /> - <Text size={2} as="p" className="text-primary/80 max-w-full"> + <Text size={2} as="p" className="max-w-full text-primary/80"> A repository contains all project files, including the revision history. Already have a project repository elsewhere? Import a repository. </Text> diff --git a/packages/playground/src/components/repo-list.tsx b/packages/playground/src/components/repo-list.tsx index 9355cb369..5bf423b24 100644 --- a/packages/playground/src/components/repo-list.tsx +++ b/packages/playground/src/components/repo-list.tsx @@ -1,6 +1,7 @@ import { Badge, Icon, StackedList } from '@harnessio/canary' -import { NoData } from './no-data' + import { Repository } from '../types/repository' +import { NoData } from './no-data' export interface PageProps { repos?: Repository[] @@ -13,11 +14,11 @@ const Stats = ({ stars, pulls }: { stars?: number; pulls: number }) => ( <div className="flex select-none items-center justify-end gap-3 font-medium"> <span className="flex items-center gap-1"> <Icon width={16} name="star" className="text-tertiary-background" /> - <span className="text-primary text-xs font-normal">{stars || 0}</span> + <span className="text-xs font-normal text-primary">{stars || 0}</span> </span> <span className="flex items-center gap-1"> <Icon size={16} name="pull" className="text-tertiary-background" /> - <span className="text-primary text-xs font-normal">{pulls || 0}</span> + <span className="text-xs font-normal text-primary">{pulls || 0}</span> </span> </div> ) diff --git a/packages/playground/src/components/repo-settings/repo-branch-settings-rules/repo-branch-settings-rules-fields.tsx b/packages/playground/src/components/repo-settings/repo-branch-settings-rules/repo-branch-settings-rules-fields.tsx index 79fd1c86d..c08d816e8 100644 --- a/packages/playground/src/components/repo-settings/repo-branch-settings-rules/repo-branch-settings-rules-fields.tsx +++ b/packages/playground/src/components/repo-settings/repo-branch-settings-rules/repo-branch-settings-rules-fields.tsx @@ -22,8 +22,15 @@ import { import { FormFieldSet, MessageTheme } from '../../../index' import { branchRules } from './repo-branch-settings-rules-data' -import type { FieldProps, Rule, Dispatch, BypassUsersList, MergeStrategy } from './types' -import { BranchRulesActionType, PatternsButtonType } from './types' +import { + BranchRulesActionType, + PatternsButtonType, + type BypassUsersList, + type Dispatch, + type FieldProps, + type MergeStrategy, + type Rule +} from './types' export const BranchSettingsRuleToggleField: React.FC<FieldProps> = ({ register, watch, setValue }) => ( <StackedList.Root className="border-none"> diff --git a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-delete.tsx b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-delete.tsx index efc13d2f3..a28141cdb 100644 --- a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-delete.tsx +++ b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-delete.tsx @@ -12,7 +12,7 @@ export const RepoSettingsGeneralDelete: React.FC<{ <Text size={4} weight="medium"> Delete Repository </Text> - <Text size={2} as="p" className="text-primary/80 max-w-full"> + <Text size={2} as="p" className="max-w-full text-primary/80"> This will permanently delete this repository, and everything contained in it.{' '} </Text> diff --git a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-rules.tsx b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-rules.tsx index d73694a68..4c61b279b 100644 --- a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-rules.tsx +++ b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-rules.tsx @@ -27,16 +27,16 @@ const Description = ({ return ( // <div className="pl-[24px]"> <Text color="tertiaryBackground" as="div" className="flex items-center gap-1 pl-[24px]"> - {targetPatternsCount} target patterns <span className="text-tertiary text-2xl">|</span> {rulesAppliedCount} rules - applied <span className="text-tertiary text-2xl">|</span> + {targetPatternsCount} target patterns <span className="text-2xl text-tertiary">|</span> {rulesAppliedCount} rules + applied <span className="text-2xl text-tertiary">|</span> {bypassAllowed ? ( <div> - <Icon name="tick" className="text-success inline" size={12} /> + <Icon name="tick" className="inline text-success" size={12} /> <span> bypass allowed</span> </div> ) : ( <div> - <Icon name="x-mark" className="text-destructive inline" size={12} /> + <Icon name="x-mark" className="inline text-destructive" size={12} /> <span> bypass not allowed</span> </div> )} diff --git a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-tooltip.tsx b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-tooltip.tsx index 05bde2c32..270cdfd0e 100644 --- a/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-tooltip.tsx +++ b/packages/playground/src/components/repo-settings/repo-settings-general/repo-settings-general-tooltip.tsx @@ -23,7 +23,7 @@ export const RepoSettingsToolTip = ({ <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" size="xs"> - <Icon name="vertical-ellipsis" size={14} className="text-tertiary-background cursor-pointer" /> + <Icon name="vertical-ellipsis" size={14} className="cursor-pointer text-tertiary-background" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent> @@ -42,14 +42,14 @@ export const RepoSettingsToolTip = ({ </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem - className="text-destructive cursor-pointer" + className="cursor-pointer text-destructive" onClick={e => { e.stopPropagation() onDelete(identifier) }} > <DropdownMenuShortcut className="ml-0"> - <Icon name="trash" className="text-destructive mr-2" /> + <Icon name="trash" className="mr-2 text-destructive" /> </DropdownMenuShortcut> Delete rule </DropdownMenuItem> diff --git a/packages/playground/src/components/settings-create-new-user-form.tsx b/packages/playground/src/components/settings-create-new-user-form.tsx index 8e06fb320..d4a561de3 100644 --- a/packages/playground/src/components/settings-create-new-user-form.tsx +++ b/packages/playground/src/components/settings-create-new-user-form.tsx @@ -64,8 +64,8 @@ function SettingsCreateNewUserForm({ <FormFieldSet.Label htmlFor="memberName" required> User ID </FormFieldSet.Label> - <Icon name="x-mark" className="text-tertiary-background ml-3" /> - <Text size={1} className="text-tertiary-background ml-1"> + <Icon name="x-mark" className="ml-3 text-tertiary-background" /> + <Text size={1} className="ml-1 text-tertiary-background"> User ID cannot be changed once created </Text> </span> diff --git a/packages/playground/src/components/settings-menu.tsx b/packages/playground/src/components/settings-menu.tsx index 7079752f4..5916f6b47 100644 --- a/packages/playground/src/components/settings-menu.tsx +++ b/packages/playground/src/components/settings-menu.tsx @@ -1,41 +1,47 @@ -import { Icon, Navbar, Sheet, SheetContent, Spacer, SheetTitle } from '@harnessio/canary' import { NavLink } from 'react-router-dom' -import { settingsMenuData } from '../data/mockSystemAsminMenuData' + +import { Icon, Navbar, ScrollArea, Sheet, SheetContent, SheetTitle, Spacer } from '@harnessio/canary' + +import { MenuGroupType } from './navbar/types' interface SystemAdminMenuProps { - showSystemAdmin: boolean - handleSystemAdmin: () => void + showSettingMenu: boolean + handleSettingsMenu: () => void + items: MenuGroupType[] } -export const SettingsMenu = ({ showSystemAdmin, handleSystemAdmin }: SystemAdminMenuProps) => { +export const SettingsMenu = ({ showSettingMenu, handleSettingsMenu, items }: SystemAdminMenuProps) => { return ( - <Sheet modal={false} open={showSystemAdmin}> + <Sheet modal={false} open={showSettingMenu}> <SheetContent className="inset-y-0 left-[220px] z-40 h-screen w-[364px] bg-transparent p-0" side="left" - onClick={handleSystemAdmin} - modal={false}> + onClick={handleSettingsMenu} + modal={false} + > <SheetTitle className="sr-only">System Administration menu</SheetTitle> <Navbar.Root className="w-[364px]" isSubMenu> - <Navbar.Content> - <Spacer size={9} /> - {settingsMenuData.map((group, group_idx) => ( - <Navbar.Group key={group.groupId} topBorder={group_idx > 0} title={group.title} titleClassName="mb-1.5"> - <div className="grid grid-cols-2 gap-x-6 gap-y-[0.6875rem]"> - {group.items.map(item => ( - <NavLink key={item.id} to={item.to || ''}> - {({ isActive }) => ( - <Navbar.Item - text={item.title || ''} - icon={<Icon name={item.iconName} size={12} />} - active={isActive} - /> - )} - </NavLink> - ))} - </div> - </Navbar.Group> - ))} + <Navbar.Content className="overflow-hidden"> + <ScrollArea> + <Spacer size={9} /> + {items.map((group, group_idx) => ( + <Navbar.Group key={group.groupId} topBorder={group_idx > 0} title={group.title} titleClassName="mb-1.5"> + <div className="grid grid-cols-2 gap-x-6 gap-y-[0.6875rem]"> + {group.items.map(item => ( + <NavLink key={item.id} to={item.to || ''}> + {({ isActive }) => ( + <Navbar.Item + text={item.title || ''} + icon={<Icon name={item.iconName} size={12} />} + active={isActive} + /> + )} + </NavLink> + ))} + </div> + </Navbar.Group> + ))} + </ScrollArea> </Navbar.Content> </Navbar.Root> </SheetContent> diff --git a/packages/playground/src/components/sha-badge.tsx b/packages/playground/src/components/sha-badge.tsx index 064ecc30f..4f450ba8a 100644 --- a/packages/playground/src/components/sha-badge.tsx +++ b/packages/playground/src/components/sha-badge.tsx @@ -30,7 +30,7 @@ function Content({ ...props }: ContentProps) { const { children } = props return ( - <div className="bg-background hover:bg-muted/50 flex items-center px-2 py-0.5"> + <div className="flex items-center bg-background px-2 py-0.5 hover:bg-muted/50"> <Text size={1} className="text-tertiary-background"> {children} </Text> @@ -46,7 +46,7 @@ function Icon({ ...props }: IconProps) { onClick={handleClick && handleClick} role="button" tabIndex={0} - className="bg-background hover:bg-muted/50 flex items-center border-l px-1.5 py-0.5" + className="flex items-center border-l bg-background px-1.5 py-0.5 hover:bg-muted/50" > {children} </div> diff --git a/packages/playground/src/components/steps/harness-steps.ts b/packages/playground/src/components/steps/harness-steps.ts index 5af447c42..ebaccb174 100644 --- a/packages/playground/src/components/steps/harness-steps.ts +++ b/packages/playground/src/components/steps/harness-steps.ts @@ -11,13 +11,13 @@ import { BACKGROUND_STEP_IDENTIFIER, BARRIER_STEP_IDENTIFIER, GROUP_IDENTIFIER, - HARNESS_STEP_IDENTIFIER, - HarnessStep, - HarnessStepGroup, PARALLEL_IDENTIFIER, QUEUE_STEP_IDENTIFIER, RUN_STEP_IDENTIFIER, - RUN_TEST_STEP_IDENTIFIER + RUN_TEST_STEP_IDENTIFIER, + type HARNESS_STEP_IDENTIFIER, + type HarnessStep, + type HarnessStepGroup } from './types' export const harnessSteps: HarnessStep[] = [ diff --git a/packages/playground/src/components/user-management/form-user-edit-dialog.tsx b/packages/playground/src/components/user-management/form-user-edit-dialog.tsx index 0b7c49971..5ea405a0f 100644 --- a/packages/playground/src/components/user-management/form-user-edit-dialog.tsx +++ b/packages/playground/src/components/user-management/form-user-edit-dialog.tsx @@ -73,9 +73,9 @@ export const FormUserEditDialog: React.FC<FormEditDialogProps> = ({ {/* User ID */} <FormFieldSet.ControlGroup> <FormFieldSet.Label className="flex content-center items-center" htmlFor="userID" required> - <Text className="text-primary/80 font-normal">User ID</Text> - <Icon name="x-mark" className="text-tertiary-background ml-3" /> - <Text size={1} className="text-tertiary-background ml-1"> + <Text className="font-normal text-primary/80">User ID</Text> + <Icon name="x-mark" className="ml-3 text-tertiary-background" /> + <Text size={1} className="ml-1 text-tertiary-background"> User ID cannot be changed once created </Text> </FormFieldSet.Label> diff --git a/packages/playground/src/components/user-management/users-list.tsx b/packages/playground/src/components/user-management/users-list.tsx index 7edff75fe..b6797a992 100644 --- a/packages/playground/src/components/user-management/users-list.tsx +++ b/packages/playground/src/components/user-management/users-list.tsx @@ -45,7 +45,7 @@ export const UsersList = ({ users, onDelete, onEdit, onRemoveAdmin, onResetPassw </Button> </DropdownMenuTrigger> <DropdownMenuContent - className="bg-primary-background w-[180px] rounded-[10px] border border-gray-800 py-2 shadow-sm" + className="w-[180px] rounded-[10px] border border-gray-800 bg-primary-background py-2 shadow-sm" onCloseAutoFocus={event => event.preventDefault()} > <DropdownMenuGroup> @@ -107,7 +107,7 @@ export const UsersList = ({ users, onDelete, onEdit, onRemoveAdmin, onResetPassw <TableHead className="text-primary">Name</TableHead> <TableHead className="text-primary">Email</TableHead> <TableHead className="text-primary">Display Name</TableHead> - <TableHead className="text-primary text-right">Date added</TableHead> + <TableHead className="text-right text-primary">Date added</TableHead> <TableHead> <></> </TableHead> @@ -131,7 +131,7 @@ export const UsersList = ({ users, onDelete, onEdit, onRemoveAdmin, onResetPassw <Badge variant="outline" size="xs" - className="bg-tertiary-background/10 text-tertiary-background m-auto ml-2 h-5 rounded-full p-2 text-center text-xs font-normal" + className="m-auto ml-2 h-5 rounded-full bg-tertiary-background/10 p-2 text-center text-xs font-normal text-tertiary-background" > Admin </Badge> diff --git a/packages/playground/src/components/users-list.tsx b/packages/playground/src/components/users-list.tsx index ecbf154fd..5aea1a5aa 100644 --- a/packages/playground/src/components/users-list.tsx +++ b/packages/playground/src/components/users-list.tsx @@ -35,7 +35,7 @@ export const UsersList = ({ users }: PageProps) => { <TableHead className="text-primary">Name</TableHead> <TableHead className="text-primary">Role</TableHead> <TableHead className="text-primary">Email</TableHead> - <TableHead className="text-primary text-right">Date added</TableHead> + <TableHead className="text-right text-primary">Date added</TableHead> <TableHead> <></> </TableHead> @@ -61,7 +61,7 @@ export const UsersList = ({ users }: PageProps) => { <Badge variant="outline" size="xs" - className="bg-tertiary-background/10 text-tertiary-background m-auto ml-2 h-5 rounded-full p-2 text-center text-xs font-normal" + className="m-auto ml-2 h-5 rounded-full bg-tertiary-background/10 p-2 text-center text-xs font-normal text-tertiary-background" > {user.role} </Badge> diff --git a/packages/playground/src/components/webhook-list.tsx b/packages/playground/src/components/webhook-list.tsx index 9086ef06e..9e449b489 100644 --- a/packages/playground/src/components/webhook-list.tsx +++ b/packages/playground/src/components/webhook-list.tsx @@ -50,7 +50,7 @@ const Title = ({ title, enabled }: { title: string; enabled: boolean }) => { </Text> </Badge> ) : ( - <Badge variant="outline" size="xs" className="text-tertiary-background rounded-full"> + <Badge variant="outline" size="xs" className="rounded-full text-tertiary-background"> <Text size={1} className="text-inherit"> {WebhookState.DISABLED} </Text> @@ -65,7 +65,7 @@ const Action = ({ id, openDeleteWebhookDialog }: { id: number; openDeleteWebhook <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" size="xs"> - <Icon name="vertical-ellipsis" size={14} className="text-tertiary-background cursor-pointer" /> + <Icon name="vertical-ellipsis" size={14} className="cursor-pointer text-tertiary-background" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent> @@ -85,14 +85,14 @@ const Action = ({ id, openDeleteWebhookDialog }: { id: number; openDeleteWebhook </Link> <DropdownMenuSeparator /> <DropdownMenuItem - className="text-destructive cursor-pointer" + className="cursor-pointer text-destructive" onClick={e => { e.stopPropagation() openDeleteWebhookDialog(id) }} > <DropdownMenuShortcut className="ml-0"> - <Icon name="trash" className="text-destructive mr-2" /> + <Icon name="trash" className="mr-2 text-destructive" /> </DropdownMenuShortcut> Delete webhook </DropdownMenuItem> diff --git a/packages/playground/src/components/webhooks/create-webhook-form-data.ts b/packages/playground/src/components/webhooks/create-webhook-form-data.ts index 7a61b021c..82213fe61 100644 --- a/packages/playground/src/components/webhooks/create-webhook-form-data.ts +++ b/packages/playground/src/components/webhooks/create-webhook-form-data.ts @@ -1,5 +1,4 @@ -import type { WebhookEvent } from './types' -import { WebhookTriggerEnum } from './types' +import { WebhookTriggerEnum, type WebhookEvent } from './types' export const branchEvents: WebhookEvent[] = [ { id: WebhookTriggerEnum.BRANCH_CREATED, event: 'Branch created' }, diff --git a/packages/playground/src/data/mockNavbarMenuData.ts b/packages/playground/src/data/mockNavbarMenuData.ts new file mode 100644 index 000000000..3704a7913 --- /dev/null +++ b/packages/playground/src/data/mockNavbarMenuData.ts @@ -0,0 +1,337 @@ +import { MenuGroupType, MenuGroupTypes } from '../components/navbar/types' + +export const navbarMenuData: MenuGroupType[] = [ + { + groupId: 0, + title: 'Devops', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 0, + iconName: 'repositories-gradient', + title: 'Repositories', + description: 'Integrated & familiar git experience.', + to: '/repos' + }, + { + id: 1, + iconName: 'pipelines-gradient', + title: 'Pipelines', + description: 'Up to 4X faster than other solutions.', + to: '/pipelines' + }, + { + id: 2, + iconName: 'execution-gradient', + title: 'Executions', + description: 'Optimize feature rollout velocity.', + to: '/executions' + }, + { + id: 3, + iconName: 'database-gradient', + title: 'Databases', + description: 'Manage all your infrastructure.', + to: '/databases' + }, + { + id: 4, + iconName: 'artifacts-gradient', + title: 'Artifacts', + description: 'Validate service resilience.', + to: '/sandbox/executions/artifacts' + }, + { + id: 5, + iconName: 'infrastructure-gradient', + title: 'Infrastructure', + description: 'Manage all your infrastructure.', + to: '/infrastructure' + }, + { + id: 6, + iconName: 'flag-gradient', + title: 'Feature Flags', + description: 'Optimize feature rollout velocity.', + to: '/feature-flags' + } + ] + }, + { + groupId: 1, + title: 'Devex', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 7, + iconName: 'dev-portal-gradient', + title: 'Developer Portal', + description: 'Built for developers, onboard in minutes.', + to: '/developer/portal' + }, + { + id: 8, + iconName: 'dev-envs-gradient', + title: 'Developer Environments', + description: 'Integrated & familiar git experience.', + to: '/developer/environments' + }, + { + id: 9, + iconName: 'dev-insights-gradient', + title: 'Developer Insights', + description: 'Actionable insights on SDLC.', + to: '/developer/insights' + } + ] + }, + { + groupId: 2, + title: 'Secops', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 10, + iconName: 'security-tests-gradient', + title: 'Security Tests', + description: 'Shift left security testing.', + to: '/sandbox/executions/security-tests' + }, + { + id: 11, + iconName: 'supply-chain-gradient', + title: 'Supply Chain', + description: 'Artifact integrity and governance.', + to: '/supply-chain' + } + ] + }, + { + groupId: 3, + title: 'Finops', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 12, + iconName: 'cloud-costs-gradient', + title: 'Cloud Costs', + description: 'Intelligent cost management.', + to: '/cloud-costs' + } + ] + }, + { + groupId: 4, + title: 'Reliability', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 13, + iconName: 'incidents-gradient', + title: 'Incidents', + description: 'Shift left security testing.', + to: '/incidents' + }, + { + id: 14, + iconName: 'chaos-engineering-gradient', + title: 'Chaos Engineering', + description: 'Validate service resilience.', + to: '/chaos' + } + ] + }, + { + groupId: 5, + title: 'Platform', + type: MenuGroupTypes.GENERAL, + items: [ + { + id: 15, + iconName: 'dashboards-gradient', + title: 'Dashboards', + description: 'Intelligent cost management.', + to: '/dashboards' + } + ] + }, + { + groupId: 0, + title: 'General', + type: MenuGroupTypes.SETTINGS, + items: [ + { + id: 0, + iconName: 'settings-2', + title: 'Settings', + to: '/admin/default-settings' + }, + { + id: 1, + iconName: 'notification', + title: 'Notifications', + to: '/admin/notifications' + } + ] + }, + { + groupId: 1, + title: 'Resources', + type: MenuGroupTypes.SETTINGS, + items: [ + { + id: 2, + iconName: 'wrench', + title: 'Services', + to: '/admin/services' + }, + { + id: 3, + iconName: 'environment', + title: 'Environments', + to: '/admin/environments' + }, + { + id: 4, + iconName: 'connectors', + title: 'Connectors', + to: '/admin/connectors' + }, + { + id: 5, + iconName: 'hierarchy', + title: 'Delegates', + to: '/admin/delegates' + }, + { + id: 6, + iconName: 'key', + title: 'Secrets', + to: '/admin/secrets' + }, + { + id: 7, + iconName: 'file-icon', + title: 'File Store', + to: '/admin/filte-store' + }, + { + id: 8, + iconName: 'sidebar-icon', + title: 'Templates', + to: '/admin/templates' + }, + { + id: 9, + iconName: 'variable', + title: 'Variables', + to: '/admin/variables' + }, + { + id: 10, + iconName: 'clock-icon', + title: 'SLO Downtime', + to: '/admin/slo-downtime' + }, + { + id: 11, + iconName: 'search', + title: 'Discovery', + to: '/admin/discovery' + }, + { + id: 12, + iconName: 'eye', + title: 'Monitored Services', + to: '/admin/monitored-services' + }, + { + id: 13, + iconName: 'stack', + title: 'Overrides', + to: '/admin/overrides' + }, + { + id: 14, + iconName: 'bookmark-icon', + title: 'Certificates', + to: '/admin/certificates' + }, + { + id: 15, + iconName: 'webhook', + title: 'Webhooks', + to: '/admin/webhooks' + } + ] + }, + { + groupId: 2, + title: 'Access Control', + type: MenuGroupTypes.SETTINGS, + items: [ + { + id: 16, + iconName: 'user', + title: 'Users', + to: '/admin/users' + }, + { + id: 17, + iconName: 'users', + title: 'User Groups', + to: '/admin/users-group' + }, + { + id: 18, + iconName: 'account-icon', + title: 'Service Accounts', + to: '/admin/service-accounts' + }, + { + id: 19, + iconName: 'folder-icon', + title: 'Resource Groups', + to: '/admin/resource-groups' + }, + { + id: 20, + iconName: 'briefcase', + title: 'Roles', + to: '/admin/roles' + } + ] + }, + { + groupId: 3, + title: 'Security and Governance', + type: MenuGroupTypes.SETTINGS, + items: [ + { + id: 21, + iconName: 'shield', + title: 'Policies', + to: '/admin/policies' + }, + { + id: 22, + iconName: 'snow', + title: 'Freeze Windows', + to: '/admin/freeze-windows' + } + ] + }, + { + groupId: 4, + title: 'External Tickets', + type: MenuGroupTypes.SETTINGS, + items: [ + { + id: 23, + iconName: 'ticket', + title: 'External Tickets', + to: '/admin/external-tickets' + } + ] + } +] diff --git a/packages/playground/src/data/mockNavbarSubmenuData.ts b/packages/playground/src/data/mockNavbarSubmenuData.ts index 4d55b75f2..e69de29bb 100644 --- a/packages/playground/src/data/mockNavbarSubmenuData.ts +++ b/packages/playground/src/data/mockNavbarSubmenuData.ts @@ -1,122 +0,0 @@ -import type { IconProps } from '@harnessio/canary' - -export const navbarSubmenuData: { - groupId: number - title: string - items: { - id: number - iconName: IconProps['name'] - title: string - description: string - to: string - }[] -}[] = [ - { - groupId: 0, - title: 'DevOps Modernization', - items: [ - { - id: 0, - iconName: 'rocket', - title: 'Continuous Delivery & GitOps', - description: 'App to production with no scripts.', - to: '/continuous-delivery-gitops' - }, - { - id: 1, - iconName: 'plug', - title: 'Continuous Integration', - description: 'Up to 4X faster than other solutions.', - to: '/continuous-integration' - }, - { - id: 2, - iconName: 'flag', - title: 'Feature Flags', - description: 'Optimize feature rollout velocity.', - to: '/feature-flags' - }, - { - id: 3, - iconName: 'filter-organization', - title: 'Infrastructure as Code Management', - description: 'Manage all your infrastructure.', - to: '/infrastructure-as-code' - }, - { - id: 4, - iconName: 'chaos-engineering', - title: 'Chaos Engineering', - description: 'Validate service resilience.', - to: '/chaos-engineering' - }, - { - id: 5, - iconName: 'shield-lock', - title: 'Service Reliability Management', - description: 'SLO configuration and service reliability.', - to: '/service-reliability' - } - ] - }, - { - groupId: 1, - title: 'Developer Experience', - items: [ - { - id: 6, - iconName: 'more-folder', - title: 'Internal Developer Portal', - description: 'Built for developers, onboard in minutes.', - to: '/internal-developer-portal' - }, - { - id: 7, - iconName: 'bookmark', - title: 'Code Repository', - description: 'Integrated & familiar git experience.', - to: '/code-repository' - }, - { - id: 8, - iconName: 'search-content', - title: 'Software Engineering Insights', - description: 'Actionable insights on SDLC.', - to: '/software-engineering-insights' - } - ] - }, - { - groupId: 2, - title: 'Secure Software Delivery', - items: [ - { - id: 9, - iconName: 'chain', - title: 'Software Supply Chain Assurance', - description: 'Artifact integrity and governance.', - to: '/software-supply-chain-assurance' - }, - { - id: 10, - iconName: 'shield-tick', - title: 'Security Testing Orchestration', - description: 'Shift left security testing.', - to: '/security-testing-orchestration' - } - ] - }, - { - groupId: 3, - title: 'Cloud Cost Optimization', - items: [ - { - id: 11, - iconName: 'cloud-mining', - title: 'Cloud Cost Management', - description: 'Intelligent cost management.', - to: '/cloud-cost-management' - } - ] - } -] diff --git a/packages/playground/src/data/mockPinnedAndRecentMenuData.ts b/packages/playground/src/data/mockPinnedAndRecentMenuData.ts new file mode 100644 index 000000000..a388760d0 --- /dev/null +++ b/packages/playground/src/data/mockPinnedAndRecentMenuData.ts @@ -0,0 +1,48 @@ +import { NavbarItemType } from '../components/navbar/types' + +export const pinnedMenuItemsData: NavbarItemType[] = [ + { + id: 0, + iconName: 'repositories-gradient', + title: 'Repositories', + description: 'Integrated & familiar git experience.', + to: '/repos' + }, + { + id: 1, + iconName: 'pipelines-gradient', + title: 'Pipelines', + description: 'Up to 4X faster than other solutions.', + to: '/pipelines' + }, + { + id: 2, + iconName: 'execution-gradient', + title: 'Executions', + description: 'Optimize feature rollout velocity.', + to: '/executions' + } +] + +export const recentMenuItemsData: NavbarItemType[] = [ + { + id: 13, + iconName: 'incidents-gradient', + title: 'Incidents', + description: 'Shift left security testing.', + to: '/incidents' + }, + { + id: 15, + iconName: 'dashboards-gradient', + title: 'Dashboards', + description: 'Intelligent cost management.', + to: '/dashboards' + }, + { + id: 20, + iconName: 'briefcase', + title: 'Roles', + to: '/admin/roles' + } +] diff --git a/packages/playground/src/hooks/use-drag-and-drop.tsx b/packages/playground/src/hooks/use-drag-and-drop.tsx index b09727ca1..faf220520 100644 --- a/packages/playground/src/hooks/use-drag-and-drop.tsx +++ b/packages/playground/src/hooks/use-drag-and-drop.tsx @@ -1,4 +1,5 @@ import { useCallback } from 'react' + import { DragEndEvent } from '@dnd-kit/core' interface UseDragAndDropProps<T> { diff --git a/packages/playground/src/index.ts b/packages/playground/src/index.ts index a8b5a69d7..094b340fe 100644 --- a/packages/playground/src/index.ts +++ b/packages/playground/src/index.ts @@ -1,5 +1,5 @@ export * from './components/repo-summary-panel' -export * from './components/branch-chooser' +export * from './components/branch-selector/branch-selector' export * from './components/search-files' export * from './components/repo-summary' export * from './components/markdown-viewer' diff --git a/packages/playground/src/layouts/RepoExecutionLayout.tsx b/packages/playground/src/layouts/RepoExecutionLayout.tsx index ca09ce858..5ab147d53 100644 --- a/packages/playground/src/layouts/RepoExecutionLayout.tsx +++ b/packages/playground/src/layouts/RepoExecutionLayout.tsx @@ -25,7 +25,7 @@ const RepoExecutionLayout: React.FC = () => { <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> - <BreadcrumbLink className="text-primary font-medium" href="/"> + <BreadcrumbLink className="font-medium text-primary" href="/"> {repoId} </BreadcrumbLink> </BreadcrumbItem> diff --git a/packages/playground/src/layouts/RootLayout.tsx b/packages/playground/src/layouts/RootLayout.tsx index 4ecfec5c4..321f77fad 100644 --- a/packages/playground/src/layouts/RootLayout.tsx +++ b/packages/playground/src/layouts/RootLayout.tsx @@ -1,78 +1,154 @@ -import { useEffect, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import { Outlet, useLocation } from 'react-router-dom' +import { ManageNavigation } from '../components/manage-navigation' import { MoreSubmenu } from '../components/more-submenu' import { Navbar } from '../components/navbar' +import { MenuGroupType, MenuGroupTypes, NavbarItemType } from '../components/navbar/types' import { SettingsMenu } from '../components/settings-menu' +import { navbarMenuData } from '../data/mockNavbarMenuData' +import { pinnedMenuItemsData, recentMenuItemsData } from '../data/mockPinnedAndRecentMenuData' import { TypesUser } from './types' interface RootLayoutProps { currentUser: TypesUser | undefined } -export const RootLayout: React.FC<RootLayoutProps> = ({ currentUser }) => { +export const RootLayout = ({ currentUser }: RootLayoutProps) => { const location = useLocation() - const [showMore, setShowMore] = useState(false) - const [showSystemAdmin, setShowSystemAdmin] = useState(false) + const [recentMenuItems, setRecentMenuItems] = useState<NavbarItemType[]>(recentMenuItemsData) + const [pinnedMenuItems, setPinnedMenuItems] = useState<NavbarItemType[]>(pinnedMenuItemsData) + const [showMoreMenu, setShowMoreMenu] = useState(false) + const [showSettingMenu, setShowSettingMenu] = useState(false) + const [showCustomNav, setShowCustomNav] = useState(false) - const handleMore = () => { - setShowSystemAdmin(false) - setShowMore(prevState => !prevState) - } + /** + * Map mock data menu by type to Settings and More + */ + const { moreMenu, settingsMenu } = useMemo(() => { + return navbarMenuData.reduce<{ + moreMenu: MenuGroupType[] + settingsMenu: MenuGroupType[] + }>( + (acc, item) => { + if (item.type === MenuGroupTypes.SETTINGS) { + acc.settingsMenu.push(item) + } else { + acc.moreMenu.push(item) + } - const handleSystemAdmin = () => { - setShowMore(false) - setShowSystemAdmin(prevState => !prevState) - } + return acc + }, + { + moreMenu: [], + settingsMenu: [] + } + ) + }, []) + + // TODO: add log out func + const handleLogOut = useCallback(() => {}, []) + + /** + * Toggle show more menu + */ + const handleMoreMenu = useCallback(() => { + setShowSettingMenu(false) + setShowMoreMenu(prevState => !prevState) + }, []) + /** + * Toggle system settings menu + */ + const handleSettingsMenu = useCallback(() => { + setShowMoreMenu(false) + setShowSettingMenu(prevState => !prevState) + }, []) + + /** + * Toggle custom navigation modal + */ + const handleCustomNav = useCallback(() => { + setShowCustomNav(prevState => !prevState) + }, []) + + /** + * Close all menu when location changed + */ useEffect(() => { - setShowMore(false) - setShowSystemAdmin(false) + setShowMoreMenu(false) + setShowSettingMenu(false) + setShowCustomNav(false) }, [location]) - // const handlePinItem = (item: NavbarItem) => { - // setPinnedItems(prevPinnedItems => { - // const isPinned = prevPinnedItems.some(pinned => pinned.id === item.id) - // - // if (isPinned) { - // return prevPinnedItems.filter(pinned => pinned.id !== item.id) - // } - // - // const itemToPin = navbarSubmenuData.flatMap(group => group.items).find(i => i.id === item.id) - // - // if (itemToPin) { - // return [ - // { - // id: itemToPin.id, - // title: itemToPin.title, - // iconName: itemToPin.iconName, - // description: itemToPin.description, - // to: itemToPin.to || '' - // }, - // ...prevPinnedItems - // ] - // } - // - // return prevPinnedItems - // }) - // } + /** + * Handle save recent and pinned items + */ + const handleSave = (recentItems: NavbarItemType[], currentPinnedItems: NavbarItemType[]) => { + setRecentMenuItems(recentItems) + setPinnedMenuItems(currentPinnedItems) + } + + /** + * Remove recent menu item + */ + const handleRemoveRecentMenuItem = useCallback((item: NavbarItemType) => { + setRecentMenuItems(prevState => prevState.filter(prevStateItem => prevStateItem.id !== item.id)) + }, []) + + /** + * Change pinned menu items + */ + const handleChangePinnedMenuItem = useCallback( + (item: NavbarItemType) => { + setPinnedMenuItems(prevState => { + const isPinned = prevState.some(pinned => pinned.id === item.id) + + if (isPinned) { + return prevState.filter(pinned => pinned.id !== item.id) + } + + // If pin item, remove it from recent + handleRemoveRecentMenuItem(item) + + return [...prevState, item] + }) + }, + [handleRemoveRecentMenuItem] + ) return ( <> <div className="min-w-screen grid md:grid-cols-[220px_minmax(900px,_1fr)]"> <Navbar - showMore={showMore} - showSystemAdmin={showSystemAdmin} - handleMore={handleMore} - handleSystemAdmin={handleSystemAdmin} + showMoreMenu={showMoreMenu} + showSettingMenu={showSettingMenu} + handleMoreMenu={handleMoreMenu} + handleSettingsMenu={handleSettingsMenu} currentUser={currentUser} + handleCustomNav={handleCustomNav} + handleLogOut={handleLogOut} + recentMenuItems={recentMenuItems} + pinnedMenuItems={pinnedMenuItems} + handleChangePinnedMenuItem={handleChangePinnedMenuItem} + handleRemoveRecentMenuItem={handleRemoveRecentMenuItem} /> <main className="col-start-2 box-border min-h-screen overflow-x-hidden overflow-y-scroll"> <Outlet /> </main> </div> - <MoreSubmenu showMore={showMore} handleMore={handleMore} /> - <SettingsMenu showSystemAdmin={showSystemAdmin} handleSystemAdmin={handleSystemAdmin} /> + <MoreSubmenu showMoreMenu={showMoreMenu} handleMoreMenu={handleMoreMenu} items={moreMenu} /> + <SettingsMenu showSettingMenu={showSettingMenu} handleSettingsMenu={handleSettingsMenu} items={settingsMenu} /> + <ManageNavigation + pinnedItems={pinnedMenuItems} + recentItems={recentMenuItems} + navbarMenuData={navbarMenuData} + showManageNavigation={showCustomNav} + isSubmitting={false} + submitted={false} + onSave={handleSave} + onClose={handleCustomNav} + /> </> ) } diff --git a/packages/playground/src/layouts/SandboxPullRequestCompareLayout.tsx b/packages/playground/src/layouts/SandboxPullRequestCompareLayout.tsx index afade9fce..536bbfb19 100644 --- a/packages/playground/src/layouts/SandboxPullRequestCompareLayout.tsx +++ b/packages/playground/src/layouts/SandboxPullRequestCompareLayout.tsx @@ -124,7 +124,7 @@ const SandboxPullRequestCompare: React.FC<SandboxPullRequestCompareProps> = ({ Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks or learn more about diff comparisons. </Text> - <Layout.Horizontal className="text-tertiary-background items-center"> + <Layout.Horizontal className="items-center text-tertiary-background"> <Icon name="pull" size={16} className="text-tertiary-background" /> <BranchSelector @@ -137,7 +137,7 @@ const SandboxPullRequestCompare: React.FC<SandboxPullRequestCompareProps> = ({ handleBranchSelection() // Call when target branch is selected }} /> - <Icon name="arrow-long" size={14} className="text-tertiary-background rotate-180" /> + <Icon name="arrow-long" size={14} className="rotate-180 text-tertiary-background" /> <BranchSelector prefix="compare" size="default" @@ -185,7 +185,7 @@ const SandboxPullRequestCompare: React.FC<SandboxPullRequestCompareProps> = ({ </Layout.Horizontal> </Layout.Vertical> <Spacer size={3} /> - <Layout.Horizontal className="border-border bg-background items-center justify-between rounded-md border-2 p-3"> + <Layout.Horizontal className="items-center justify-between rounded-md border-2 border-border bg-background p-3"> <div> <Layout.Horizontal className="py-2"> {isBranchSelected ? ( diff --git a/packages/playground/src/layouts/SandboxRoot.tsx b/packages/playground/src/layouts/SandboxRoot.tsx index 631c7114e..edb13f9fb 100644 --- a/packages/playground/src/layouts/SandboxRoot.tsx +++ b/packages/playground/src/layouts/SandboxRoot.tsx @@ -1,44 +1,153 @@ -import { useState } from 'react' -import { Outlet } from 'react-router-dom' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { Outlet, useLocation } from 'react-router-dom' +import { ManageNavigation } from '../components/manage-navigation' import { MoreSubmenu } from '../components/more-submenu' import { Navbar } from '../components/navbar' +import { MenuGroupType, MenuGroupTypes, NavbarItemType } from '../components/navbar/types' import { SettingsMenu } from '../components/settings-menu' +import { navbarMenuData } from '../data/mockNavbarMenuData' +import { pinnedMenuItemsData, recentMenuItemsData } from '../data/mockPinnedAndRecentMenuData' import { SandboxLayout } from '../index' -import { TypesUser } from './types' +import type { TypesUser } from './types' interface SandboxRootProps { currentUser: TypesUser | undefined } export const SandboxRoot: React.FC<SandboxRootProps> = ({ currentUser }) => { - const [showMore, setShowMore] = useState(false) - const [showSystemAdmin, setShowSystemAdmin] = useState(false) + const location = useLocation() + const [recentMenuItems, setRecentMenuItems] = useState<NavbarItemType[]>(recentMenuItemsData) + const [pinnedMenuItems, setPinnedMenuItems] = useState<NavbarItemType[]>(pinnedMenuItemsData) + const [showMoreMenu, setShowMoreMenu] = useState(false) + const [showSettingMenu, setShowSettingMenu] = useState(false) + const [showCustomNav, setShowCustomNav] = useState(false) - const handleMore = () => { - setShowSystemAdmin(false) - setShowMore(prevState => !prevState) - } + /** + * Map mock data menu by type to Settings and More + */ + const { moreMenu, settingsMenu } = useMemo(() => { + return navbarMenuData.reduce<{ + moreMenu: MenuGroupType[] + settingsMenu: MenuGroupType[] + }>( + (acc, item) => { + if (item.type === MenuGroupTypes.SETTINGS) { + acc.settingsMenu.push(item) + } else { + acc.moreMenu.push(item) + } + + return acc + }, + { + moreMenu: [], + settingsMenu: [] + } + ) + }, []) + + // TODO: add log out func + const handleLogOut = useCallback(() => {}, []) + + /** + * Toggle show more menu + */ + const handleMoreMenu = useCallback(() => { + setShowSettingMenu(false) + setShowMoreMenu(prevState => !prevState) + }, []) + + /** + * Toggle system settings menu + */ + const handleSettingsMenu = useCallback(() => { + setShowMoreMenu(false) + setShowSettingMenu(prevState => !prevState) + }, []) + + /** + * Toggle custom navigation modal + */ + const handleCustomNav = useCallback(() => { + setShowCustomNav(prevState => !prevState) + }, []) + + /** + * Close all menu when location changed + */ + useEffect(() => { + setShowMoreMenu(false) + setShowSettingMenu(false) + setShowCustomNav(false) + }, [location]) - const handleSystemAdmin = () => { - setShowMore(false) - setShowSystemAdmin(prevState => !prevState) + /** + * Handle save recent and pinned items + */ + const handleSave = (recentItems: NavbarItemType[], currentPinnedItems: NavbarItemType[]) => { + setRecentMenuItems(recentItems) + setPinnedMenuItems(currentPinnedItems) } + /** + * Remove recent menu item + */ + const handleRemoveRecentMenuItem = useCallback((item: NavbarItemType) => { + setRecentMenuItems(prevState => prevState.filter(prevStateItem => prevStateItem.id !== item.id)) + }, []) + + /** + * Change pinned menu items + */ + const handleChangePinnedMenuItem = useCallback( + (item: NavbarItemType) => { + setPinnedMenuItems(prevState => { + const isPinned = prevState.some(pinned => pinned.id === item.id) + + if (isPinned) { + return prevState.filter(pinned => pinned.id !== item.id) + } + + // If pin item, remove it from recent + handleRemoveRecentMenuItem(item) + + return [...prevState, item] + }) + }, + [handleRemoveRecentMenuItem] + ) + return ( <SandboxLayout.Root> <SandboxLayout.LeftPanel> <Navbar - showMore={showMore} - showSystemAdmin={showSystemAdmin} - handleMore={handleMore} - handleSystemAdmin={handleSystemAdmin} + showMoreMenu={showMoreMenu} + showSettingMenu={showSettingMenu} + handleMoreMenu={handleMoreMenu} + handleSettingsMenu={handleSettingsMenu} currentUser={currentUser} + handleCustomNav={handleCustomNav} + handleLogOut={handleLogOut} + recentMenuItems={recentMenuItems} + pinnedMenuItems={pinnedMenuItems} + handleChangePinnedMenuItem={handleChangePinnedMenuItem} + handleRemoveRecentMenuItem={handleRemoveRecentMenuItem} /> </SandboxLayout.LeftPanel> <Outlet /> - <MoreSubmenu showMore={showMore} handleMore={handleMore} /> - <SettingsMenu showSystemAdmin={showSystemAdmin} handleSystemAdmin={handleSystemAdmin} /> + <MoreSubmenu showMoreMenu={showMoreMenu} handleMoreMenu={handleMoreMenu} items={moreMenu} /> + <SettingsMenu showSettingMenu={showSettingMenu} handleSettingsMenu={handleSettingsMenu} items={settingsMenu} /> + <ManageNavigation + pinnedItems={pinnedMenuItems} + recentItems={recentMenuItems} + navbarMenuData={navbarMenuData} + showManageNavigation={showCustomNav} + isSubmitting={false} + submitted={false} + onSave={handleSave} + onClose={handleCustomNav} + /> </SandboxLayout.Root> ) } diff --git a/packages/playground/src/layouts/SandboxSettings.tsx b/packages/playground/src/layouts/SandboxSettings.tsx index fffa6a02e..fb018f571 100644 --- a/packages/playground/src/layouts/SandboxSettings.tsx +++ b/packages/playground/src/layouts/SandboxSettings.tsx @@ -21,7 +21,7 @@ const SandboxSettings: React.FC = () => { return ( <SandboxLayout.Root> <SandboxLayout.Header> - <div className="border-border-background flex h-full items-center border-b px-8"> + <div className="flex h-full items-center border-b border-border-background px-8"> <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> diff --git a/packages/playground/src/layouts/types.ts b/packages/playground/src/layouts/types.ts index 8d476cbf0..faf56ab11 100644 --- a/packages/playground/src/layouts/types.ts +++ b/packages/playground/src/layouts/types.ts @@ -6,6 +6,7 @@ export interface TypesUser { created?: number display_name?: string email?: string + role?: string uid?: string updated?: number url?: string diff --git a/packages/playground/src/pages/mocks/mockCurrentUserData.ts b/packages/playground/src/pages/mocks/mockCurrentUserData.ts index 0a8991005..c86fe11bf 100644 --- a/packages/playground/src/pages/mocks/mockCurrentUserData.ts +++ b/packages/playground/src/pages/mocks/mockCurrentUserData.ts @@ -1,8 +1,11 @@ -export const currentUser = { +import { TypesUser } from '../../layouts/types' + +export const currentUser: TypesUser = { admin: true, blocked: false, uid: 'admin', display_name: 'Steven M.', + role: 'Admin', email: 'admin@gitness.io', created: 1728591718910, updated: 1728591718910, diff --git a/packages/playground/src/pages/pull-request-changes-page.tsx b/packages/playground/src/pages/pull-request-changes-page.tsx index 35efeb5af..3941cdc88 100644 --- a/packages/playground/src/pages/pull-request-changes-page.tsx +++ b/packages/playground/src/pages/pull-request-changes-page.tsx @@ -141,7 +141,7 @@ const FilterSortViewDropdowns: React.FC<FilterViewProps> = ({ active }) => { mockApprovalItems[index].items.map(itm => ( <DropdownMenuItem key={itm.id}> <RadioGroup className="flex items-start gap-2"> - <RadioGroupItem value="false" className="text-tertiary-background mt-1 size-3" /> + <RadioGroupItem value="false" className="mt-1 size-3 text-tertiary-background" /> <div className="flex flex-col"> <Text truncate size={1} color="primary"> {itm.title} diff --git a/packages/playground/src/pages/sandbox-repo-code-page.tsx b/packages/playground/src/pages/sandbox-repo-code-page.tsx index 156dbb5ba..b714bcb8a 100644 --- a/packages/playground/src/pages/sandbox-repo-code-page.tsx +++ b/packages/playground/src/pages/sandbox-repo-code-page.tsx @@ -90,7 +90,7 @@ function Sidebar() { <BranchSelector size="sm" name="main" branchList={mockBranchList} selectBranch={noop} width="full" /> <ButtonGroup.Root spacing="0" - className="shadow-border h-full overflow-hidden rounded-md shadow-[inset_0_0_0_1px]" + className="h-full overflow-hidden rounded-md shadow-[inset_0_0_0_1px] shadow-border" > <Button size="sm" variant="ghost" className="w-8 rounded-none p-0"> <Icon size={15} name="add-folder" className="text-primary/80" /> diff --git a/packages/playground/src/pages/settings-account-general-page.tsx b/packages/playground/src/pages/settings-account-general-page.tsx index df0436410..b7ca9df13 100644 --- a/packages/playground/src/pages/settings-account-general-page.tsx +++ b/packages/playground/src/pages/settings-account-general-page.tsx @@ -115,7 +115,7 @@ export function SettingsAccountGeneralPage() { {/* PERSONAL INFORMATION */} <FormFieldSet.Legend>Personal information</FormFieldSet.Legend> <FormFieldSet.ControlGroup className="flex w-auto flex-row items-center justify-start gap-x-6"> - <Avatar size="80" className="bg-primary/[0.02] size-20 rounded-full shadow-md"> + <Avatar size="80" className="size-20 rounded-full bg-primary/[0.02] shadow-md"> <AvatarImage src="/images/anon.jpg" /> <AvatarFallback> <Text size={5} weight="medium" color="tertiaryBackground"> diff --git a/packages/playground/src/utils/debaunce.ts b/packages/playground/src/utils/debaunce.ts new file mode 100644 index 000000000..836ef06aa --- /dev/null +++ b/packages/playground/src/utils/debaunce.ts @@ -0,0 +1,14 @@ +export const debounce = <T extends (...args: Parameters<T>) => void>(func: T, wait: number): T => { + let timeout: ReturnType<typeof setTimeout> | null = null + + return ((...args: Parameters<T>) => { + const later = () => { + timeout = null + func(...args) + } + if (timeout !== null) { + clearTimeout(timeout) + } + timeout = setTimeout(later, wait) + }) as T +}