+
{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 (