From 0908a8c8f70f8e796660730340a5a638a69ed34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Francisco?= <4301103+tomasfrancisco@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:30:31 +0100 Subject: [PATCH] Improve app navigation with new sidebar (#66) --- .../src/app/app/@connections/default.tsx | 3 + .../destinations}/default.tsx | 0 .../_actions/disable-integration.action.tsx | 2 +- .../destinations}/github/_actions/index.ts | 0 .../github/_actions/update-settings.action.ts | 0 .../github/_components/github-card.tsx | 0 .../github/_components/settings-form.tsx | 0 .../destinations}/github/_rsc/github.tsx | 0 .../destinations}/github/callback/route.ts | 2 +- .../destinations}/github/page.tsx | 0 .../_actions/disable-integration.action.tsx | 2 +- .../destinations}/gitlab/_actions/index.ts | 0 .../_actions/select-repository.action.ts | 0 .../gitlab/_components/gitlab-card.tsx | 0 .../destinations}/gitlab/_rsc/gitlab.tsx | 0 .../destinations}/page.tsx | 2 +- .../notifications/default.tsx | 0 .../discord/_components/discord-card.tsx | 0 .../notifications/discord/_rsc/discord.tsx | 0 .../notifications/page.tsx | 0 .../slack/_components/slack-card.tsx | 0 .../notifications/slack/_rsc/slack.tsx | 0 .../sources}/default.tsx | 0 .../sources}/figma/_components/figma-card.tsx | 0 .../sources}/figma/_components/provider.tsx | 0 .../sources}/figma/_rsc/figma.tsx | 0 .../sources}/figma/callback/route.ts | 0 .../resources/[resourceId]/_actions/index.ts | 0 .../[resourceId]/_actions/resource.action.ts | 0 .../figma/resources/[resourceId]/page.tsx | 0 .../resources/_actions/file-preview.action.ts | 0 .../figma/resources/_actions/index.ts | 0 .../_actions/register-file.action.ts | 0 .../resources/_actions/resources.action.ts | 0 .../resources/_components/figma-file.tsx | 0 .../resources/_components/figma-form.tsx | 0 .../resources/_components/file-preview.tsx | 0 .../resources/_components/resources-list.tsx | 0 .../figma/resources/_schemas/schema.ts | 0 .../sources}/figma/resources/page.tsx | 0 .../inputs => @connections/sources}/page.tsx | 2 +- .../penpot/_components/penpot-card.tsx | 0 .../sources}/penpot/_rsc/penpot.tsx | 0 .../app/app/integrations/@tabs/default.tsx | 3 - .../src/app/app/integrations/default.tsx | 3 - .../src/app/app/integrations/layout.tsx | 44 - apps/engine/src/app/app/integrations/page.tsx | 7 - apps/engine/src/app/app/layout.tsx | 30 +- .../components/account-menu/acocunt-menu.tsx | 72 - .../src/components/account-menu/index.ts | 1 - .../app-navigation/app-navigation.tsx | 2 +- .../integration-settings.tsx | 12 +- apps/engine/src/config.ts | 2 +- .../src/modules/app-layout/acocunt-menu.tsx | 88 + .../src/modules/app-layout/app-layout.tsx | 32 + .../src/modules/app-layout/app-sidebar.tsx | 97 + .../src/modules/app-layout/breadcrumb-nav.tsx | 37 + apps/engine/src/modules/app-layout/index.ts | 1 + apps/engine/tailwind.config.ts | 6 +- apps/storybook/package.json | 10 +- packages/components/package.json | 1 + packages/components/public/dark-theme.css | 8 + packages/components/public/light-theme.css | 8 + packages/components/src/alert/alert.tsx | 2 +- packages/components/src/button/button.tsx | 3 +- .../src/collapsible/collapsible.tsx | 11 + packages/components/src/collapsible/index.ts | 1 + packages/components/src/globals.css | 16 + packages/components/src/hooks/use-mobile.tsx | 21 + packages/components/src/icons/ds-logo.tsx | 2 - packages/components/src/index.ts | 3 + packages/components/src/input/input.tsx | 5 +- .../src/navigation-menu/navigation-menu.tsx | 2 +- packages/components/src/sheet/sheet.tsx | 33 +- packages/components/src/sidebar/index.ts | 1 + packages/components/src/sidebar/sidebar.tsx | 776 + packages/components/src/skeleton/index.ts | 1 + packages/components/src/skeleton/skeleton.tsx | 15 + packages/components/src/toaster/toast.tsx | 2 +- packages/components/tailwind.config.cjs | 10 + pnpm-lock.yaml | 12800 +++++++--------- tools/eslint/package.json | 2 +- tools/eslint/react.js | 2 + 83 files changed, 6764 insertions(+), 7421 deletions(-) create mode 100644 apps/engine/src/app/app/@connections/default.tsx rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/destinations}/default.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_actions/disable-integration.action.tsx (92%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_actions/index.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_actions/update-settings.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_components/github-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_components/settings-form.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/_rsc/github.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/callback/route.ts (95%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/github/page.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/gitlab/_actions/disable-integration.action.tsx (92%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/gitlab/_actions/index.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/gitlab/_actions/select-repository.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/gitlab/_components/gitlab-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/gitlab/_rsc/gitlab.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/destinations}/page.tsx (92%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/default.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/discord/_components/discord-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/discord/_rsc/discord.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/page.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/slack/_components/slack-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs => @connections}/notifications/slack/_rsc/slack.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/outputs => @connections/sources}/default.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/_components/figma-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/_components/provider.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/_rsc/figma.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/callback/route.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/[resourceId]/_actions/index.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/[resourceId]/_actions/resource.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/[resourceId]/page.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_actions/file-preview.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_actions/index.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_actions/register-file.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_actions/resources.action.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_components/figma-file.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_components/figma-form.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_components/file-preview.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_components/resources-list.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/_schemas/schema.ts (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/figma/resources/page.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/page.tsx (92%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/penpot/_components/penpot-card.tsx (100%) rename apps/engine/src/app/app/{integrations/@tabs/inputs => @connections/sources}/penpot/_rsc/penpot.tsx (100%) delete mode 100644 apps/engine/src/app/app/integrations/@tabs/default.tsx delete mode 100644 apps/engine/src/app/app/integrations/default.tsx delete mode 100644 apps/engine/src/app/app/integrations/layout.tsx delete mode 100644 apps/engine/src/app/app/integrations/page.tsx delete mode 100644 apps/engine/src/components/account-menu/acocunt-menu.tsx delete mode 100644 apps/engine/src/components/account-menu/index.ts create mode 100644 apps/engine/src/modules/app-layout/acocunt-menu.tsx create mode 100644 apps/engine/src/modules/app-layout/app-layout.tsx create mode 100644 apps/engine/src/modules/app-layout/app-sidebar.tsx create mode 100644 apps/engine/src/modules/app-layout/breadcrumb-nav.tsx create mode 100644 apps/engine/src/modules/app-layout/index.ts create mode 100644 packages/components/src/collapsible/collapsible.tsx create mode 100644 packages/components/src/collapsible/index.ts create mode 100644 packages/components/src/hooks/use-mobile.tsx create mode 100644 packages/components/src/sidebar/index.ts create mode 100644 packages/components/src/sidebar/sidebar.tsx create mode 100644 packages/components/src/skeleton/index.ts create mode 100644 packages/components/src/skeleton/skeleton.tsx diff --git a/apps/engine/src/app/app/@connections/default.tsx b/apps/engine/src/app/app/@connections/default.tsx new file mode 100644 index 00000000..d01c3897 --- /dev/null +++ b/apps/engine/src/app/app/@connections/default.tsx @@ -0,0 +1,3 @@ +import DefaultPage from './destinations/page'; + +export default DefaultPage; diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/default.tsx b/apps/engine/src/app/app/@connections/destinations/default.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/default.tsx rename to apps/engine/src/app/app/@connections/destinations/default.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/disable-integration.action.tsx b/apps/engine/src/app/app/@connections/destinations/github/_actions/disable-integration.action.tsx similarity index 92% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/disable-integration.action.tsx rename to apps/engine/src/app/app/@connections/destinations/github/_actions/disable-integration.action.tsx index 969b9cf2..c896d4e3 100644 --- a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/disable-integration.action.tsx +++ b/apps/engine/src/app/app/@connections/destinations/github/_actions/disable-integration.action.tsx @@ -19,6 +19,6 @@ export const disableIntegration = authorizedAction .delete(Integrations) .where(and(eq(Integrations.type, integrationType.Enum.github))); - revalidatePath('/app/integrations/outputs'); + revalidatePath('/app/destinations'); return { success: true }; }); diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/index.ts b/apps/engine/src/app/app/@connections/destinations/github/_actions/index.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/index.ts rename to apps/engine/src/app/app/@connections/destinations/github/_actions/index.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/update-settings.action.ts b/apps/engine/src/app/app/@connections/destinations/github/_actions/update-settings.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_actions/update-settings.action.ts rename to apps/engine/src/app/app/@connections/destinations/github/_actions/update-settings.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_components/github-card.tsx b/apps/engine/src/app/app/@connections/destinations/github/_components/github-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_components/github-card.tsx rename to apps/engine/src/app/app/@connections/destinations/github/_components/github-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_components/settings-form.tsx b/apps/engine/src/app/app/@connections/destinations/github/_components/settings-form.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_components/settings-form.tsx rename to apps/engine/src/app/app/@connections/destinations/github/_components/settings-form.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/_rsc/github.tsx b/apps/engine/src/app/app/@connections/destinations/github/_rsc/github.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/_rsc/github.tsx rename to apps/engine/src/app/app/@connections/destinations/github/_rsc/github.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/callback/route.ts b/apps/engine/src/app/app/@connections/destinations/github/callback/route.ts similarity index 95% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/callback/route.ts rename to apps/engine/src/app/app/@connections/destinations/github/callback/route.ts index 1baa0219..708b07e7 100644 --- a/apps/engine/src/app/app/integrations/@tabs/outputs/github/callback/route.ts +++ b/apps/engine/src/app/app/@connections/destinations/github/callback/route.ts @@ -43,5 +43,5 @@ export async function GET(request: NextRequest) { console.error('Failed to connect GitHub app.'); } - return NextResponse.redirect(`${origin}/app/integrations/outputs`); + return NextResponse.redirect(`${origin}/app/destinations`); } diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/github/page.tsx b/apps/engine/src/app/app/@connections/destinations/github/page.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/github/page.tsx rename to apps/engine/src/app/app/@connections/destinations/github/page.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/disable-integration.action.tsx b/apps/engine/src/app/app/@connections/destinations/gitlab/_actions/disable-integration.action.tsx similarity index 92% rename from apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/disable-integration.action.tsx rename to apps/engine/src/app/app/@connections/destinations/gitlab/_actions/disable-integration.action.tsx index 969b9cf2..c896d4e3 100644 --- a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/disable-integration.action.tsx +++ b/apps/engine/src/app/app/@connections/destinations/gitlab/_actions/disable-integration.action.tsx @@ -19,6 +19,6 @@ export const disableIntegration = authorizedAction .delete(Integrations) .where(and(eq(Integrations.type, integrationType.Enum.github))); - revalidatePath('/app/integrations/outputs'); + revalidatePath('/app/destinations'); return { success: true }; }); diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/index.ts b/apps/engine/src/app/app/@connections/destinations/gitlab/_actions/index.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/index.ts rename to apps/engine/src/app/app/@connections/destinations/gitlab/_actions/index.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/select-repository.action.ts b/apps/engine/src/app/app/@connections/destinations/gitlab/_actions/select-repository.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_actions/select-repository.action.ts rename to apps/engine/src/app/app/@connections/destinations/gitlab/_actions/select-repository.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_components/gitlab-card.tsx b/apps/engine/src/app/app/@connections/destinations/gitlab/_components/gitlab-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_components/gitlab-card.tsx rename to apps/engine/src/app/app/@connections/destinations/gitlab/_components/gitlab-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_rsc/gitlab.tsx b/apps/engine/src/app/app/@connections/destinations/gitlab/_rsc/gitlab.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/gitlab/_rsc/gitlab.tsx rename to apps/engine/src/app/app/@connections/destinations/gitlab/_rsc/gitlab.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/page.tsx b/apps/engine/src/app/app/@connections/destinations/page.tsx similarity index 92% rename from apps/engine/src/app/app/integrations/@tabs/outputs/page.tsx rename to apps/engine/src/app/app/@connections/destinations/page.tsx index 64d124a7..fb9d9fad 100644 --- a/apps/engine/src/app/app/integrations/@tabs/outputs/page.tsx +++ b/apps/engine/src/app/app/@connections/destinations/page.tsx @@ -8,7 +8,7 @@ export default function Page() { return (
- + {/* */}
); } diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/default.tsx b/apps/engine/src/app/app/@connections/notifications/default.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/default.tsx rename to apps/engine/src/app/app/@connections/notifications/default.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/discord/_components/discord-card.tsx b/apps/engine/src/app/app/@connections/notifications/discord/_components/discord-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/discord/_components/discord-card.tsx rename to apps/engine/src/app/app/@connections/notifications/discord/_components/discord-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/discord/_rsc/discord.tsx b/apps/engine/src/app/app/@connections/notifications/discord/_rsc/discord.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/discord/_rsc/discord.tsx rename to apps/engine/src/app/app/@connections/notifications/discord/_rsc/discord.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/page.tsx b/apps/engine/src/app/app/@connections/notifications/page.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/page.tsx rename to apps/engine/src/app/app/@connections/notifications/page.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/slack/_components/slack-card.tsx b/apps/engine/src/app/app/@connections/notifications/slack/_components/slack-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/slack/_components/slack-card.tsx rename to apps/engine/src/app/app/@connections/notifications/slack/_components/slack-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/notifications/slack/_rsc/slack.tsx b/apps/engine/src/app/app/@connections/notifications/slack/_rsc/slack.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/notifications/slack/_rsc/slack.tsx rename to apps/engine/src/app/app/@connections/notifications/slack/_rsc/slack.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/outputs/default.tsx b/apps/engine/src/app/app/@connections/sources/default.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/outputs/default.tsx rename to apps/engine/src/app/app/@connections/sources/default.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/_components/figma-card.tsx b/apps/engine/src/app/app/@connections/sources/figma/_components/figma-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/_components/figma-card.tsx rename to apps/engine/src/app/app/@connections/sources/figma/_components/figma-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/_components/provider.tsx b/apps/engine/src/app/app/@connections/sources/figma/_components/provider.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/_components/provider.tsx rename to apps/engine/src/app/app/@connections/sources/figma/_components/provider.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/_rsc/figma.tsx b/apps/engine/src/app/app/@connections/sources/figma/_rsc/figma.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/_rsc/figma.tsx rename to apps/engine/src/app/app/@connections/sources/figma/_rsc/figma.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/callback/route.ts b/apps/engine/src/app/app/@connections/sources/figma/callback/route.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/callback/route.ts rename to apps/engine/src/app/app/@connections/sources/figma/callback/route.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/_actions/index.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/_actions/index.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/_actions/index.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/_actions/index.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/_actions/resource.action.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/_actions/resource.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/_actions/resource.action.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/_actions/resource.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/page.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/page.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/[resourceId]/page.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/[resourceId]/page.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/file-preview.action.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/_actions/file-preview.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/file-preview.action.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/_actions/file-preview.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/index.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/_actions/index.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/index.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/_actions/index.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/register-file.action.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/_actions/register-file.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/register-file.action.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/_actions/register-file.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/resources.action.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/_actions/resources.action.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_actions/resources.action.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/_actions/resources.action.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/figma-file.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/_components/figma-file.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/figma-file.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/_components/figma-file.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/figma-form.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/_components/figma-form.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/figma-form.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/_components/figma-form.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/file-preview.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/_components/file-preview.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/file-preview.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/_components/file-preview.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/resources-list.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/_components/resources-list.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_components/resources-list.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/_components/resources-list.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_schemas/schema.ts b/apps/engine/src/app/app/@connections/sources/figma/resources/_schemas/schema.ts similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/_schemas/schema.ts rename to apps/engine/src/app/app/@connections/sources/figma/resources/_schemas/schema.ts diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/page.tsx b/apps/engine/src/app/app/@connections/sources/figma/resources/page.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/figma/resources/page.tsx rename to apps/engine/src/app/app/@connections/sources/figma/resources/page.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/page.tsx b/apps/engine/src/app/app/@connections/sources/page.tsx similarity index 92% rename from apps/engine/src/app/app/integrations/@tabs/inputs/page.tsx rename to apps/engine/src/app/app/@connections/sources/page.tsx index 4fbb3f08..1b3a815e 100644 --- a/apps/engine/src/app/app/integrations/@tabs/inputs/page.tsx +++ b/apps/engine/src/app/app/@connections/sources/page.tsx @@ -8,7 +8,7 @@ export default function Page() { return (
- + {/* */}
); } diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/penpot/_components/penpot-card.tsx b/apps/engine/src/app/app/@connections/sources/penpot/_components/penpot-card.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/penpot/_components/penpot-card.tsx rename to apps/engine/src/app/app/@connections/sources/penpot/_components/penpot-card.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/inputs/penpot/_rsc/penpot.tsx b/apps/engine/src/app/app/@connections/sources/penpot/_rsc/penpot.tsx similarity index 100% rename from apps/engine/src/app/app/integrations/@tabs/inputs/penpot/_rsc/penpot.tsx rename to apps/engine/src/app/app/@connections/sources/penpot/_rsc/penpot.tsx diff --git a/apps/engine/src/app/app/integrations/@tabs/default.tsx b/apps/engine/src/app/app/integrations/@tabs/default.tsx deleted file mode 100644 index c8e35914..00000000 --- a/apps/engine/src/app/app/integrations/@tabs/default.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import DefaultPage from './inputs/page'; - -export default DefaultPage; diff --git a/apps/engine/src/app/app/integrations/default.tsx b/apps/engine/src/app/app/integrations/default.tsx deleted file mode 100644 index 71ad8d97..00000000 --- a/apps/engine/src/app/app/integrations/default.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import DefaultPage from './@tabs/inputs/page'; - -export default DefaultPage; diff --git a/apps/engine/src/app/app/integrations/layout.tsx b/apps/engine/src/app/app/integrations/layout.tsx deleted file mode 100644 index a7562903..00000000 --- a/apps/engine/src/app/app/integrations/layout.tsx +++ /dev/null @@ -1,44 +0,0 @@ -'use client'; - -import { MainContent } from '@/components'; -import { - Tabs, - TabsContent, - TabsList, - TabsTrigger, -} from '@ds-project/components'; -import Link from 'next/link'; -import { useSelectedLayoutSegment } from 'next/navigation'; - -import type { ReactNode } from 'react'; - -export default function Layout({ - tabs, -}: Readonly<{ - tabs: ReactNode; -}>) { - const tabsSegment = useSelectedLayoutSegment('tabs'); - - return ( - -
- - - - Inputs - - - Outputs - - - Notifications - - - {tabs} - -
- ); -} diff --git a/apps/engine/src/app/app/integrations/page.tsx b/apps/engine/src/app/app/integrations/page.tsx deleted file mode 100644 index 551ea5f1..00000000 --- a/apps/engine/src/app/app/integrations/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { getMetadata } from '@/lib/metadata'; - -export const metadata = getMetadata({ title: 'Integrations' }); - -export default function Page() { - return null; -} diff --git a/apps/engine/src/app/app/layout.tsx b/apps/engine/src/app/app/layout.tsx index 3175fc5b..eaafcb63 100644 --- a/apps/engine/src/app/app/layout.tsx +++ b/apps/engine/src/app/app/layout.tsx @@ -1,32 +1,20 @@ -import { AppNavigation } from '@/components'; import { api } from '@ds-project/api/rsc'; import { getMetadata } from '@/lib/metadata'; -import { getShowReleasesFlag } from '@/lib/flags'; + +import type { ReactNode } from 'react'; +import { AppLayout } from '@/modules/app-layout'; export const metadata = getMetadata({ title: 'Dashboard' }); export default async function RootLayout({ - children, + connections, }: Readonly<{ - children: React.ReactNode; + connections: ReactNode; }>) { - const projects = await api.projects.getAll(); + // const tabsSegment = useSelectedLayoutSegment('tabs'); + // const projects = await api.projects.getAll(); const user = await api.users.getCurrent(); - const showReleases = await getShowReleasesFlag(); + // const showReleases = await getShowReleasesFlag(); - return ( - <> -
- -
-
- {children} -
- - ); + return {connections}; } diff --git a/apps/engine/src/components/account-menu/acocunt-menu.tsx b/apps/engine/src/components/account-menu/acocunt-menu.tsx deleted file mode 100644 index c70295f5..00000000 --- a/apps/engine/src/components/account-menu/acocunt-menu.tsx +++ /dev/null @@ -1,72 +0,0 @@ -'use client'; - -import { shapes } from '@dicebear/collection'; -import { createAvatar } from '@dicebear/core'; -import { - Avatar, - AvatarFallback, - AvatarImage, - Button, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, - Icons, - Text, -} from '@ds-project/components'; -import Link from 'next/link'; -import { useMemo } from 'react'; - -interface AccountMenuProps { - email: string; -} - -export function AccountMenu({ email }: AccountMenuProps) { - const avatarUri = useMemo(() => { - const avatar = createAvatar(shapes, { - seed: email, - }); - - return avatar.toDataUri(); - }, [email]); - - return ( - - - - - - My Account - - - {email} - - - - - - - Home Page - - - - - - Log Out - - - - - ); -} diff --git a/apps/engine/src/components/account-menu/index.ts b/apps/engine/src/components/account-menu/index.ts deleted file mode 100644 index c8fd4f12..00000000 --- a/apps/engine/src/components/account-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './acocunt-menu'; diff --git a/apps/engine/src/components/app-navigation/app-navigation.tsx b/apps/engine/src/components/app-navigation/app-navigation.tsx index 5c993a3f..2c7aadac 100644 --- a/apps/engine/src/components/app-navigation/app-navigation.tsx +++ b/apps/engine/src/components/app-navigation/app-navigation.tsx @@ -15,7 +15,7 @@ import Link from 'next/link'; import { cn } from '@/lib/css'; import { HomeButton } from '../home-button'; import type { SelectProjects } from '@ds-project/database/schema'; -import { AccountMenu } from '../account-menu/acocunt-menu'; +import { AccountMenu } from '../../modules/app-layout/acocunt-menu'; import { config } from '@/config'; interface AppNavigationProps { diff --git a/apps/engine/src/components/integration-settings/integration-settings.tsx b/apps/engine/src/components/integration-settings/integration-settings.tsx index db5f2f38..fd275b8f 100644 --- a/apps/engine/src/components/integration-settings/integration-settings.tsx +++ b/apps/engine/src/components/integration-settings/integration-settings.tsx @@ -53,18 +53,14 @@ export function IntegrationSettings({ -
+
{integrationLogo} - +

Integration settings

- -

{name}

-
- -

Configure integration

-
+ {name} + Configure integration {children} diff --git a/apps/engine/src/config.ts b/apps/engine/src/config.ts index 27f7d162..f6f5ff92 100644 --- a/apps/engine/src/config.ts +++ b/apps/engine/src/config.ts @@ -23,7 +23,7 @@ export const config = { isSentryEnabled: isProduction, FIGMA_QUERY_KEY: 'figma_key', FIGMA_COOKIE_KEY: 'figma.key', - figmaRedirectUri: `${pageUrl}/integrations/inputs/figma/callback`, + figmaRedirectUri: `${pageUrl}/app/sources/figma/callback`, defaultGitTokensPath: '', defaultTargetGitBranch: 'ds-pro/sync-tokens', defaultCommitMessage: 'feat(tokens): [ds-pro] 💅 Sync Tokens', diff --git a/apps/engine/src/modules/app-layout/acocunt-menu.tsx b/apps/engine/src/modules/app-layout/acocunt-menu.tsx new file mode 100644 index 00000000..bdda1443 --- /dev/null +++ b/apps/engine/src/modules/app-layout/acocunt-menu.tsx @@ -0,0 +1,88 @@ +'use client'; + +import { shapes } from '@dicebear/collection'; +import { createAvatar } from '@dicebear/core'; +import { + Avatar, + AvatarFallback, + AvatarImage, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, + LucideIcons, + SidebarMenuButton, +} from '@ds-project/components'; +import Link from 'next/link'; +import { useMemo } from 'react'; + +interface AccountMenuProps { + email: string; +} + +export function AccountMenu({ email }: AccountMenuProps) { + const avatarUri = useMemo(() => { + const avatar = createAvatar(shapes, { + seed: email, + }); + + return avatar.toDataUri(); + }, [email]); + + return ( + + + + + {/* TODO: improve alt description, perhaps with user name when we ask for it */} + + CN + +
+ {email} + {email} +
+ +
+
+ + +
+ + {/* TODO: improve alt description, perhaps with user name when we ask for it */} + + CN + +
+ {email} + {email} +
+
+
+ + + + + Home + + + + + + Log out + + +
+
+ ); +} diff --git a/apps/engine/src/modules/app-layout/app-layout.tsx b/apps/engine/src/modules/app-layout/app-layout.tsx new file mode 100644 index 00000000..88ec82bc --- /dev/null +++ b/apps/engine/src/modules/app-layout/app-layout.tsx @@ -0,0 +1,32 @@ +import { + Separator, + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from '@ds-project/components'; +import { BreadcrumbNav } from './breadcrumb-nav'; +import { AppSidebar } from './app-sidebar'; + +export function AppLayout({ + children, + email, +}: { + children: React.ReactNode; + email: string; +}) { + return ( + + + +
+
+ + + +
+
+
{children}
+
+
+ ); +} diff --git a/apps/engine/src/modules/app-layout/app-sidebar.tsx b/apps/engine/src/modules/app-layout/app-sidebar.tsx new file mode 100644 index 00000000..a93080dc --- /dev/null +++ b/apps/engine/src/modules/app-layout/app-sidebar.tsx @@ -0,0 +1,97 @@ +'use client'; + +import * as React from 'react'; + +import { Icons, LucideIcons } from '@ds-project/components'; + +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupLabel, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, +} from '@ds-project/components'; + +import Link from 'next/link'; +import { AccountMenu } from './acocunt-menu'; +import { config } from '@/config'; + +const navigationItems = [ + { + title: 'GitHub', + url: '/app/destinations', + icon: LucideIcons.Github, + }, + { + title: 'Figma', + url: '/app/sources', + icon: LucideIcons.Figma, + }, +]; + +export function AppSidebar({ email }: { email: string }) { + return ( + + + + + + DS + Dashboard + + + + + + + Connections + + {navigationItems.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + Shortcuts + + + + + + Discord + + + + + + + Feedback + + + + + + + + + + + + + + ); +} diff --git a/apps/engine/src/modules/app-layout/breadcrumb-nav.tsx b/apps/engine/src/modules/app-layout/breadcrumb-nav.tsx new file mode 100644 index 00000000..89ddb1d7 --- /dev/null +++ b/apps/engine/src/modules/app-layout/breadcrumb-nav.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@ds-project/components'; +import { useSelectedLayoutSegment } from 'next/navigation'; + +export function BreadcrumbNav() { + const connectionGroup = useSelectedLayoutSegment('connections'); + + if (!connectionGroup) { + return null; + } + + const connectionPage = { + sources: 'Figma', + destinations: 'GitHub', + }[connectionGroup]; + + return ( + + + + Connections + + + + {connectionPage} + + + + ); +} diff --git a/apps/engine/src/modules/app-layout/index.ts b/apps/engine/src/modules/app-layout/index.ts new file mode 100644 index 00000000..e8b945e8 --- /dev/null +++ b/apps/engine/src/modules/app-layout/index.ts @@ -0,0 +1 @@ +export * from './app-layout'; diff --git a/apps/engine/tailwind.config.ts b/apps/engine/tailwind.config.ts index b23db3e8..201c4547 100644 --- a/apps/engine/tailwind.config.ts +++ b/apps/engine/tailwind.config.ts @@ -4,11 +4,7 @@ const config: Config = { corePlugins: { preflight: false, // Usage of packages/components includes preflight already }, - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', - ], + content: ['./src/**/*.{ts,tsx}'], theme: { extend: { backgroundImage: { diff --git a/apps/storybook/package.json b/apps/storybook/package.json index 8e80caad..533bdc4b 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -23,14 +23,14 @@ "@ds-project/eslint": "workspace:*", "@ds-project/prettier": "workspace:*", "@etchteam/storybook-addon-css-variables-theme": "^3.0.0", - "@storybook/addon-essentials": "^8.2.3", + "@storybook/addon-essentials": "^8.3.6", "@storybook/addon-interactions": "^8.2.3", "@storybook/addon-links": "^8.2.3", "@storybook/addon-onboarding": "^8.2.3", "@storybook/blocks": "^8.2.3", "@storybook/react": "^8.2.3", - "@storybook/react-vite": "^8.2.3", - "@storybook/test": "^8.2.3", + "@storybook/react-vite": "^8.3.6", + "@storybook/test": "^8.3.6", "@types/react": "catalog:", "@types/react-dom": "catalog:", "@typescript-eslint/eslint-plugin": "^7.13.1", @@ -39,8 +39,8 @@ "eslint": "catalog:", "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.7", - "eslint-plugin-storybook": "^0.8.0", - "storybook": "^8.2.3", + "eslint-plugin-storybook": "^0.10.1", + "storybook": "^8.3.6", "typescript": "catalog:", "vite": "catalog:", "zod": "catalog:" diff --git a/packages/components/package.json b/packages/components/package.json index 139ccab3..d7b7d814 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -40,6 +40,7 @@ "@radix-ui/react-aspect-ratio": "^1.1.0", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.1", + "@radix-ui/react-collapsible": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", diff --git a/packages/components/public/dark-theme.css b/packages/components/public/dark-theme.css index 6661f52c..3a60b092 100644 --- a/packages/components/public/dark-theme.css +++ b/packages/components/public/dark-theme.css @@ -23,4 +23,12 @@ --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; + --sidebar-background: 240 5.9% 10%; + --sidebar-foreground: 240 4.8% 95.9%; + --sidebar-primary: 224.3 76.3% 48%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 240 3.7% 15.9%; + --sidebar-accent-foreground: 240 4.8% 95.9%; + --sidebar-border: 240 3.7% 15.9%; + --sidebar-ring: 217.2 91.2% 59.8%; } diff --git a/packages/components/public/light-theme.css b/packages/components/public/light-theme.css index 1b77a5e0..8aa9b4eb 100644 --- a/packages/components/public/light-theme.css +++ b/packages/components/public/light-theme.css @@ -24,4 +24,12 @@ --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; + --sidebar-background: 0 0% 98%; + --sidebar-foreground: 240 5.3% 26.1%; + --sidebar-primary: 240 5.9% 10%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 240 4.8% 95.9%; + --sidebar-accent-foreground: 240 5.9% 10%; + --sidebar-border: 220 13% 91%; + --sidebar-ring: 217.2 91.2% 59.8%; } diff --git a/packages/components/src/alert/alert.tsx b/packages/components/src/alert/alert.tsx index 25e33f30..25c27088 100644 --- a/packages/components/src/alert/alert.tsx +++ b/packages/components/src/alert/alert.tsx @@ -5,7 +5,7 @@ import { Slot } from '@radix-ui/react-slot'; import { cn } from '@/utils'; const alertVariants = cva( - 'ds-relative ds-w-full ds-rounded-lg ds-border ds-p-4 [&>svg~*]:ds-pl-7 [&>svg+div]:ds-translate-y-[-3px] [&>svg]:ds-absolute [&>svg]:ds-left-4 [&>svg]:ds-top-4 [&>svg]:ds-text-foreground', + 'ds-relative ds-w-full ds-rounded-lg ds-border ds-p-4 [&>svg+div]:ds-translate-y-[-3px] [&>svg]:ds-absolute [&>svg]:ds-left-4 [&>svg]:ds-top-4 [&>svg]:ds-text-foreground [&>svg~*]:ds-pl-7', { variants: { variant: { diff --git a/packages/components/src/button/button.tsx b/packages/components/src/button/button.tsx index 0818da4e..ee32fcaa 100644 --- a/packages/components/src/button/button.tsx +++ b/packages/components/src/button/button.tsx @@ -2,10 +2,11 @@ import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva } from 'class-variance-authority'; import type { VariantProps } from 'class-variance-authority'; + import { cn } from '@/utils'; const buttonVariants = cva( - 'ds-inline-flex ds-items-center ds-justify-center ds-whitespace-nowrap ds-rounded-md ds-text-sm ds-font-medium ds-ring-offset-background ds-transition-colors focus-visible:ds-outline-none focus-visible:ds-ring-2 focus-visible:ds-ring-ring focus-visible:ds-ring-offset-2 disabled:ds-pointer-events-none disabled:ds-opacity-50 ds-cursor-pointer', + 'ds-inline-flex ds-items-center ds-justify-center ds-gap-2 ds-whitespace-nowrap ds-rounded-md ds-text-sm ds-font-medium ds-ring-offset-background ds-transition-colors focus-visible:ds-outline-none focus-visible:ds-ring-2 focus-visible:ds-ring-ring focus-visible:ds-ring-offset-2 disabled:ds-pointer-events-none disabled:ds-opacity-50 [&_svg]:ds-pointer-events-none [&_svg]:ds-size-4 [&_svg]:ds-shrink-0', { variants: { variant: { diff --git a/packages/components/src/collapsible/collapsible.tsx b/packages/components/src/collapsible/collapsible.tsx new file mode 100644 index 00000000..86ab87d8 --- /dev/null +++ b/packages/components/src/collapsible/collapsible.tsx @@ -0,0 +1,11 @@ +'use client'; + +import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; + +const Collapsible = CollapsiblePrimitive.Root; + +const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; + +const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; + +export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/packages/components/src/collapsible/index.ts b/packages/components/src/collapsible/index.ts new file mode 100644 index 00000000..20c0813c --- /dev/null +++ b/packages/components/src/collapsible/index.ts @@ -0,0 +1 @@ +export * from './collapsible'; diff --git a/packages/components/src/globals.css b/packages/components/src/globals.css index 5b58394c..30b9c7e5 100644 --- a/packages/components/src/globals.css +++ b/packages/components/src/globals.css @@ -29,6 +29,14 @@ --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; + --sidebar-background: 0 0% 98%; + --sidebar-foreground: 240 5.3% 26.1%; + --sidebar-primary: 240 5.9% 10%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 240 4.8% 95.9%; + --sidebar-accent-foreground: 240 5.9% 10%; + --sidebar-border: 220 13% 91%; + --sidebar-ring: 217.2 91.2% 59.8%; } .dark { @@ -56,6 +64,14 @@ --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; + --sidebar-background: 240 5.9% 10%; + --sidebar-foreground: 240 4.8% 95.9%; + --sidebar-primary: 224.3 76.3% 48%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 240 3.7% 15.9%; + --sidebar-accent-foreground: 240 4.8% 95.9%; + --sidebar-border: 240 3.7% 15.9%; + --sidebar-ring: 217.2 91.2% 59.8%; } } diff --git a/packages/components/src/hooks/use-mobile.tsx b/packages/components/src/hooks/use-mobile.tsx new file mode 100644 index 00000000..6be5f6c1 --- /dev/null +++ b/packages/components/src/hooks/use-mobile.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +const MOBILE_BREAKPOINT = 768; + +export function useIsMobile() { + const [isMobile, setIsMobile] = React.useState( + undefined + ); + + React.useEffect(() => { + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); + const onChange = () => { + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + }; + mql.addEventListener('change', onChange); + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + return () => mql.removeEventListener('change', onChange); + }, []); + + return !!isMobile; +} diff --git a/packages/components/src/icons/ds-logo.tsx b/packages/components/src/icons/ds-logo.tsx index c316ba64..eda1c77e 100644 --- a/packages/components/src/icons/ds-logo.tsx +++ b/packages/components/src/icons/ds-logo.tsx @@ -6,8 +6,6 @@ export const DSLogo = React.forwardRef( return ( ; @@ -7,12 +8,12 @@ const Input = React.forwardRef( ({ className, type, ...props }, ref) => { return ( ); diff --git a/packages/components/src/navigation-menu/navigation-menu.tsx b/packages/components/src/navigation-menu/navigation-menu.tsx index 4ab44ced..6072a925 100644 --- a/packages/components/src/navigation-menu/navigation-menu.tsx +++ b/packages/components/src/navigation-menu/navigation-menu.tsx @@ -55,7 +55,7 @@ const NavigationMenuTrigger = React.forwardRef< {children}{' '} )); diff --git a/packages/components/src/sheet/sheet.tsx b/packages/components/src/sheet/sheet.tsx index 39978c01..ae78ec14 100644 --- a/packages/components/src/sheet/sheet.tsx +++ b/packages/components/src/sheet/sheet.tsx @@ -7,7 +7,6 @@ import type { VariantProps } from 'class-variance-authority'; import { X } from 'lucide-react'; import { cn } from '@/utils'; -import { Text } from '@/text'; const Sheet = SheetPrimitive.Root; @@ -33,7 +32,7 @@ const SheetOverlay = React.forwardRef< SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; const sheetVariants = cva( - 'ds-fixed ds-z-50 ds-gap-4 ds-bg-background ds-p-6 ds-shadow-lg ds-transition ds-ease-in-out data-[state=open]:ds-animate-in data-[state=closed]:ds-animate-out data-[state=closed]:ds-duration-300 data-[state=open]:ds-duration-500', + 'ds-fixed ds-z-50 ds-gap-4 ds-bg-background ds-p-6 ds-shadow-lg ds-transition ds-ease-in-out data-[state=closed]:ds-duration-300 data-[state=open]:ds-duration-500 data-[state=open]:ds-animate-in data-[state=closed]:ds-animate-out', { variants: { side: { @@ -42,7 +41,7 @@ const sheetVariants = cva( 'ds-inset-x-0 ds-bottom-0 ds-border-t data-[state=closed]:ds-slide-out-to-bottom data-[state=open]:ds-slide-in-from-bottom', left: 'ds-inset-y-0 ds-left-0 ds-h-full ds-w-3/4 ds-border-r data-[state=closed]:ds-slide-out-to-left data-[state=open]:ds-slide-in-from-left sm:ds-max-w-sm', right: - 'ds-inset-y-0 ds-right-0 ds-h-full ds-w-3/4 ds- ds-border-l data-[state=closed]:ds-slide-out-to-right data-[state=open]:ds-slide-in-from-right sm:ds-max-w-sm', + 'ds- ds-inset-y-0 ds-right-0 ds-h-full ds-w-3/4 ds-border-l data-[state=closed]:ds-slide-out-to-right data-[state=open]:ds-slide-in-from-right sm:ds-max-w-sm', }, }, defaultVariants: { @@ -106,33 +105,25 @@ SheetFooter.displayName = 'SheetFooter'; const SheetTitle = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( - - {children} - - + className={cn('ds-text-lg ds-font-semibold ds-text-foreground', className)} + {...props} + /> )); SheetTitle.displayName = SheetPrimitive.Title.displayName; const SheetDescription = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( - - {children} - - + className={cn('ds-text-sm ds-text-muted-foreground', className)} + {...props} + /> )); SheetDescription.displayName = SheetPrimitive.Description.displayName; diff --git a/packages/components/src/sidebar/index.ts b/packages/components/src/sidebar/index.ts new file mode 100644 index 00000000..b2ba9a43 --- /dev/null +++ b/packages/components/src/sidebar/index.ts @@ -0,0 +1 @@ +export * from './sidebar'; diff --git a/packages/components/src/sidebar/sidebar.tsx b/packages/components/src/sidebar/sidebar.tsx new file mode 100644 index 00000000..b82f7a33 --- /dev/null +++ b/packages/components/src/sidebar/sidebar.tsx @@ -0,0 +1,776 @@ +'use client'; + +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import type { VariantProps } from 'class-variance-authority'; +import { cva } from 'class-variance-authority'; +import { PanelLeft } from 'lucide-react'; + +import { useIsMobile } from '@/hooks/use-mobile'; +import { cn } from '@/utils'; +import { Button } from '@/button'; +import { Input } from '@/input'; +import { Separator } from '@/separator'; +import { Sheet, SheetContent } from '@/sheet'; +import { Skeleton } from '@/skeleton'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/tooltip'; + +const SIDEBAR_COOKIE_NAME = 'sidebar:state'; +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; +const SIDEBAR_WIDTH = '16rem'; +const SIDEBAR_WIDTH_MOBILE = '18rem'; +const SIDEBAR_WIDTH_ICON = '3rem'; +const SIDEBAR_KEYBOARD_SHORTCUT = 'b'; + +interface SidebarContext { + state: 'expanded' | 'collapsed'; + open: boolean; + setOpen: (open: boolean) => void; + openMobile: boolean; + setOpenMobile: (open: boolean) => void; + isMobile: boolean; + toggleSidebar: () => void; +} + +const SidebarContext = React.createContext(null); + +function useSidebar() { + const context = React.useContext(SidebarContext); + if (!context) { + throw new Error('useSidebar must be used within a SidebarProvider.'); + } + + return context; +} + +const SidebarProvider = React.forwardRef< + HTMLDivElement, + React.ComponentProps<'div'> & { + defaultOpen?: boolean; + open?: boolean; + onOpenChange?: (open: boolean) => void; + } +>( + ( + { + defaultOpen = true, + open: openProp, + onOpenChange: setOpenProp, + className, + style, + children, + ...props + }, + ref + ) => { + const isMobile = useIsMobile(); + const [openMobile, setOpenMobile] = React.useState(false); + + // This is the internal state of the sidebar. + // We use openProp and setOpenProp for control from outside the component. + const [_open, _setOpen] = React.useState(defaultOpen); + const open = openProp ?? _open; + const setOpen = React.useCallback( + (value: boolean | ((value: boolean) => boolean)) => { + const openState = typeof value === 'function' ? value(open) : value; + if (setOpenProp) { + setOpenProp(openState); + } else { + _setOpen(openState); + } + + // This sets the cookie to keep the sidebar state. + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + }, + [setOpenProp, open] + ); + + // Helper to toggle the sidebar. + const toggleSidebar = React.useCallback(() => { + return isMobile + ? setOpenMobile((open) => !open) + : setOpen((open) => !open); + }, [isMobile, setOpen, setOpenMobile]); + + // Adds a keyboard shortcut to toggle the sidebar. + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + event.key === SIDEBAR_KEYBOARD_SHORTCUT && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault(); + toggleSidebar(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [toggleSidebar]); + + // We add a state so that we can do data-state="expanded" or "collapsed". + // This makes it easier to style the sidebar with Tailwind classes. + const state = open ? 'expanded' : 'collapsed'; + + const contextValue = React.useMemo( + () => ({ + state, + open, + setOpen, + isMobile, + openMobile, + setOpenMobile, + toggleSidebar, + }), + [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] + ); + + return ( + + +
+ {children} +
+ + + ); + } +); +SidebarProvider.displayName = 'SidebarProvider'; + +const Sidebar = React.forwardRef< + HTMLDivElement, + React.ComponentProps<'div'> & { + side?: 'left' | 'right'; + variant?: 'sidebar' | 'floating' | 'inset'; + collapsible?: 'offcanvas' | 'icon' | 'none'; + } +>( + ( + { + side = 'left', + variant = 'sidebar', + collapsible = 'offcanvas', + className, + children, + ...props + }, + ref + ) => { + const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); + + if (collapsible === 'none') { + return ( +
+ {children} +
+ ); + } + + if (isMobile) { + return ( + + +
+ {children} +
+
+
+ ); + } + + return ( +
+ {/* This is what handles the sidebar gap on desktop */} +
+
+
+ {children} +
+
+
+ ); + } +); +Sidebar.displayName = 'Sidebar'; + +const SidebarTrigger = React.forwardRef< + React.ElementRef, + React.ComponentProps +>(({ className, onClick, ...props }, ref) => { + const { toggleSidebar } = useSidebar(); + + return ( + + ); +}); +SidebarTrigger.displayName = 'SidebarTrigger'; + +const SidebarRail = React.forwardRef< + HTMLButtonElement, + React.ComponentProps<'button'> +>(({ className, ...props }, ref) => { + const { toggleSidebar } = useSidebar(); + + return ( +