From a4c549e7c393bab80d4a2ac1814118e1b08559be Mon Sep 17 00:00:00 2001 From: lonelyhentxi Date: Mon, 30 Dec 2024 06:39:09 +0800 Subject: [PATCH] feat: add basic webui --- .cargo/config.toml | 4 +- .editorconfig | 10 + .gitignore | 37 +- .prettierignore | 14 + .vscode/extensions.json | 10 + .vscode/launch.json | 57 +- .vscode/settings.json | 33 +- Cargo.toml | 2 +- apps/api/.env.development | 15 + apps/api/.env.example | 15 + apps/{webui => api}/.gitignore | 11 +- apps/api/app/apple-icon.png | Bin 0 -> 216 bytes apps/api/app/cron/keep-alive/route.ts | 17 + apps/api/app/global-error.tsx | 29 + apps/api/app/health/route.ts | 3 + apps/api/app/icon.png | Bin 0 -> 96 bytes apps/api/app/layout.tsx | 13 + apps/api/app/opengraph-image.png | Bin 0 -> 58106 bytes apps/api/instrumentation.ts | 3 + apps/api/next.config.ts | 15 + apps/api/package.json | 37 + apps/api/sentry.client.config.ts | 34 + apps/api/tsconfig.json | 17 + apps/api/vercel.json | 8 + apps/app/.env.development | 15 + apps/app/.env.example | 15 + apps/app/.gitignore | 45 + apps/app/__tests__/sign-in.test.tsx | 13 + apps/app/__tests__/sign-up.test.tsx | 13 + .../components/avatar-stack.tsx | 59 + .../components/collaboration-provider.tsx | 48 + .../(authenticated)/components/cursors.tsx | 106 + .../app/(authenticated)/components/header.tsx | 43 + .../components/posthog-identifier.tsx | 44 + .../(authenticated)/components/sidebar.tsx | 342 + apps/app/app/(authenticated)/layout.tsx | 42 + apps/app/app/(authenticated)/page.tsx | 57 + .../app/app/(authenticated)/webhooks/page.tsx | 29 + apps/app/app/(unauthenticated)/layout.tsx | 58 + .../sign-in/[[...sign-in]]/page.tsx | 23 + .../sign-up/[[...sign-up]]/page.tsx | 23 + .../app/app/.well-known/vercel/flags/route.ts | 3 + apps/app/app/actions/users/get.ts | 63 + apps/app/app/actions/users/search.ts | 50 + apps/app/app/api/collaboration/auth/route.ts | 42 + apps/app/app/apple-icon.png | Bin 0 -> 216 bytes apps/app/app/global-error.tsx | 29 + apps/app/app/icon.png | Bin 0 -> 96 bytes apps/app/app/layout.tsx | 18 + apps/app/app/opengraph-image.png | Bin 0 -> 58106 bytes apps/app/instrumentation.ts | 3 + apps/app/liveblocks.config.ts | 1 + apps/app/middleware.ts | 22 + apps/app/next.config.ts | 15 + apps/app/package.json | 51 + apps/app/postcss.config.mjs | 1 + apps/app/sentry.client.config.ts | 34 + apps/app/tailwind.config.ts | 1 + apps/app/tsconfig.json | 17 + apps/app/vitest.config.ts | 1 + apps/docs/api-reference/endpoint/create.mdx | 4 + apps/docs/api-reference/endpoint/delete.mdx | 4 + apps/docs/api-reference/endpoint/get.mdx | 4 + apps/docs/api-reference/introduction.mdx | 33 + apps/docs/api-reference/openapi.json | 195 + apps/docs/development.mdx | 98 + apps/docs/essentials/code.mdx | 37 + apps/docs/essentials/images.mdx | 59 + apps/docs/essentials/markdown.mdx | 88 + apps/docs/essentials/navigation.mdx | 66 + apps/docs/essentials/reusable-snippets.mdx | 110 + apps/docs/essentials/settings.mdx | 318 + apps/docs/favicon.svg | 49 + apps/docs/images/checks-passed.png | Bin 0 -> 160724 bytes apps/docs/images/hero-dark.svg | 161 + apps/docs/images/hero-light.svg | 155 + apps/docs/introduction.mdx | 71 + apps/docs/logo/dark.svg | 55 + apps/docs/logo/light.svg | 51 + apps/docs/mint.json | 85 + apps/docs/package.json | 11 + apps/docs/quickstart.mdx | 86 + apps/docs/snippets/snippet-intro.mdx | 4 + apps/email-playground/.gitignore | 1 + apps/email-playground/emails/contact.tsx | 11 + apps/email-playground/package.json | 24 + apps/email-playground/tsconfig.json | 5 + apps/proxy/package.json | 6 +- .../recorder/.devcontainer/Dockerfile | 0 .../recorder/.devcontainer/devcontainer.json | 0 .../recorder/.devcontainer/docker-compose.yml | 0 .../recorder/.github/workflows/ci.yaml | 0 {crates => apps}/recorder/.gitignore | 0 {crates => apps}/recorder/Cargo.toml | 4 +- .../recorder/examples/playground.rs | 0 {crates => apps}/recorder/src/app.rs | 0 {crates => apps}/recorder/src/bin/main.rs | 0 {crates => apps}/recorder/src/config/mod.rs | 0 .../recorder/src/controllers/mod.rs | 0 .../recorder/src/controllers/subscribers.rs | 0 {crates => apps}/recorder/src/dal/client.rs | 0 {crates => apps}/recorder/src/dal/config.rs | 0 {crates => apps}/recorder/src/dal/mod.rs | 0 {crates => apps}/recorder/src/extract/defs.rs | 0 .../recorder/src/extract/errors.rs | 0 .../recorder/src/extract/html/mod.rs | 0 .../recorder/src/extract/html/styles.rs | 0 .../recorder/src/extract/mikan/client.rs | 0 .../recorder/src/extract/mikan/config.rs | 0 .../recorder/src/extract/mikan/constants.rs | 0 .../recorder/src/extract/mikan/mod.rs | 0 .../recorder/src/extract/mikan/rss_parser.rs | 0 .../recorder/src/extract/mikan/web_parser.rs | 0 {crates => apps}/recorder/src/extract/mod.rs | 0 .../recorder/src/extract/rawname/mod.rs | 0 .../recorder/src/extract/rawname/parser.rs | 2 +- .../recorder/src/extract/torrent/mod.rs | 0 .../recorder/src/extract/torrent/parser.rs | 0 {crates => apps}/recorder/src/fetch/bytes.rs | 0 {crates => apps}/recorder/src/fetch/client.rs | 0 {crates => apps}/recorder/src/fetch/core.rs | 0 {crates => apps}/recorder/src/fetch/html.rs | 0 {crates => apps}/recorder/src/fetch/image.rs | 0 {crates => apps}/recorder/src/fetch/mod.rs | 0 {crates => apps}/recorder/src/lib.rs | 0 .../recorder/src/migrations/defs.rs | 0 .../src/migrations/m20220101_000001_init.rs | 0 .../m20240224_082543_add_downloads.rs | 0 ...240225_060853_subscriber_add_downloader.rs | 0 .../recorder/src/migrations/mod.rs | 0 .../recorder/src/models/bangumi.rs | 0 .../recorder/src/models/downloaders.rs | 0 .../recorder/src/models/downloads.rs | 0 .../recorder/src/models/entities/bangumi.rs | 0 .../src/models/entities/downloaders.rs | 0 .../recorder/src/models/entities/downloads.rs | 0 .../recorder/src/models/entities/episodes.rs | 0 .../recorder/src/models/entities/mod.rs | 0 .../src/models/entities/subscribers.rs | 0 .../src/models/entities/subscriptions.rs | 0 .../recorder/src/models/episodes.rs | 0 {crates => apps}/recorder/src/models/mod.rs | 0 .../recorder/src/models/notifications.rs | 0 .../recorder/src/models/prelude.rs | 0 .../recorder/src/models/query/mod.rs | 0 .../recorder/src/models/subscribers.rs | 0 .../recorder/src/models/subscriptions.rs | 20 +- {crates => apps}/recorder/src/tasks/mod.rs | 0 {crates => apps}/recorder/src/views/mod.rs | 0 .../recorder/src/views/subscribers.rs | 0 {crates => apps}/recorder/src/workers/mod.rs | 0 .../src/workers/subscription_worker.rs | 0 {crates => apps}/recorder/tests/mod.rs | 0 {crates => apps}/recorder/tests/models/mod.rs | 0 .../can_find_by_pid@subscribers-2.snap | 0 .../can_find_by_pid@subscribers.snap | 0 .../recorder/tests/models/subscribers.rs | 0 .../recorder/tests/requests/mod.rs | 0 .../recorder/tests/requests/subscribers.rs | 21 +- {crates => apps}/recorder/tests/tasks/mod.rs | 0 {crates => apps}/recorder/tests/tasks/seed.rs | 6 +- apps/storybook/.gitignore | 45 + apps/storybook/.storybook/main.ts | 30 + apps/storybook/.storybook/preview-head.html | 17 + apps/storybook/.storybook/preview.tsx | 53 + apps/storybook/README.md | 40 + apps/storybook/next.config.ts | 7 + apps/storybook/package.json | 39 + apps/storybook/postcss.config.mjs | 8 + .../app => storybook/public}/favicon.ico | Bin apps/storybook/stories/accordion.stories.tsx | 60 + .../stories/alert-dialog.stories.tsx | 54 + apps/storybook/stories/alert.stories.tsx | 60 + .../stories/aspect-ratio.stories.tsx | 71 + apps/storybook/stories/avatar.stories.tsx | 35 + apps/storybook/stories/badge.stories.tsx | 62 + apps/storybook/stories/breadcrumb.stories.tsx | 78 + apps/storybook/stories/button.stories.tsx | 157 + apps/storybook/stories/calendar.stories.tsx | 81 + apps/storybook/stories/card.stories.tsx | 75 + apps/storybook/stories/carousel.stories.tsx | 73 + apps/storybook/stories/chart.stories.tsx | 271 + apps/storybook/stories/checkbox.stories.tsx | 50 + .../storybook/stories/collapsible.stories.tsx | 55 + apps/storybook/stories/command.stories.tsx | 55 + .../stories/context-menu.stories.tsx | 153 + apps/storybook/stories/dialog.stories.tsx | 62 + apps/storybook/stories/drawer.stories.tsx | 58 + .../stories/dropdown-menu.stories.tsx | 159 + apps/storybook/stories/form.stories.tsx | 85 + apps/storybook/stories/hover-card.stories.tsx | 49 + apps/storybook/stories/input-otp.stories.tsx | 70 + apps/storybook/stories/input.stories.tsx | 84 + apps/storybook/stories/label.stories.tsx | 30 + apps/storybook/stories/menubar.stories.tsx | 126 + .../stories/navigation-menu.stories.tsx | 79 + apps/storybook/stories/pagination.stories.tsx | 57 + apps/storybook/stories/popover.stories.tsx | 36 + apps/storybook/stories/progress.stories.tsx | 45 + .../storybook/stories/radio-group.stories.tsx | 40 + apps/storybook/stories/resizable.stories.tsx | 59 + .../storybook/stories/scroll-area.stories.tsx | 62 + apps/storybook/stories/select.stories.tsx | 70 + apps/storybook/stories/separator.stories.tsx | 43 + apps/storybook/stories/sheet.stories.tsx | 72 + apps/storybook/stories/sidebar.stories.tsx | 494 + apps/storybook/stories/skeleton.stories.tsx | 35 + apps/storybook/stories/slider.stories.tsx | 45 + apps/storybook/stories/sonner.stories.tsx | 50 + apps/storybook/stories/switch.stories.tsx | 47 + apps/storybook/stories/table.stories.tsx | 80 + apps/storybook/stories/tabs.stories.tsx | 47 + apps/storybook/stories/textarea.stories.tsx | 82 + apps/storybook/stories/toast.stories.tsx | 94 + .../stories/toggle-group.stories.tsx | 102 + apps/storybook/stories/toggle.stories.tsx | 87 + apps/storybook/stories/tooltip.stories.tsx | 84 + apps/storybook/tailwind.config.ts | 1 + apps/storybook/tsconfig.json | 13 + apps/web/.env.development | 15 + apps/web/.env.example | 15 + apps/web/.gitignore | 48 + apps/web/.well-known/vercel/flags/route.ts | 3 + apps/web/app/(home)/components/cases.tsx | 53 + apps/web/app/(home)/components/cta.tsx | 35 + apps/web/app/(home)/components/faq.tsx | 55 + apps/web/app/(home)/components/features.tsx | 63 + apps/web/app/(home)/components/hero.tsx | 64 + apps/web/app/(home)/components/stats.tsx | 75 + .../app/(home)/components/testimonials.tsx | 78 + apps/web/app/(home)/page.tsx | 41 + apps/web/app/apple-icon.png | Bin 0 -> 216 bytes apps/web/app/blog/[slug]/page.tsx | 132 + apps/web/app/blog/layout.tsx | 15 + apps/web/app/blog/page.tsx | 87 + apps/web/app/components/footer.tsx | 118 + apps/web/app/components/header/index.tsx | 195 + apps/web/app/components/header/logo.svg | 1 + apps/web/app/contact/actions/contact.tsx | 48 + .../app/contact/components/contact-form.tsx | 116 + apps/web/app/contact/page.tsx | 16 + apps/web/app/global-error.tsx | 29 + apps/web/app/icon.png | Bin 0 -> 96 bytes apps/web/app/layout.tsx | 30 + apps/web/app/legal/[slug]/page.tsx | 98 + apps/web/app/legal/layout.tsx | 15 + apps/web/app/opengraph-image.png | Bin 0 -> 58106 bytes apps/web/app/pricing/page.tsx | 156 + apps/web/app/robots.ts | 15 + apps/web/app/sitemap.ts | 49 + apps/web/app/styles/web.css | 36 + apps/web/components/sidebar.tsx | 50 + apps/web/content-collections.ts | 1 + apps/web/content/blog/my-first-blog.mdx | 6 + apps/web/instrumentation.ts | 3 + apps/web/middleware.ts | 41 + apps/web/next.config.ts | 33 + apps/web/package.json | 55 + apps/web/postcss.config.mjs | 1 + apps/web/tailwind.config.ts | 1 + apps/web/tsconfig.json | 20 + apps/web/vercel.json | 3 + apps/webui/.eslintrc.mjs | 6 - apps/webui/README.md | 36 - apps/webui/app/globals.css | 76 - apps/webui/app/layout.tsx | 22 - apps/webui/app/page.tsx | 113 - apps/webui/components.json | 17 - apps/webui/lib/utils.ts | 6 - apps/webui/next.config.mjs | 7 - apps/webui/package.json | 37 - apps/webui/postcss.config.js | 6 - apps/webui/public/next.svg | 1 - apps/webui/public/vercel.svg | 1 - apps/webui/tailwind.config.ts | 80 - apps/webui/tsconfig.json | 40 - biome.json | 31 + .../development.yaml} | 4 +- .../production.yaml} | 0 .../test.yaml} | 0 docker-compose.yaml | 31 + justfile | 15 +- package.json | 55 +- packages/ai/components/message.tsx | 22 + packages/ai/components/thread.tsx | 16 + packages/ai/index.ts | 1 + packages/ai/lib/provider.ts | 7 + packages/ai/lib/react.ts | 1 + packages/ai/package.json | 23 + packages/ai/tsconfig.json | 8 + packages/analytics/client.tsx | 23 + packages/analytics/index.tsx | 12 + packages/analytics/package.json | 20 + packages/analytics/server.ts | 13 + packages/analytics/tsconfig.json | 8 + packages/auth/better-auth.config.ts | 18 + packages/auth/client.ts | 6 + packages/auth/components/sign-in.tsx | 33 + packages/auth/components/sign-up.tsx | 40 + packages/auth/middleware.ts | 21 + packages/auth/package.json | 29 + packages/auth/provider.tsx | 7 + packages/auth/server.ts | 41 + packages/auth/tsconfig.json | 8 + packages/cms/collections.ts | 89 + packages/cms/components/body.tsx | 10 + packages/cms/components/image.tsx | 1 + packages/cms/components/toc.tsx | 31 + packages/cms/components/toolbar.tsx | 1 + packages/cms/index.ts | 23 + packages/cms/next-config.ts | 1 + packages/cms/package.json | 30 + packages/cms/tsconfig.json | 8 + packages/cms/typescript-config.json | 7 + packages/collaboration/auth.ts | 31 + packages/collaboration/config.ts | 49 + packages/collaboration/hooks.ts | 1 + packages/collaboration/package.json | 23 + packages/collaboration/room.tsx | 37 + packages/collaboration/tsconfig.json | 8 + packages/database/.gitignore | 3 + packages/database/builder.ts | 47 + packages/database/index.ts | 12 + packages/database/migrate/migrator.ts | 0 .../migrations/m20241229_000001_init.ts | 15 + packages/database/package.json | 25 + packages/database/schema/database.ts | 5 + packages/database/schema/page.ts | 10 + packages/database/tsconfig.json | 8 + packages/design-system/components.json | 19 + .../design-system/components/mode-toggle.tsx | 44 + .../design-system/components/ui/accordion.tsx | 56 + .../components/ui/alert-dialog.tsx | 141 + .../design-system/components/ui/alert.tsx | 59 + .../components/ui/aspect-ratio.tsx | 7 + .../design-system/components/ui/avatar.tsx | 50 + .../design-system/components/ui/badge.tsx | 36 + .../components/ui/breadcrumb.tsx | 114 + .../design-system/components/ui/button.tsx | 57 + .../design-system/components/ui/calendar.tsx | 72 + packages/design-system/components/ui/card.tsx | 76 + .../design-system/components/ui/carousel.tsx | 261 + .../design-system/components/ui/chart.tsx | 370 + .../design-system/components/ui/checkbox.tsx | 29 + .../components/ui/collapsible.tsx | 11 + .../design-system/components/ui/command.tsx | 152 + .../components/ui/context-menu.tsx | 199 + .../design-system/components/ui/dialog.tsx | 121 + .../design-system/components/ui/drawer.tsx | 118 + .../components/ui/dropdown-menu.tsx | 200 + packages/design-system/components/ui/form.tsx | 178 + .../components/ui/hover-card.tsx | 29 + .../design-system/components/ui/input-otp.tsx | 70 + .../design-system/components/ui/input.tsx | 22 + .../design-system/components/ui/label.tsx | 26 + .../design-system/components/ui/menubar.tsx | 235 + .../components/ui/navigation-menu.tsx | 127 + .../components/ui/pagination.tsx | 116 + .../design-system/components/ui/popover.tsx | 33 + .../design-system/components/ui/progress.tsx | 28 + .../components/ui/radio-group.tsx | 43 + .../design-system/components/ui/resizable.tsx | 44 + .../components/ui/scroll-area.tsx | 48 + .../design-system/components/ui/select.tsx | 158 + .../design-system/components/ui/separator.tsx | 31 + .../design-system/components/ui/sheet.tsx | 139 + .../design-system/components/ui/sidebar.tsx | 763 + .../design-system/components/ui/skeleton.tsx | 15 + .../design-system/components/ui/slider.tsx | 28 + .../design-system/components/ui/sonner.tsx | 31 + .../design-system/components/ui/switch.tsx | 29 + .../design-system/components/ui/table.tsx | 120 + packages/design-system/components/ui/tabs.tsx | 55 + .../design-system/components/ui/textarea.tsx | 22 + .../design-system/components/ui/toast.tsx | 128 + .../design-system/components/ui/toaster.tsx | 35 + .../components/ui/toggle-group.tsx | 61 + .../design-system/components/ui/toggle.tsx | 45 + .../design-system/components/ui/tooltip.tsx | 32 + .../design-system/components/ui/use-toast.ts | 194 + packages/design-system/hooks/use-mobile.tsx | 19 + packages/design-system/hooks/use-toast.ts | 194 + packages/design-system/index.tsx | 28 + packages/design-system/lib/fonts.ts | 9 + packages/design-system/lib/utils.ts | 16 + packages/design-system/package.json | 74 + packages/design-system/postcss.config.mjs | 9 + packages/design-system/providers/theme.tsx | 17 + packages/design-system/styles/globals.css | 130 + packages/design-system/tsconfig.json | 17 + packages/email/index.tsx | 17 + packages/email/package.json | 22 + packages/email/templates/contact.tsx | 56 + packages/email/tsconfig.json | 8 + packages/env/index.ts | 69 + packages/env/package.json | 18 + packages/env/tsconfig.json | 10 + packages/feature-flags/access.ts | 26 + packages/feature-flags/index.ts | 3 + packages/feature-flags/lib/create-flag.ts | 20 + packages/feature-flags/package.json | 22 + packages/feature-flags/tsconfig.json | 8 + packages/migrate/.gitignore | 3 + packages/migrate/index.ts | 83 + packages/migrate/package.json | 22 + packages/migrate/scripts/down.ts | 12 + packages/migrate/scripts/up.ts | 12 + packages/migrate/tsconfig.json | 8 + packages/next-config/index.ts | 101 + packages/next-config/instrumentation.ts | 16 + packages/next-config/package.json | 21 + packages/next-config/tsconfig.json | 8 + packages/observability/error.ts | 24 + packages/observability/log.ts | 3 + packages/observability/package.json | 22 + packages/observability/status/index.tsx | 66 + packages/observability/status/types.ts | 62 + packages/observability/tsconfig.json | 8 + {crates => packages}/quirks-path/Cargo.toml | 0 {crates => packages}/quirks-path/src/lib.rs | 35 +- {crates => packages}/quirks-path/src/url.rs | 2 +- .../quirks-path/src/windows.rs | 6 +- packages/rate-limit/index.ts | 17 + packages/rate-limit/package.json | 18 + packages/security/index.ts | 45 + packages/security/middleware.ts | 23 + packages/security/package.json | 20 + packages/security/tsconfig.json | 8 + packages/seo/json-ld.tsx | 15 + packages/seo/metadata.ts | 67 + packages/seo/package.json | 22 + packages/seo/tsconfig.json | 8 + packages/storage/client.ts | 1 + packages/storage/index.ts | 1 + packages/storage/package.json | 15 + packages/storage/tsconfig.json | 8 + packages/tailwind-config/config.ts | 106 + packages/tailwind-config/index.ts | 4 + packages/tailwind-config/package.json | 18 + packages/tailwind-config/tsconfig.json | 8 + packages/tailwind-config/typography.config.ts | 96 + packages/testing/package.json | 15 + packages/testing/tsconfig.json | 8 + {crates => packages}/torrent/.gitignore | 0 {crates => packages}/torrent/Cargo.toml | 2 +- {crates => packages}/torrent/src/core.rs | 0 {crates => packages}/torrent/src/error.rs | 0 {crates => packages}/torrent/src/lib.rs | 0 {crates => packages}/torrent/src/qbit.rs | 21 +- packages/typescript-config/base.json | 21 + packages/typescript-config/nextjs.json | 18 + packages/typescript-config/package.json | 9 + packages/typescript-config/react-library.json | 8 + packages/webhooks/index.ts | 6 + packages/webhooks/lib/svix.ts | 51 + packages/webhooks/package.json | 18 + pnpm-lock.yaml | 20168 ++++++++++++++-- turbo.json | 41 + turbo/generators/config.ts | 37 + turbo/generators/package.json | 3 + turbo/generators/templates/package.json.hbs | 9 + turbo/generators/templates/tsconfig.json.hbs | 12 + 462 files changed, 35900 insertions(+), 2491 deletions(-) create mode 100644 .editorconfig create mode 100644 .prettierignore create mode 100644 .vscode/extensions.json create mode 100644 apps/api/.env.development create mode 100644 apps/api/.env.example rename apps/{webui => api}/.gitignore (81%) create mode 100644 apps/api/app/apple-icon.png create mode 100644 apps/api/app/cron/keep-alive/route.ts create mode 100644 apps/api/app/global-error.tsx create mode 100644 apps/api/app/health/route.ts create mode 100644 apps/api/app/icon.png create mode 100644 apps/api/app/layout.tsx create mode 100644 apps/api/app/opengraph-image.png create mode 100644 apps/api/instrumentation.ts create mode 100644 apps/api/next.config.ts create mode 100644 apps/api/package.json create mode 100644 apps/api/sentry.client.config.ts create mode 100644 apps/api/tsconfig.json create mode 100644 apps/api/vercel.json create mode 100644 apps/app/.env.development create mode 100644 apps/app/.env.example create mode 100644 apps/app/.gitignore create mode 100644 apps/app/__tests__/sign-in.test.tsx create mode 100644 apps/app/__tests__/sign-up.test.tsx create mode 100644 apps/app/app/(authenticated)/components/avatar-stack.tsx create mode 100644 apps/app/app/(authenticated)/components/collaboration-provider.tsx create mode 100644 apps/app/app/(authenticated)/components/cursors.tsx create mode 100644 apps/app/app/(authenticated)/components/header.tsx create mode 100644 apps/app/app/(authenticated)/components/posthog-identifier.tsx create mode 100644 apps/app/app/(authenticated)/components/sidebar.tsx create mode 100644 apps/app/app/(authenticated)/layout.tsx create mode 100644 apps/app/app/(authenticated)/page.tsx create mode 100644 apps/app/app/(authenticated)/webhooks/page.tsx create mode 100644 apps/app/app/(unauthenticated)/layout.tsx create mode 100644 apps/app/app/(unauthenticated)/sign-in/[[...sign-in]]/page.tsx create mode 100644 apps/app/app/(unauthenticated)/sign-up/[[...sign-up]]/page.tsx create mode 100644 apps/app/app/.well-known/vercel/flags/route.ts create mode 100644 apps/app/app/actions/users/get.ts create mode 100644 apps/app/app/actions/users/search.ts create mode 100644 apps/app/app/api/collaboration/auth/route.ts create mode 100644 apps/app/app/apple-icon.png create mode 100644 apps/app/app/global-error.tsx create mode 100644 apps/app/app/icon.png create mode 100644 apps/app/app/layout.tsx create mode 100644 apps/app/app/opengraph-image.png create mode 100644 apps/app/instrumentation.ts create mode 100644 apps/app/liveblocks.config.ts create mode 100644 apps/app/middleware.ts create mode 100644 apps/app/next.config.ts create mode 100644 apps/app/package.json create mode 100644 apps/app/postcss.config.mjs create mode 100644 apps/app/sentry.client.config.ts create mode 100644 apps/app/tailwind.config.ts create mode 100644 apps/app/tsconfig.json create mode 100644 apps/app/vitest.config.ts create mode 100644 apps/docs/api-reference/endpoint/create.mdx create mode 100644 apps/docs/api-reference/endpoint/delete.mdx create mode 100644 apps/docs/api-reference/endpoint/get.mdx create mode 100644 apps/docs/api-reference/introduction.mdx create mode 100644 apps/docs/api-reference/openapi.json create mode 100644 apps/docs/development.mdx create mode 100644 apps/docs/essentials/code.mdx create mode 100644 apps/docs/essentials/images.mdx create mode 100644 apps/docs/essentials/markdown.mdx create mode 100644 apps/docs/essentials/navigation.mdx create mode 100644 apps/docs/essentials/reusable-snippets.mdx create mode 100644 apps/docs/essentials/settings.mdx create mode 100644 apps/docs/favicon.svg create mode 100644 apps/docs/images/checks-passed.png create mode 100644 apps/docs/images/hero-dark.svg create mode 100644 apps/docs/images/hero-light.svg create mode 100644 apps/docs/introduction.mdx create mode 100644 apps/docs/logo/dark.svg create mode 100644 apps/docs/logo/light.svg create mode 100644 apps/docs/mint.json create mode 100644 apps/docs/package.json create mode 100644 apps/docs/quickstart.mdx create mode 100644 apps/docs/snippets/snippet-intro.mdx create mode 100644 apps/email-playground/.gitignore create mode 100644 apps/email-playground/emails/contact.tsx create mode 100644 apps/email-playground/package.json create mode 100644 apps/email-playground/tsconfig.json rename {crates => apps}/recorder/.devcontainer/Dockerfile (100%) rename {crates => apps}/recorder/.devcontainer/devcontainer.json (100%) rename {crates => apps}/recorder/.devcontainer/docker-compose.yml (100%) rename {crates => apps}/recorder/.github/workflows/ci.yaml (100%) rename {crates => apps}/recorder/.gitignore (100%) rename {crates => apps}/recorder/Cargo.toml (93%) rename {crates => apps}/recorder/examples/playground.rs (100%) rename {crates => apps}/recorder/src/app.rs (100%) rename {crates => apps}/recorder/src/bin/main.rs (100%) rename {crates => apps}/recorder/src/config/mod.rs (100%) rename {crates => apps}/recorder/src/controllers/mod.rs (100%) rename {crates => apps}/recorder/src/controllers/subscribers.rs (100%) rename {crates => apps}/recorder/src/dal/client.rs (100%) rename {crates => apps}/recorder/src/dal/config.rs (100%) rename {crates => apps}/recorder/src/dal/mod.rs (100%) rename {crates => apps}/recorder/src/extract/defs.rs (100%) rename {crates => apps}/recorder/src/extract/errors.rs (100%) rename {crates => apps}/recorder/src/extract/html/mod.rs (100%) rename {crates => apps}/recorder/src/extract/html/styles.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/client.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/config.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/constants.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/mod.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/rss_parser.rs (100%) rename {crates => apps}/recorder/src/extract/mikan/web_parser.rs (100%) rename {crates => apps}/recorder/src/extract/mod.rs (100%) rename {crates => apps}/recorder/src/extract/rawname/mod.rs (100%) rename {crates => apps}/recorder/src/extract/rawname/parser.rs (99%) rename {crates => apps}/recorder/src/extract/torrent/mod.rs (100%) rename {crates => apps}/recorder/src/extract/torrent/parser.rs (100%) rename {crates => apps}/recorder/src/fetch/bytes.rs (100%) rename {crates => apps}/recorder/src/fetch/client.rs (100%) rename {crates => apps}/recorder/src/fetch/core.rs (100%) rename {crates => apps}/recorder/src/fetch/html.rs (100%) rename {crates => apps}/recorder/src/fetch/image.rs (100%) rename {crates => apps}/recorder/src/fetch/mod.rs (100%) rename {crates => apps}/recorder/src/lib.rs (100%) rename {crates => apps}/recorder/src/migrations/defs.rs (100%) rename {crates => apps}/recorder/src/migrations/m20220101_000001_init.rs (100%) rename {crates => apps}/recorder/src/migrations/m20240224_082543_add_downloads.rs (100%) rename {crates => apps}/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs (100%) rename {crates => apps}/recorder/src/migrations/mod.rs (100%) rename {crates => apps}/recorder/src/models/bangumi.rs (100%) rename {crates => apps}/recorder/src/models/downloaders.rs (100%) rename {crates => apps}/recorder/src/models/downloads.rs (100%) rename {crates => apps}/recorder/src/models/entities/bangumi.rs (100%) rename {crates => apps}/recorder/src/models/entities/downloaders.rs (100%) rename {crates => apps}/recorder/src/models/entities/downloads.rs (100%) rename {crates => apps}/recorder/src/models/entities/episodes.rs (100%) rename {crates => apps}/recorder/src/models/entities/mod.rs (100%) rename {crates => apps}/recorder/src/models/entities/subscribers.rs (100%) rename {crates => apps}/recorder/src/models/entities/subscriptions.rs (100%) rename {crates => apps}/recorder/src/models/episodes.rs (100%) rename {crates => apps}/recorder/src/models/mod.rs (100%) rename {crates => apps}/recorder/src/models/notifications.rs (100%) rename {crates => apps}/recorder/src/models/prelude.rs (100%) rename {crates => apps}/recorder/src/models/query/mod.rs (100%) rename {crates => apps}/recorder/src/models/subscribers.rs (100%) rename {crates => apps}/recorder/src/models/subscriptions.rs (93%) rename {crates => apps}/recorder/src/tasks/mod.rs (100%) rename {crates => apps}/recorder/src/views/mod.rs (100%) rename {crates => apps}/recorder/src/views/subscribers.rs (100%) rename {crates => apps}/recorder/src/workers/mod.rs (100%) rename {crates => apps}/recorder/src/workers/subscription_worker.rs (100%) rename {crates => apps}/recorder/tests/mod.rs (100%) rename {crates => apps}/recorder/tests/models/mod.rs (100%) rename {crates => apps}/recorder/tests/models/snapshots/can_find_by_pid@subscribers-2.snap (100%) rename {crates => apps}/recorder/tests/models/snapshots/can_find_by_pid@subscribers.snap (100%) rename {crates => apps}/recorder/tests/models/subscribers.rs (100%) rename {crates => apps}/recorder/tests/requests/mod.rs (100%) rename {crates => apps}/recorder/tests/requests/subscribers.rs (58%) rename {crates => apps}/recorder/tests/tasks/mod.rs (100%) rename {crates => apps}/recorder/tests/tasks/seed.rs (87%) create mode 100644 apps/storybook/.gitignore create mode 100644 apps/storybook/.storybook/main.ts create mode 100644 apps/storybook/.storybook/preview-head.html create mode 100644 apps/storybook/.storybook/preview.tsx create mode 100644 apps/storybook/README.md create mode 100644 apps/storybook/next.config.ts create mode 100644 apps/storybook/package.json create mode 100644 apps/storybook/postcss.config.mjs rename apps/{webui/app => storybook/public}/favicon.ico (100%) create mode 100644 apps/storybook/stories/accordion.stories.tsx create mode 100644 apps/storybook/stories/alert-dialog.stories.tsx create mode 100644 apps/storybook/stories/alert.stories.tsx create mode 100644 apps/storybook/stories/aspect-ratio.stories.tsx create mode 100644 apps/storybook/stories/avatar.stories.tsx create mode 100644 apps/storybook/stories/badge.stories.tsx create mode 100644 apps/storybook/stories/breadcrumb.stories.tsx create mode 100644 apps/storybook/stories/button.stories.tsx create mode 100644 apps/storybook/stories/calendar.stories.tsx create mode 100644 apps/storybook/stories/card.stories.tsx create mode 100644 apps/storybook/stories/carousel.stories.tsx create mode 100644 apps/storybook/stories/chart.stories.tsx create mode 100644 apps/storybook/stories/checkbox.stories.tsx create mode 100644 apps/storybook/stories/collapsible.stories.tsx create mode 100644 apps/storybook/stories/command.stories.tsx create mode 100644 apps/storybook/stories/context-menu.stories.tsx create mode 100644 apps/storybook/stories/dialog.stories.tsx create mode 100644 apps/storybook/stories/drawer.stories.tsx create mode 100644 apps/storybook/stories/dropdown-menu.stories.tsx create mode 100644 apps/storybook/stories/form.stories.tsx create mode 100644 apps/storybook/stories/hover-card.stories.tsx create mode 100644 apps/storybook/stories/input-otp.stories.tsx create mode 100644 apps/storybook/stories/input.stories.tsx create mode 100644 apps/storybook/stories/label.stories.tsx create mode 100644 apps/storybook/stories/menubar.stories.tsx create mode 100644 apps/storybook/stories/navigation-menu.stories.tsx create mode 100644 apps/storybook/stories/pagination.stories.tsx create mode 100644 apps/storybook/stories/popover.stories.tsx create mode 100644 apps/storybook/stories/progress.stories.tsx create mode 100644 apps/storybook/stories/radio-group.stories.tsx create mode 100644 apps/storybook/stories/resizable.stories.tsx create mode 100644 apps/storybook/stories/scroll-area.stories.tsx create mode 100644 apps/storybook/stories/select.stories.tsx create mode 100644 apps/storybook/stories/separator.stories.tsx create mode 100644 apps/storybook/stories/sheet.stories.tsx create mode 100644 apps/storybook/stories/sidebar.stories.tsx create mode 100644 apps/storybook/stories/skeleton.stories.tsx create mode 100644 apps/storybook/stories/slider.stories.tsx create mode 100644 apps/storybook/stories/sonner.stories.tsx create mode 100644 apps/storybook/stories/switch.stories.tsx create mode 100644 apps/storybook/stories/table.stories.tsx create mode 100644 apps/storybook/stories/tabs.stories.tsx create mode 100644 apps/storybook/stories/textarea.stories.tsx create mode 100644 apps/storybook/stories/toast.stories.tsx create mode 100644 apps/storybook/stories/toggle-group.stories.tsx create mode 100644 apps/storybook/stories/toggle.stories.tsx create mode 100644 apps/storybook/stories/tooltip.stories.tsx create mode 100644 apps/storybook/tailwind.config.ts create mode 100644 apps/storybook/tsconfig.json create mode 100644 apps/web/.env.development create mode 100644 apps/web/.env.example create mode 100644 apps/web/.gitignore create mode 100644 apps/web/.well-known/vercel/flags/route.ts create mode 100644 apps/web/app/(home)/components/cases.tsx create mode 100644 apps/web/app/(home)/components/cta.tsx create mode 100644 apps/web/app/(home)/components/faq.tsx create mode 100644 apps/web/app/(home)/components/features.tsx create mode 100644 apps/web/app/(home)/components/hero.tsx create mode 100644 apps/web/app/(home)/components/stats.tsx create mode 100644 apps/web/app/(home)/components/testimonials.tsx create mode 100644 apps/web/app/(home)/page.tsx create mode 100644 apps/web/app/apple-icon.png create mode 100644 apps/web/app/blog/[slug]/page.tsx create mode 100644 apps/web/app/blog/layout.tsx create mode 100644 apps/web/app/blog/page.tsx create mode 100644 apps/web/app/components/footer.tsx create mode 100644 apps/web/app/components/header/index.tsx create mode 100644 apps/web/app/components/header/logo.svg create mode 100644 apps/web/app/contact/actions/contact.tsx create mode 100644 apps/web/app/contact/components/contact-form.tsx create mode 100644 apps/web/app/contact/page.tsx create mode 100644 apps/web/app/global-error.tsx create mode 100644 apps/web/app/icon.png create mode 100644 apps/web/app/layout.tsx create mode 100644 apps/web/app/legal/[slug]/page.tsx create mode 100644 apps/web/app/legal/layout.tsx create mode 100644 apps/web/app/opengraph-image.png create mode 100644 apps/web/app/pricing/page.tsx create mode 100644 apps/web/app/robots.ts create mode 100644 apps/web/app/sitemap.ts create mode 100644 apps/web/app/styles/web.css create mode 100644 apps/web/components/sidebar.tsx create mode 100644 apps/web/content-collections.ts create mode 100644 apps/web/content/blog/my-first-blog.mdx create mode 100644 apps/web/instrumentation.ts create mode 100644 apps/web/middleware.ts create mode 100644 apps/web/next.config.ts create mode 100644 apps/web/package.json create mode 100644 apps/web/postcss.config.mjs create mode 100644 apps/web/tailwind.config.ts create mode 100644 apps/web/tsconfig.json create mode 100644 apps/web/vercel.json delete mode 100644 apps/webui/.eslintrc.mjs delete mode 100644 apps/webui/README.md delete mode 100644 apps/webui/app/globals.css delete mode 100644 apps/webui/app/layout.tsx delete mode 100644 apps/webui/app/page.tsx delete mode 100644 apps/webui/components.json delete mode 100644 apps/webui/lib/utils.ts delete mode 100644 apps/webui/next.config.mjs delete mode 100644 apps/webui/package.json delete mode 100644 apps/webui/postcss.config.js delete mode 100644 apps/webui/public/next.svg delete mode 100644 apps/webui/public/vercel.svg delete mode 100644 apps/webui/tailwind.config.ts delete mode 100644 apps/webui/tsconfig.json create mode 100644 biome.json rename config/{recorder.test.yaml => recorder/development.yaml} (99%) rename config/{recorder.production.yaml => recorder/production.yaml} (100%) rename config/{recorder.development.yaml => recorder/test.yaml} (100%) create mode 100644 docker-compose.yaml create mode 100644 packages/ai/components/message.tsx create mode 100644 packages/ai/components/thread.tsx create mode 100644 packages/ai/index.ts create mode 100644 packages/ai/lib/provider.ts create mode 100644 packages/ai/lib/react.ts create mode 100644 packages/ai/package.json create mode 100644 packages/ai/tsconfig.json create mode 100644 packages/analytics/client.tsx create mode 100644 packages/analytics/index.tsx create mode 100644 packages/analytics/package.json create mode 100644 packages/analytics/server.ts create mode 100644 packages/analytics/tsconfig.json create mode 100644 packages/auth/better-auth.config.ts create mode 100644 packages/auth/client.ts create mode 100644 packages/auth/components/sign-in.tsx create mode 100644 packages/auth/components/sign-up.tsx create mode 100644 packages/auth/middleware.ts create mode 100644 packages/auth/package.json create mode 100644 packages/auth/provider.tsx create mode 100644 packages/auth/server.ts create mode 100644 packages/auth/tsconfig.json create mode 100644 packages/cms/collections.ts create mode 100644 packages/cms/components/body.tsx create mode 100644 packages/cms/components/image.tsx create mode 100644 packages/cms/components/toc.tsx create mode 100644 packages/cms/components/toolbar.tsx create mode 100644 packages/cms/index.ts create mode 100644 packages/cms/next-config.ts create mode 100644 packages/cms/package.json create mode 100644 packages/cms/tsconfig.json create mode 100644 packages/cms/typescript-config.json create mode 100644 packages/collaboration/auth.ts create mode 100644 packages/collaboration/config.ts create mode 100644 packages/collaboration/hooks.ts create mode 100644 packages/collaboration/package.json create mode 100644 packages/collaboration/room.tsx create mode 100644 packages/collaboration/tsconfig.json create mode 100644 packages/database/.gitignore create mode 100644 packages/database/builder.ts create mode 100644 packages/database/index.ts create mode 100644 packages/database/migrate/migrator.ts create mode 100644 packages/database/migrations/m20241229_000001_init.ts create mode 100644 packages/database/package.json create mode 100644 packages/database/schema/database.ts create mode 100644 packages/database/schema/page.ts create mode 100644 packages/database/tsconfig.json create mode 100644 packages/design-system/components.json create mode 100644 packages/design-system/components/mode-toggle.tsx create mode 100644 packages/design-system/components/ui/accordion.tsx create mode 100644 packages/design-system/components/ui/alert-dialog.tsx create mode 100644 packages/design-system/components/ui/alert.tsx create mode 100644 packages/design-system/components/ui/aspect-ratio.tsx create mode 100644 packages/design-system/components/ui/avatar.tsx create mode 100644 packages/design-system/components/ui/badge.tsx create mode 100644 packages/design-system/components/ui/breadcrumb.tsx create mode 100644 packages/design-system/components/ui/button.tsx create mode 100644 packages/design-system/components/ui/calendar.tsx create mode 100644 packages/design-system/components/ui/card.tsx create mode 100644 packages/design-system/components/ui/carousel.tsx create mode 100644 packages/design-system/components/ui/chart.tsx create mode 100644 packages/design-system/components/ui/checkbox.tsx create mode 100644 packages/design-system/components/ui/collapsible.tsx create mode 100644 packages/design-system/components/ui/command.tsx create mode 100644 packages/design-system/components/ui/context-menu.tsx create mode 100644 packages/design-system/components/ui/dialog.tsx create mode 100644 packages/design-system/components/ui/drawer.tsx create mode 100644 packages/design-system/components/ui/dropdown-menu.tsx create mode 100644 packages/design-system/components/ui/form.tsx create mode 100644 packages/design-system/components/ui/hover-card.tsx create mode 100644 packages/design-system/components/ui/input-otp.tsx create mode 100644 packages/design-system/components/ui/input.tsx create mode 100644 packages/design-system/components/ui/label.tsx create mode 100644 packages/design-system/components/ui/menubar.tsx create mode 100644 packages/design-system/components/ui/navigation-menu.tsx create mode 100644 packages/design-system/components/ui/pagination.tsx create mode 100644 packages/design-system/components/ui/popover.tsx create mode 100644 packages/design-system/components/ui/progress.tsx create mode 100644 packages/design-system/components/ui/radio-group.tsx create mode 100644 packages/design-system/components/ui/resizable.tsx create mode 100644 packages/design-system/components/ui/scroll-area.tsx create mode 100644 packages/design-system/components/ui/select.tsx create mode 100644 packages/design-system/components/ui/separator.tsx create mode 100644 packages/design-system/components/ui/sheet.tsx create mode 100644 packages/design-system/components/ui/sidebar.tsx create mode 100644 packages/design-system/components/ui/skeleton.tsx create mode 100644 packages/design-system/components/ui/slider.tsx create mode 100644 packages/design-system/components/ui/sonner.tsx create mode 100644 packages/design-system/components/ui/switch.tsx create mode 100644 packages/design-system/components/ui/table.tsx create mode 100644 packages/design-system/components/ui/tabs.tsx create mode 100644 packages/design-system/components/ui/textarea.tsx create mode 100644 packages/design-system/components/ui/toast.tsx create mode 100644 packages/design-system/components/ui/toaster.tsx create mode 100644 packages/design-system/components/ui/toggle-group.tsx create mode 100644 packages/design-system/components/ui/toggle.tsx create mode 100644 packages/design-system/components/ui/tooltip.tsx create mode 100644 packages/design-system/components/ui/use-toast.ts create mode 100644 packages/design-system/hooks/use-mobile.tsx create mode 100644 packages/design-system/hooks/use-toast.ts create mode 100644 packages/design-system/index.tsx create mode 100644 packages/design-system/lib/fonts.ts create mode 100644 packages/design-system/lib/utils.ts create mode 100644 packages/design-system/package.json create mode 100644 packages/design-system/postcss.config.mjs create mode 100644 packages/design-system/providers/theme.tsx create mode 100644 packages/design-system/styles/globals.css create mode 100644 packages/design-system/tsconfig.json create mode 100644 packages/email/index.tsx create mode 100644 packages/email/package.json create mode 100644 packages/email/templates/contact.tsx create mode 100644 packages/email/tsconfig.json create mode 100644 packages/env/index.ts create mode 100644 packages/env/package.json create mode 100644 packages/env/tsconfig.json create mode 100644 packages/feature-flags/access.ts create mode 100644 packages/feature-flags/index.ts create mode 100644 packages/feature-flags/lib/create-flag.ts create mode 100644 packages/feature-flags/package.json create mode 100644 packages/feature-flags/tsconfig.json create mode 100644 packages/migrate/.gitignore create mode 100644 packages/migrate/index.ts create mode 100644 packages/migrate/package.json create mode 100644 packages/migrate/scripts/down.ts create mode 100644 packages/migrate/scripts/up.ts create mode 100644 packages/migrate/tsconfig.json create mode 100644 packages/next-config/index.ts create mode 100644 packages/next-config/instrumentation.ts create mode 100644 packages/next-config/package.json create mode 100644 packages/next-config/tsconfig.json create mode 100644 packages/observability/error.ts create mode 100644 packages/observability/log.ts create mode 100644 packages/observability/package.json create mode 100644 packages/observability/status/index.tsx create mode 100644 packages/observability/status/types.ts create mode 100644 packages/observability/tsconfig.json rename {crates => packages}/quirks-path/Cargo.toml (100%) rename {crates => packages}/quirks-path/src/lib.rs (97%) rename {crates => packages}/quirks-path/src/url.rs (98%) rename {crates => packages}/quirks-path/src/windows.rs (95%) create mode 100644 packages/rate-limit/index.ts create mode 100644 packages/rate-limit/package.json create mode 100644 packages/security/index.ts create mode 100644 packages/security/middleware.ts create mode 100644 packages/security/package.json create mode 100644 packages/security/tsconfig.json create mode 100644 packages/seo/json-ld.tsx create mode 100644 packages/seo/metadata.ts create mode 100644 packages/seo/package.json create mode 100644 packages/seo/tsconfig.json create mode 100644 packages/storage/client.ts create mode 100644 packages/storage/index.ts create mode 100644 packages/storage/package.json create mode 100644 packages/storage/tsconfig.json create mode 100644 packages/tailwind-config/config.ts create mode 100644 packages/tailwind-config/index.ts create mode 100644 packages/tailwind-config/package.json create mode 100644 packages/tailwind-config/tsconfig.json create mode 100644 packages/tailwind-config/typography.config.ts create mode 100644 packages/testing/package.json create mode 100644 packages/testing/tsconfig.json rename {crates => packages}/torrent/.gitignore (100%) rename {crates => packages}/torrent/Cargo.toml (100%) rename {crates => packages}/torrent/src/core.rs (100%) rename {crates => packages}/torrent/src/error.rs (100%) rename {crates => packages}/torrent/src/lib.rs (100%) rename {crates => packages}/torrent/src/qbit.rs (96%) create mode 100644 packages/typescript-config/base.json create mode 100644 packages/typescript-config/nextjs.json create mode 100644 packages/typescript-config/package.json create mode 100644 packages/typescript-config/react-library.json create mode 100644 packages/webhooks/index.ts create mode 100644 packages/webhooks/lib/svix.ts create mode 100644 packages/webhooks/package.json create mode 100644 turbo.json create mode 100644 turbo/generators/config.ts create mode 100644 turbo/generators/package.json create mode 100644 turbo/generators/templates/package.json.hbs create mode 100644 turbo/generators/templates/tsconfig.json.hbs diff --git a/.cargo/config.toml b/.cargo/config.toml index bc10c1a..01ffcf7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,6 @@ [alias] -recorder = "run -p recorder --bin recorder_cli -- --environment recorder.development" -recorder-playground = "run -p recorder --example playground -- --environment recorder.development" +recorder = "run -p recorder --bin recorder_cli -- --environment recorder/development" +recorder-playground = "run -p recorder --example playground -- --environment recorder/development" [build] rustflags = ["-Zthreads=8"] diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d8e085a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = lf +max_line_length = null diff --git a/.gitignore b/.gitignore index cc5bee7..9bcd4eb 100644 --- a/.gitignore +++ b/.gitignore @@ -127,6 +127,8 @@ build/Release # Dependency directories node_modules/ jspm_packages/ +.pnp +.pnp.js # Snowpack dependency directory (https://snowpack.dev/) web_modules/ @@ -155,9 +157,12 @@ web_modules/ # Yarn Integrity file .yarn-integrity -# dotenv environment variables file +# Local env files .env -.env.test +.env.local +.env.development.local +.env.test.local +.env.production.local # parcel-bundler cache (https://parceljs.org/) .cache @@ -222,4 +227,32 @@ index.d.ts.map /temp /rustc-ice-* + +# Misc +.DS_Store +*.pem + +# Sentry Config File +.env.sentry-build-plugin + +# BaseHub +.basehub + +# Build Outputs +build +dist + +# Turbo +.turbo + +# Vercel +.vercel + +# Payload default media upload directory +public/media/ + +public/robots.txt +public/sitemap*.xml + +# Custom /data \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..996b10e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +**/payload-types.ts +.tmp +**/.git +**/.hg +**/.pnp.* +**/.svn +**/.yarn/** +**/build +**/dist/** +**/node_modules +**/temp +**/docs/** +tsconfig.json + diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f1f907f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "biomejs.biome", + "bradlc.vscode-tailwindcss", + "unifiedjs.vscode-mdx", + "mikestead.dotenv", + "christian-kohler.npm-intellisense", + "skellock.just" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index 427cd52..057362d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -40,7 +40,7 @@ }, "args": [ "--environment", - "recorder.development" + "recorder/development" ], "cwd": "${workspaceFolder}" }, @@ -61,7 +61,7 @@ }, "args": [ "--environment", - "recorder.development" + "recorder/development" ], "cwd": "${workspaceFolder}" }, @@ -83,6 +83,57 @@ }, "args": [], "cwd": "${workspaceFolder}" + }, + { + "name": "Next.js: debug server-side", + "type": "node-terminal", + "request": "launch", + "command": "pnpm dev" + }, + { + "name": "Next.js: debug client-side (app)", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000" + }, + { + "name": "Next.js: debug client-side (web)", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3001" + }, + { + "name": "Next.js: debug client-side (api)", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3002" + }, + { + "name": "Next.js: debug client-side (email)", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3003" + }, + { + "name": "Next.js: debug client-side (app)", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3004" + }, + { + "name": "Next.js: debug full stack", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/node_modules/.bin/next", + "runtimeArgs": ["--inspect"], + "skipFiles": ["/**"], + "serverReadyAction": { + "action": "debugWithEdge", + "killOnServerStop": true, + "pattern": "- Local:.+(https?://.+)", + "uriFormat": "%s", + "webRoot": "${workspaceFolder}" + } } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 875c867..05e54d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,32 @@ { - "rust-analyzer.showUnlinkedFileNotification": false -} \ No newline at end of file + "npm.packageManager": "pnpm", + "rust-analyzer.showUnlinkedFileNotification": false, + "[javascript]": { + "editor.defaultFormatter": "vscode.typescript-language-features", + "editor.formatOnSave": true + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true + }, + "editor.codeActionsOnSave": { + "quickfix.biome": "explicit", + "source.organizeImports.biome": "explicit" + }, + "emmet.showExpandedAbbreviation": "never", + "prettier.enable": false, + "tailwindCSS.experimental.configFile": "./packages/tailwind-config/config.ts", + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/Cargo.toml b/Cargo.toml index 23eaeac..429c0db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["crates/quirks-path", "crates/recorder", "crates/torrent"] +members = ["apps/recorder", "packages/quirks-path", "packages/torrent"] resolver = "2" diff --git a/apps/api/.env.development b/apps/api/.env.development new file mode 100644 index 0000000..52a6723 --- /dev/null +++ b/apps/api/.env.development @@ -0,0 +1,15 @@ +# Server +BETTER_AUTH_SECRET="konobangu" +DATABASE_URL="postgres://konobangu:konobangu@127.0.0.1:5432/konobangu" +BETTERSTACK_API_KEY="" +BETTERSTACK_URL="" +FLAGS_SECRET="" +ARCJET_KEY="" +SVIX_TOKEN="" +LIVEBLOCKS_SECRET="" + +# Client +NEXT_PUBLIC_APP_URL="http://localhost:3000" +NEXT_PUBLIC_WEB_URL="http://localhost:3001" +NEXT_PUBLIC_DOCS_URL="http://localhost:3004" +NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL="https://webui.konobangu.com" \ No newline at end of file diff --git a/apps/api/.env.example b/apps/api/.env.example new file mode 100644 index 0000000..ca7d1ee --- /dev/null +++ b/apps/api/.env.example @@ -0,0 +1,15 @@ +# Server +BETTER_AUTH_SECRET="" +DATABASE_URL="" +BETTERSTACK_API_KEY="" +BETTERSTACK_URL="" +FLAGS_SECRET="" +ARCJET_KEY="" +SVIX_TOKEN="" +LIVEBLOCKS_SECRET="" + +# Client +NEXT_PUBLIC_APP_URL="http://localhost:3000" +NEXT_PUBLIC_WEB_URL="http://localhost:3001" +NEXT_PUBLIC_DOCS_URL="http://localhost:3004" +NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3000" \ No newline at end of file diff --git a/apps/webui/.gitignore b/apps/api/.gitignore similarity index 81% rename from apps/webui/.gitignore rename to apps/api/.gitignore index fd3dbb5..663a9cc 100644 --- a/apps/webui/.gitignore +++ b/apps/api/.gitignore @@ -4,7 +4,6 @@ /node_modules /.pnp .pnp.js -.yarn/install-state.gz # testing /coverage @@ -24,6 +23,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* # local env files .env*.local @@ -34,3 +34,12 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# prisma +.env + +# react.email +.react-email + +# Sentry +.sentryclirc \ No newline at end of file diff --git a/apps/api/app/apple-icon.png b/apps/api/app/apple-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d185929cc52a90e65492c5e3ee719b48f1775c2a GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvG8AvYpRA>UEBm#UwTz~!g_3G8DIdkUJ*46^W z^!4>`-@dJ&prHG8njVl}?djqeQo;E4yd&pf2LXlytxors@>OyD>S)ekadG82VlOC= zr}(D)*g+O!py}mT>@I#ebxSVRdzu+51hlq`pn|?Ne;2>3P0Q@%Yqf@|L8V#)e;;K5 b8pi5<*lSI@#dl|*GZ;Kw{an^LB{Ts5y-Go@ literal 0 HcmV?d00001 diff --git a/apps/api/app/cron/keep-alive/route.ts b/apps/api/app/cron/keep-alive/route.ts new file mode 100644 index 0000000..b34a27c --- /dev/null +++ b/apps/api/app/cron/keep-alive/route.ts @@ -0,0 +1,17 @@ +import { database } from '@konobangu/database'; + +export const POST = async () => { + const newPage = await database + .insertInto('page') + .values([ + { + name: 'cron-temp', + }, + ]) + .returning('id') + .executeTakeFirstOrThrow(); + + await database.deleteFrom('page').where('id', '=', newPage.id); + + return new Response('OK', { status: 200 }); +}; diff --git a/apps/api/app/global-error.tsx b/apps/api/app/global-error.tsx new file mode 100644 index 0000000..6e0511e --- /dev/null +++ b/apps/api/app/global-error.tsx @@ -0,0 +1,29 @@ +'use client'; + +import { Button } from '@konobangu/design-system/components/ui/button'; +import { fonts } from '@konobangu/design-system/lib/fonts'; +import { captureException } from '@sentry/nextjs'; +import type NextError from 'next/error'; +import { useEffect } from 'react'; + +type GlobalErrorProperties = { + readonly error: NextError & { digest?: string }; + readonly reset: () => void; +}; + +const GlobalError = ({ error, reset }: GlobalErrorProperties) => { + useEffect(() => { + captureException(error); + }, [error]); + + return ( + + +

Oops, something went wrong

+ + + + ); +}; + +export default GlobalError; diff --git a/apps/api/app/health/route.ts b/apps/api/app/health/route.ts new file mode 100644 index 0000000..4ad1dd2 --- /dev/null +++ b/apps/api/app/health/route.ts @@ -0,0 +1,3 @@ +export const runtime = 'edge'; + +export const GET = (): Response => new Response('OK', { status: 200 }); diff --git a/apps/api/app/icon.png b/apps/api/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d79828515a04ae36e18cadffe4892aa5b5df2331 GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4U>Ygr+Ar-fh6EYHh^ow6J7GPTJ t)+1$@b>xFVlF1IYUJ28rD;zTf8B!|$3GCaY_7kXu!PC{xWt~$(699t!99;ka literal 0 HcmV?d00001 diff --git a/apps/api/app/layout.tsx b/apps/api/app/layout.tsx new file mode 100644 index 0000000..23be9db --- /dev/null +++ b/apps/api/app/layout.tsx @@ -0,0 +1,13 @@ +import type { ReactNode } from 'react'; + +type RootLayoutProperties = { + readonly children: ReactNode; +}; + +const RootLayout = ({ children }: RootLayoutProperties) => ( + + {children} + +); + +export default RootLayout; diff --git a/apps/api/app/opengraph-image.png b/apps/api/app/opengraph-image.png new file mode 100644 index 0000000000000000000000000000000000000000..c79169f1eb2db58b5b35e1688f3149fba622d167 GIT binary patch literal 58106 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

ywa8VA#Nc>TQ}epi}OZq-5)L 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 { + render(); + expect( + screen.getByRole('heading', { + level: 1, + name: 'Welcome back', + }) + ).toBeDefined(); +}); diff --git a/apps/app/__tests__/sign-up.test.tsx b/apps/app/__tests__/sign-up.test.tsx new file mode 100644 index 0000000..9a4dcbe --- /dev/null +++ b/apps/app/__tests__/sign-up.test.tsx @@ -0,0 +1,13 @@ +import { render, screen } from '@testing-library/react'; +import { expect, test } from 'vitest'; +import Page from '../app/(unauthenticated)/sign-up/[[...sign-up]]/page'; + +test('Sign Up Page', () => { + render(); + expect( + screen.getByRole('heading', { + level: 1, + name: 'Create an account', + }) + ).toBeDefined(); +}); diff --git a/apps/app/app/(authenticated)/components/avatar-stack.tsx b/apps/app/app/(authenticated)/components/avatar-stack.tsx new file mode 100644 index 0000000..1e926d5 --- /dev/null +++ b/apps/app/app/(authenticated)/components/avatar-stack.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { useOthers, useSelf } from '@konobangu/collaboration/hooks'; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from '@konobangu/design-system/components/ui/avatar'; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@konobangu/design-system/components/ui/tooltip'; +import { tailwind } from '@konobangu/tailwind-config'; + +type PresenceAvatarProps = { + info?: Liveblocks['UserMeta']['info']; +}; + +const PresenceAvatar = ({ info }: PresenceAvatarProps) => ( + + + + + + {info?.name?.slice(0, 2)} + + + + +

{info?.name ?? 'Unknown'}

+ + +); + +export const AvatarStack = () => { + const others = useOthers(); + const self = useSelf(); + const hasMoreUsers = others.length > 3; + + return ( +
+ {others.slice(0, 3).map(({ connectionId, info }) => ( + + ))} + + {hasMoreUsers && ( + + )} + + {self && } +
+ ); +}; diff --git a/apps/app/app/(authenticated)/components/collaboration-provider.tsx b/apps/app/app/(authenticated)/components/collaboration-provider.tsx new file mode 100644 index 0000000..94bb373 --- /dev/null +++ b/apps/app/app/(authenticated)/components/collaboration-provider.tsx @@ -0,0 +1,48 @@ +'use client'; + +import { getUsers } from '@/app/actions/users/get'; +import { searchUsers } from '@/app/actions/users/search'; +import { Room } from '@konobangu/collaboration/room'; +import type { ReactNode } from 'react'; + +export const CollaborationProvider = ({ + orgId, + children, +}: { + orgId: string; + children: ReactNode; +}) => { + const resolveUsers = async ({ userIds }: { userIds: string[] }) => { + const response = await getUsers(userIds); + + if ('error' in response) { + throw new Error('Problem resolving users'); + } + + return response.data; + }; + + const resolveMentionSuggestions = async ({ text }: { text: string }) => { + const response = await searchUsers(text); + + if ('error' in response) { + throw new Error('Problem resolving mention suggestions'); + } + + return response.data; + }; + + return ( + Loading... + } + resolveUsers={resolveUsers} + resolveMentionSuggestions={resolveMentionSuggestions} + > + {children} + + ); +}; diff --git a/apps/app/app/(authenticated)/components/cursors.tsx b/apps/app/app/(authenticated)/components/cursors.tsx new file mode 100644 index 0000000..d630598 --- /dev/null +++ b/apps/app/app/(authenticated)/components/cursors.tsx @@ -0,0 +1,106 @@ +'use client'; + +import { useMyPresence, useOthers } from '@konobangu/collaboration/hooks'; +import { useEffect } from 'react'; + +const Cursor = ({ + name, + color, + x, + y, +}: { + name: string | undefined; + color: string; + x: number; + y: number; +}) => ( +
+ + Cursor + + +
+ {name} +
+
+); + +export const Cursors = () => { + /** + * useMyPresence returns the presence of the current user and a function to update it. + * updateMyPresence is different than the setState function returned by the useState hook from React. + * You don't need to pass the full presence object to update it. + * See https://liveblocks.io/docs/api-reference/liveblocks-react#useMyPresence for more information + */ + const [_cursor, updateMyPresence] = useMyPresence(); + + /** + * Return all the other users in the room and their presence (a cursor position in this case) + */ + const others = useOthers(); + + useEffect(() => { + const onPointerMove = (event: PointerEvent) => { + // Update the user cursor position on every pointer move + updateMyPresence({ + cursor: { + x: Math.round(event.clientX), + y: Math.round(event.clientY), + }, + }); + }; + + const onPointerLeave = () => { + // When the pointer goes out, set cursor to null + updateMyPresence({ + cursor: null, + }); + }; + + document.body.addEventListener('pointermove', onPointerMove); + document.body.addEventListener('pointerleave', onPointerLeave); + + return () => { + document.body.removeEventListener('pointermove', onPointerMove); + document.body.removeEventListener('pointerleave', onPointerLeave); + }; + }, [updateMyPresence]); + + return others.map(({ connectionId, presence, info }) => { + if (!presence.cursor) { + return null; + } + + return ( + + ); + }); +}; diff --git a/apps/app/app/(authenticated)/components/header.tsx b/apps/app/app/(authenticated)/components/header.tsx new file mode 100644 index 0000000..138eb88 --- /dev/null +++ b/apps/app/app/(authenticated)/components/header.tsx @@ -0,0 +1,43 @@ +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@konobangu/design-system/components/ui/breadcrumb'; +import { Separator } from '@konobangu/design-system/components/ui/separator'; +import { SidebarTrigger } from '@konobangu/design-system/components/ui/sidebar'; +import { Fragment, type ReactNode } from 'react'; + +type HeaderProps = { + pages: string[]; + page: string; + children?: ReactNode; +}; + +export const Header = ({ pages, page, children }: HeaderProps) => ( +
+
+ + + + + {pages.map((page, index) => ( + + {index > 0 && } + + {page} + + + ))} + + + {page} + + + +
+ {children} +
+); diff --git a/apps/app/app/(authenticated)/components/posthog-identifier.tsx b/apps/app/app/(authenticated)/components/posthog-identifier.tsx new file mode 100644 index 0000000..bda1472 --- /dev/null +++ b/apps/app/app/(authenticated)/components/posthog-identifier.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { analytics } from '@konobangu/analytics/client'; +import { useSession } from '@konobangu/auth/client'; +import { usePathname, useSearchParams } from 'next/navigation'; +import { useEffect, useRef } from 'react'; + +export const PostHogIdentifier = () => { + const session = useSession(); + const user = session?.data?.user; + const identified = useRef(false); + const pathname = usePathname(); + const searchParams = useSearchParams(); + + useEffect(() => { + // Track pageviews + if (pathname && analytics) { + let url = window.origin + pathname; + if (searchParams.toString()) { + url = `${url}?${searchParams.toString()}`; + } + analytics.capture('$pageview', { + $current_url: url, + }); + } + }, [pathname, searchParams]); + + useEffect(() => { + if (!user || identified.current) { + return; + } + + analytics.identify(user.id, { + email: user.email, + name: user.name, + createdAt: user.createdAt, + avatar: user.image, + }); + + identified.current = true; + }, [user]); + + return null; +}; diff --git a/apps/app/app/(authenticated)/components/sidebar.tsx b/apps/app/app/(authenticated)/components/sidebar.tsx new file mode 100644 index 0000000..5a5c103 --- /dev/null +++ b/apps/app/app/(authenticated)/components/sidebar.tsx @@ -0,0 +1,342 @@ +'use client'; + +// import { OrganizationSwitcher, UserButton } from '@konobangu/auth/client'; +import { ModeToggle } from '@konobangu/design-system/components/mode-toggle'; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from '@konobangu/design-system/components/ui/collapsible'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@konobangu/design-system/components/ui/dropdown-menu'; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarHeader, + SidebarInset, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, + useSidebar, +} from '@konobangu/design-system/components/ui/sidebar'; +import { cn } from '@konobangu/design-system/lib/utils'; +import { + AnchorIcon, + BookOpenIcon, + BotIcon, + ChevronRightIcon, + FolderIcon, + FrameIcon, + LifeBuoyIcon, + MapIcon, + MoreHorizontalIcon, + PieChartIcon, + SendIcon, + Settings2Icon, + ShareIcon, + SquareTerminalIcon, + Trash2Icon, +} from 'lucide-react'; +import type { ReactNode } from 'react'; + +type GlobalSidebarProperties = { + readonly children: ReactNode; +}; + +const data = { + user: { + name: 'shadcn', + email: 'm@example.com', + avatar: '/avatars/shadcn.jpg', + }, + navMain: [ + { + title: 'Playground', + url: '#', + icon: SquareTerminalIcon, + isActive: true, + items: [ + { + title: 'History', + url: '#', + }, + { + title: 'Starred', + url: '#', + }, + { + title: 'Settings', + url: '#', + }, + ], + }, + { + title: 'Models', + url: '#', + icon: BotIcon, + items: [ + { + title: 'Genesis', + url: '#', + }, + { + title: 'Explorer', + url: '#', + }, + { + title: 'Quantum', + url: '#', + }, + ], + }, + { + title: 'Documentation', + url: '#', + icon: BookOpenIcon, + items: [ + { + title: 'Introduction', + url: '#', + }, + { + title: 'Get Started', + url: '#', + }, + { + title: 'Tutorials', + url: '#', + }, + { + title: 'Changelog', + url: '#', + }, + ], + }, + { + title: 'Settings', + url: '#', + icon: Settings2Icon, + items: [ + { + title: 'General', + url: '#', + }, + { + title: 'Team', + url: '#', + }, + { + title: 'Billing', + url: '#', + }, + { + title: 'Limits', + url: '#', + }, + ], + }, + ], + navSecondary: [ + { + title: 'Webhooks', + url: '/webhooks', + icon: AnchorIcon, + }, + { + title: 'Support', + url: '#', + icon: LifeBuoyIcon, + }, + { + title: 'Feedback', + url: '#', + icon: SendIcon, + }, + ], + projects: [ + { + name: 'Design Engineering', + url: '#', + icon: FrameIcon, + }, + { + name: 'Sales & Marketing', + url: '#', + icon: PieChartIcon, + }, + { + name: 'Travel', + url: '#', + icon: MapIcon, + }, + ], +}; + +export const GlobalSidebar = ({ children }: GlobalSidebarProperties) => { + const sidebar = useSidebar(); + + return ( + <> + + + + +
div]:w-full', + sidebar.open ? '' : '-mx-1' + )} + > + {/* */} +
+
+
+
+ + + Platform + + {data.navMain.map((item) => ( + + + + + + {item.title} + + + {item.items?.length ? ( + <> + + + + Toggle + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + ) : null} + + + ))} + + + + Projects + + {data.projects.map((item) => ( + + + + + {item.name} + + + + + + + More + + + + + + View Project + + + + Share Project + + + + + Delete Project + + + + + ))} + + + + More + + + + + + + + {data.navSecondary.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + + + {/* */} + + + + +
+ {children} + + ); +}; diff --git a/apps/app/app/(authenticated)/layout.tsx b/apps/app/app/(authenticated)/layout.tsx new file mode 100644 index 0000000..ccf64bd --- /dev/null +++ b/apps/app/app/(authenticated)/layout.tsx @@ -0,0 +1,42 @@ +import { getSessionFromHeaders } from '@konobangu/auth/server'; +import { SidebarProvider } from '@konobangu/design-system/components/ui/sidebar'; +import { env } from '@konobangu/env'; +import { showBetaFeature } from '@konobangu/feature-flags'; +import { secure } from '@konobangu/security'; +import { redirect } from 'next/navigation'; +import type { ReactNode } from 'react'; +import { PostHogIdentifier } from './components/posthog-identifier'; +import { GlobalSidebar } from './components/sidebar'; + +type AppLayoutProperties = { + readonly children: ReactNode; +}; + +const AppLayout = async ({ children }: AppLayoutProperties) => { + if (env.ARCJET_KEY) { + await secure(['CATEGORY:PREVIEW']); + } + + const { user } = await getSessionFromHeaders(); + + if (!user) { + return redirect('/sign-in'); // from next/navigation + } + const betaFeature = await showBetaFeature(); + + return ( + + + {betaFeature && ( +
+ Beta feature now available +
+ )} + {children} +
+ +
+ ); +}; + +export default AppLayout; diff --git a/apps/app/app/(authenticated)/page.tsx b/apps/app/app/(authenticated)/page.tsx new file mode 100644 index 0000000..ddaafd1 --- /dev/null +++ b/apps/app/app/(authenticated)/page.tsx @@ -0,0 +1,57 @@ +import { getSessionFromHeaders } from '@konobangu/auth/server'; +import { database } from '@konobangu/database'; +import { env } from '@konobangu/env'; +import type { Metadata } from 'next'; +import dynamic from 'next/dynamic'; +import { notFound } from 'next/navigation'; +import { AvatarStack } from './components/avatar-stack'; +import { Cursors } from './components/cursors'; +import { Header } from './components/header'; + +const title = 'Acme Inc'; +const description = 'My application.'; + +const CollaborationProvider = dynamic(() => + import('./components/collaboration-provider').then( + (mod) => mod.CollaborationProvider + ) +); + +export const metadata: Metadata = { + title, + description, +}; + +const App = async () => { + const pages = await database.selectFrom('page').selectAll().execute(); + const { orgId } = await getSessionFromHeaders(); + + if (!orgId) { + notFound(); + } + + return ( + <> +
+ {env.LIVEBLOCKS_SECRET && ( + + + + + )} +
+
+
+ {pages.map((page) => ( +
+ {page.name} +
+ ))} +
+
+
+ + ); +}; + +export default App; diff --git a/apps/app/app/(authenticated)/webhooks/page.tsx b/apps/app/app/(authenticated)/webhooks/page.tsx new file mode 100644 index 0000000..b0bae17 --- /dev/null +++ b/apps/app/app/(authenticated)/webhooks/page.tsx @@ -0,0 +1,29 @@ +import { webhooks } from '@konobangu/webhooks'; +import { notFound } from 'next/navigation'; + +export const metadata = { + title: 'Webhooks', + description: 'Send webhooks to your users.', +}; + +const WebhooksPage = async () => { + const response = await webhooks.getAppPortal(); + + if (!response?.url) { + notFound(); + } + + return ( +
+ + +
+ + + +Mintlify supports [HTML tags in Markdown](https://www.markdownguide.org/basic-syntax/#html). This is helpful if you prefer HTML tags to Markdown syntax, and lets you create documentation with infinite flexibility. + + + +### iFrames + +Loads another HTML page within the document. Most commonly used for embedding videos. + +```html + +``` diff --git a/apps/docs/essentials/markdown.mdx b/apps/docs/essentials/markdown.mdx new file mode 100644 index 0000000..c8ad9c1 --- /dev/null +++ b/apps/docs/essentials/markdown.mdx @@ -0,0 +1,88 @@ +--- +title: 'Markdown Syntax' +description: 'Text, title, and styling in standard markdown' +icon: 'text-size' +--- + +## Titles + +Best used for section headers. + +```md +## Titles +``` + +### Subtitles + +Best use to subsection headers. + +```md +### Subtitles +``` + + + +Each **title** and **subtitle** creates an anchor and also shows up on the table of contents on the right. + + + +## Text Formatting + +We support most markdown formatting. Simply add `**`, `_`, or `~` around text to format it. + +| Style | How to write it | Result | +| ------------- | ----------------- | --------------- | +| Bold | `**bold**` | **bold** | +| Italic | `_italic_` | _italic_ | +| Strikethrough | `~strikethrough~` | ~strikethrough~ | + +You can combine these. For example, write `**_bold and italic_**` to get **_bold and italic_** text. + +You need to use HTML to write superscript and subscript text. That is, add `` or `` around your text. + +| Text Size | How to write it | Result | +| ----------- | ------------------------ | ---------------------- | +| Superscript | `superscript` | superscript | +| Subscript | `subscript` | subscript | + +## Linking to Pages + +You can add a link by wrapping text in `[]()`. You would write `[link to google](https://google.com)` to [link to google](https://google.com). + +Links to pages in your docs need to be root-relative. Basically, you should include the entire folder path. For example, `[link to text](/writing-content/text)` links to the page "Text" in our components section. + +Relative links like `[link to text](../text)` will open slower because we cannot optimize them as easily. + +## Blockquotes + +### Singleline + +To create a blockquote, add a `>` in front of a paragraph. + +> Dorothy followed her through many of the beautiful rooms in her castle. + +```md +> Dorothy followed her through many of the beautiful rooms in her castle. +``` + +### Multiline + +> Dorothy followed her through many of the beautiful rooms in her castle. +> +> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. + +```md +> Dorothy followed her through many of the beautiful rooms in her castle. +> +> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. +``` + +### LaTeX + +Mintlify supports [LaTeX](https://www.latex-project.org) through the Latex component. + +8 x (vk x H1 - H2) = (0,1) + +```md +8 x (vk x H1 - H2) = (0,1) +``` diff --git a/apps/docs/essentials/navigation.mdx b/apps/docs/essentials/navigation.mdx new file mode 100644 index 0000000..ca44bb6 --- /dev/null +++ b/apps/docs/essentials/navigation.mdx @@ -0,0 +1,66 @@ +--- +title: 'Navigation' +description: 'The navigation field in mint.json defines the pages that go in the navigation menu' +icon: 'map' +--- + +The navigation menu is the list of links on every website. + +You will likely update `mint.json` every time you add a new page. Pages do not show up automatically. + +## Navigation syntax + +Our navigation syntax is recursive which means you can make nested navigation groups. You don't need to include `.mdx` in page names. + + + +```json Regular Navigation +"navigation": [ + { + "group": "Getting Started", + "pages": ["quickstart"] + } +] +``` + +```json Nested Navigation +"navigation": [ + { + "group": "Getting Started", + "pages": [ + "quickstart", + { + "group": "Nested Reference Pages", + "pages": ["nested-reference-page"] + } + ] + } +] +``` + + + +## Folders + +Simply put your MDX files in folders and update the paths in `mint.json`. + +For example, to have a page at `https://yoursite.com/your-folder/your-page` you would make a folder called `your-folder` containing an MDX file called `your-page.mdx`. + + + +You cannot use `api` for the name of a folder unless you nest it inside another folder. Mintlify uses Next.js which reserves the top-level `api` folder for internal server calls. A folder name such as `api-reference` would be accepted. + + + +```json Navigation With Folder +"navigation": [ + { + "group": "Group Name", + "pages": ["your-folder/your-page"] + } +] +``` + +## Hidden Pages + +MDX files not included in `mint.json` will not show up in the sidebar but are accessible through the search bar and by linking directly to them. diff --git a/apps/docs/essentials/reusable-snippets.mdx b/apps/docs/essentials/reusable-snippets.mdx new file mode 100644 index 0000000..a0a5529 --- /dev/null +++ b/apps/docs/essentials/reusable-snippets.mdx @@ -0,0 +1,110 @@ +--- +title: Reusable Snippets +description: Reusable, custom snippets to keep content in sync +icon: 'recycle' +--- + +import SnippetIntro from '/snippets/snippet-intro.mdx'; + + + +## Creating a custom snippet + +**Pre-condition**: You must create your snippet file in the `snippets` directory. + + + Any page in the `snippets` directory will be treated as a snippet and will not + be rendered into a standalone page. If you want to create a standalone page + from the snippet, import the snippet into another file and call it as a + component. + + +### Default export + +1. Add content to your snippet file that you want to re-use across multiple + locations. Optionally, you can add variables that can be filled in via props + when you import the snippet. + +```mdx snippets/my-snippet.mdx +Hello world! This is my content I want to reuse across pages. My keyword of the +day is {word}. +``` + + + The content that you want to reuse must be inside the `snippets` directory in + order for the import to work. + + +2. Import the snippet into your destination file. + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import MySnippet from '/snippets/path/to/my-snippet.mdx'; + +## Header + +Lorem impsum dolor sit amet. + + +``` + +### Reusable variables + +1. Export a variable from your snippet file: + +```mdx snippets/path/to/custom-variables.mdx +export const myName = 'my name'; + +export const myObject = { fruit: 'strawberries' }; +``` + +2. Import the snippet from your destination file and use the variable: + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import { myName, myObject } from '/snippets/path/to/custom-variables.mdx'; + +Hello, my name is {myName} and I like {myObject.fruit}. +``` + +### Reusable components + +1. Inside your snippet file, create a component that takes in props by exporting + your component in the form of an arrow function. + +```mdx snippets/custom-component.mdx +export const MyComponent = ({ title }) => ( +
+

{title}

+

... snippet content ...

+
+); +``` + + + MDX does not compile inside the body of an arrow function. Stick to HTML + syntax when you can or use a default export if you need to use MDX. + + +2. Import the snippet into your destination file and pass in the props + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import { MyComponent } from '/snippets/custom-component.mdx'; + +Lorem ipsum dolor sit amet. + + +``` diff --git a/apps/docs/essentials/settings.mdx b/apps/docs/essentials/settings.mdx new file mode 100644 index 0000000..d9dd2d7 --- /dev/null +++ b/apps/docs/essentials/settings.mdx @@ -0,0 +1,318 @@ +--- +title: 'Global Settings' +description: 'Mintlify gives you complete control over the look and feel of your documentation using the mint.json file' +icon: 'gear' +--- + +Every Mintlify site needs a `mint.json` file with the core configuration settings. Learn more about the [properties](#properties) below. + +## Properties + + +Name of your project. Used for the global title. + +Example: `mintlify` + + + + + An array of groups with all the pages within that group + + + The name of the group. + + Example: `Settings` + + + + The relative paths to the markdown files that will serve as pages. + + Example: `["customization", "page"]` + + + + + + + + Path to logo image or object with path to "light" and "dark" mode logo images + + + Path to the logo in light mode + + + Path to the logo in dark mode + + + Where clicking on the logo links you to + + + + + + Path to the favicon image + + + + Hex color codes for your global theme + + + The primary color. Used for most often for highlighted content, section + headers, accents, in light mode + + + The primary color for dark mode. Used for most often for highlighted + content, section headers, accents, in dark mode + + + The primary color for important buttons + + + The color of the background in both light and dark mode + + + The hex color code of the background in light mode + + + The hex color code of the background in dark mode + + + + + + + + Array of `name`s and `url`s of links you want to include in the topbar + + + The name of the button. + + Example: `Contact us` + + + The url once you click on the button. Example: `https://mintlify.com/contact` + + + + + + + + + Link shows a button. GitHub shows the repo information at the url provided including the number of GitHub stars. + + + If `link`: What the button links to. + + If `github`: Link to the repository to load GitHub information from. + + + Text inside the button. Only required if `type` is a `link`. + + + + + + + Array of version names. Only use this if you want to show different versions + of docs with a dropdown in the navigation bar. + + + + An array of the anchors, includes the `icon`, `color`, and `url`. + + + The [Font Awesome](https://fontawesome.com/search?s=brands%2Cduotone) icon used to feature the anchor. + + Example: `comments` + + + The name of the anchor label. + + Example: `Community` + + + The start of the URL that marks what pages go in the anchor. Generally, this is the name of the folder you put your pages in. + + + The hex color of the anchor icon background. Can also be a gradient if you pass an object with the properties `from` and `to` that are each a hex color. + + + Used if you want to hide an anchor until the correct docs version is selected. + + + Pass `true` if you want to hide the anchor until you directly link someone to docs inside it. + + + One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" + + + + + + + Override the default configurations for the top-most anchor. + + + The name of the top-most anchor + + + Font Awesome icon. + + + One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" + + + + + + An array of navigational tabs. + + + The name of the tab label. + + + The start of the URL that marks what pages go in the tab. Generally, this + is the name of the folder you put your pages in. + + + + + + Configuration for API settings. Learn more about API pages at [API Components](/api-playground/demo). + + + The base url for all API endpoints. If `baseUrl` is an array, it will enable for multiple base url + options that the user can toggle. + + + + + + The authentication strategy used for all API endpoints. + + + The name of the authentication parameter used in the API playground. + + If method is `basic`, the format should be `[usernameName]:[passwordName]` + + + The default value that's designed to be a prefix for the authentication input field. + + E.g. If an `inputPrefix` of `AuthKey` would inherit the default input result of the authentication field as `AuthKey`. + + + + + + Configurations for the API playground + + + + Whether the playground is showing, hidden, or only displaying the endpoint with no added user interactivity `simple` + + Learn more at the [playground guides](/api-playground/demo) + + + + + + Enabling this flag ensures that key ordering in OpenAPI pages matches the key ordering defined in the OpenAPI file. + + This behavior will soon be enabled by default, at which point this field will be deprecated. + + + + + + + A string or an array of strings of URL(s) or relative path(s) pointing to your + OpenAPI file. + + Examples: + + ```json Absolute + "openapi": "https://example.com/openapi.json" + ``` + ```json Relative + "openapi": "/openapi.json" + ``` + ```json Multiple + "openapi": ["https://example.com/openapi1.json", "/openapi2.json", "/openapi3.json"] + ``` + + + + + + An object of social media accounts where the key:property pair represents the social media platform and the account url. + + Example: + ```json + { + "x": "https://x.com/mintlify", + "website": "https://mintlify.com" + } + ``` + + + One of the following values `website`, `facebook`, `x`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news` + + Example: `x` + + + The URL to the social platform. + + Example: `https://x.com/mintlify` + + + + + + Configurations to enable feedback buttons + + + + Enables a button to allow users to suggest edits via pull requests + + + Enables a button to allow users to raise an issue about the documentation + + + + + + Customize the dark mode toggle. + + + Set if you always want to show light or dark mode for new users. When not + set, we default to the same mode as the user's operating system. + + + Set to true to hide the dark/light mode toggle. You can combine `isHidden` with `default` to force your docs to only use light or dark mode. For example: + + + ```json Only Dark Mode + "modeToggle": { + "default": "dark", + "isHidden": true + } + ``` + + ```json Only Light Mode + "modeToggle": { + "default": "light", + "isHidden": true + } + ``` + + + + + + + + + A background image to be displayed behind every page. See example with + [Infisical](https://infisical.com/docs) and [FRPC](https://frpc.io). + diff --git a/apps/docs/favicon.svg b/apps/docs/favicon.svg new file mode 100644 index 0000000..6a32332 --- /dev/null +++ b/apps/docs/favicon.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/checks-passed.png b/apps/docs/images/checks-passed.png new file mode 100644 index 0000000000000000000000000000000000000000..3303c773646ca12fb6852356663540e3ed048115 GIT binary patch literal 160724 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/images/hero-light.svg b/apps/docs/images/hero-light.svg new file mode 100644 index 0000000..297d68f --- /dev/null +++ b/apps/docs/images/hero-light.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/introduction.mdx b/apps/docs/introduction.mdx new file mode 100644 index 0000000..2589c0b --- /dev/null +++ b/apps/docs/introduction.mdx @@ -0,0 +1,71 @@ +--- +title: Introduction +description: 'Welcome to the home of your new documentation' +--- + +Hero Light +Hero Dark + +## Setting up + +The first step to world-class documentation is setting up your editing environments. + + + + Get your docs set up locally for easy development + + + Preview your changes before you push to make sure they're perfect + + + +## Make it yours + +Update your docs to your brand and add valuable content for the best user conversion. + + + + Customize your docs to your company's colors and brands + + + Automatically generate endpoints from an OpenAPI spec + + + Build interactive features and designs to guide your users + + + Check out our showcase of our favorite documentation + + diff --git a/apps/docs/logo/dark.svg b/apps/docs/logo/dark.svg new file mode 100644 index 0000000..a628378 --- /dev/null +++ b/apps/docs/logo/dark.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/logo/light.svg b/apps/docs/logo/light.svg new file mode 100644 index 0000000..582b3b9 --- /dev/null +++ b/apps/docs/logo/light.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/docs/mint.json b/apps/docs/mint.json new file mode 100644 index 0000000..f32f763 --- /dev/null +++ b/apps/docs/mint.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://mintlify.com/schema.json", + "name": "Starter Kit", + "logo": { + "dark": "/logo/dark.svg", + "light": "/logo/light.svg" + }, + "favicon": "/favicon.svg", + "colors": { + "primary": "#0D9373", + "light": "#07C983", + "dark": "#0D9373", + "anchors": { + "from": "#0D9373", + "to": "#07C983" + } + }, + "topbarLinks": [ + { + "name": "Support", + "url": "mailto:support@mintlify.com" + } + ], + "topbarCtaButton": { + "name": "Dashboard", + "url": "https://dashboard.mintlify.com" + }, + "tabs": [ + { + "name": "API Reference", + "url": "api-reference" + } + ], + "anchors": [ + { + "name": "Documentation", + "icon": "book-open-cover", + "url": "https://mintlify.com/docs" + }, + { + "name": "Community", + "icon": "slack", + "url": "https://mintlify.com/community" + }, + { + "name": "Blog", + "icon": "newspaper", + "url": "https://mintlify.com/blog" + } + ], + "navigation": [ + { + "group": "Get Started", + "pages": ["introduction", "quickstart", "development"] + }, + { + "group": "Essentials", + "pages": [ + "essentials/markdown", + "essentials/code", + "essentials/images", + "essentials/settings", + "essentials/navigation", + "essentials/reusable-snippets" + ] + }, + { + "group": "API Documentation", + "pages": ["api-reference/introduction"] + }, + { + "group": "Endpoint Examples", + "pages": [ + "api-reference/endpoint/get", + "api-reference/endpoint/create", + "api-reference/endpoint/delete" + ] + } + ], + "footerSocials": { + "x": "https://x.com/mintlify", + "github": "https://github.com/mintlify", + "linkedin": "https://www.linkedin.com/company/mintlify" + } +} diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 0000000..d8b11e6 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,11 @@ +{ + "name": "docs", + "private": true, + "scripts": { + "dev": "npx --yes mintlify dev --port 3004", + "lint": "npx --yes mintlify broken-links" + }, + "devDependencies": { + "typescript": "^5.7.2" + } +} diff --git a/apps/docs/quickstart.mdx b/apps/docs/quickstart.mdx new file mode 100644 index 0000000..d7f3486 --- /dev/null +++ b/apps/docs/quickstart.mdx @@ -0,0 +1,86 @@ +--- +title: 'Quickstart' +description: 'Start building awesome documentation in under 5 minutes' +--- + +## Setup your development + +Learn how to update your docs locally and and deploy them to the public. + +### Edit and preview + + + + During the onboarding process, we created a repository on your Github with + your docs content. You can find this repository on our + [dashboard](https://dashboard.mintlify.com). To clone the repository + locally, follow these + [instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) + in your terminal. + + + Previewing helps you make sure your changes look as intended. We built a + command line interface to render these changes locally. 1. Install the + [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the + documentation changes locally with this command: ``` npm i -g mintlify ``` + 2. Run the following command at the root of your documentation (where + `mint.json` is): ``` mintlify dev ``` + + + +### Deploy your changes + + + + + Our Github app automatically deploys your changes to your docs site, so you + don't need to manage deployments yourself. You can find the link to install on + your [dashboard](https://dashboard.mintlify.com). Once the bot has been + successfully installed, there should be a check mark next to the commit hash + of the repo. + + + [Commit and push your changes to + Git](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository#about-git-push) + for your changes to update in your docs site. If you push and don't see that + the Github app successfully deployed your changes, you can also manually + update your docs through our [dashboard](https://dashboard.mintlify.com). + + + + +## Update your docs + +Add content directly in your files with MDX syntax and React components. You can use any of our components, or even build your own. + + + + + Add flair to your docs with personalized branding. + + + + Implement your OpenAPI spec and enable API user interaction. + + + + Draw insights from user interactions with your documentation. + + + + Keep your docs on your own website's subdomain. + + + diff --git a/apps/docs/snippets/snippet-intro.mdx b/apps/docs/snippets/snippet-intro.mdx new file mode 100644 index 0000000..c57e7c7 --- /dev/null +++ b/apps/docs/snippets/snippet-intro.mdx @@ -0,0 +1,4 @@ +One of the core principles of software development is DRY (Don't Repeat +Yourself). This is a principle that apply to documentation as +well. If you find yourself repeating the same content in multiple places, you +should consider creating a custom snippet to keep your content in sync. diff --git a/apps/email-playground/.gitignore b/apps/email-playground/.gitignore new file mode 100644 index 0000000..9e9e879 --- /dev/null +++ b/apps/email-playground/.gitignore @@ -0,0 +1 @@ +.react-email \ No newline at end of file diff --git a/apps/email-playground/emails/contact.tsx b/apps/email-playground/emails/contact.tsx new file mode 100644 index 0000000..2bc22d1 --- /dev/null +++ b/apps/email-playground/emails/contact.tsx @@ -0,0 +1,11 @@ +import { ContactTemplate } from '@konobangu/email/templates/contact'; + +const ExampleContactEmail = () => ( + +); + +export default ExampleContactEmail; diff --git a/apps/email-playground/package.json b/apps/email-playground/package.json new file mode 100644 index 0000000..7209526 --- /dev/null +++ b/apps/email-playground/package.json @@ -0,0 +1,24 @@ +{ + "name": "email-playground", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "email build", + "dev": "email dev --port 3003", + "export": "email export", + "clean": "git clean -xdf .cache .turbo dist node_modules", + "typecheck": "tsc --noEmit --emitDeclarationOnly false" + }, + "dependencies": { + "@react-email/components": "0.0.31", + "@konobangu/email": "workspace:*", + "react": "^19.0.0", + "react-email": "3.0.4" + }, + "devDependencies": { + "@konobangu/typescript-config": "workspace:*", + "@types/node": "22.10.1", + "@types/react": "19.0.1", + "typescript": "^5.7.2" + } +} diff --git a/apps/email-playground/tsconfig.json b/apps/email-playground/tsconfig.json new file mode 100644 index 0000000..9d2f043 --- /dev/null +++ b/apps/email-playground/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@konobangu/typescript-config/nextjs.json", + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/apps/proxy/package.json b/apps/proxy/package.json index 7eba008..18bc1c5 100644 --- a/apps/proxy/package.json +++ b/apps/proxy/package.json @@ -3,11 +3,13 @@ "version": "0.1.0", "private": true, "scripts": { - "start": "whistle run -p 8899 -t 30000 -M \"keepXFF|prod|capture\" -D . --no-global-plugins" + "start": "cross-env WHISTLE_MODE=\"prod|capture|keepXFF\" whistle run -p 8899 -t 30000 -D . --no-global-plugins", + "dev": "pnpm run start" }, "keywords": [], "license": "MIT", "devDependencies": { - "whistle": "^2.9.61" + "whistle": "^2.9.61", + "cross-env": "^7.0.3" } } \ No newline at end of file diff --git a/crates/recorder/.devcontainer/Dockerfile b/apps/recorder/.devcontainer/Dockerfile similarity index 100% rename from crates/recorder/.devcontainer/Dockerfile rename to apps/recorder/.devcontainer/Dockerfile diff --git a/crates/recorder/.devcontainer/devcontainer.json b/apps/recorder/.devcontainer/devcontainer.json similarity index 100% rename from crates/recorder/.devcontainer/devcontainer.json rename to apps/recorder/.devcontainer/devcontainer.json diff --git a/crates/recorder/.devcontainer/docker-compose.yml b/apps/recorder/.devcontainer/docker-compose.yml similarity index 100% rename from crates/recorder/.devcontainer/docker-compose.yml rename to apps/recorder/.devcontainer/docker-compose.yml diff --git a/crates/recorder/.github/workflows/ci.yaml b/apps/recorder/.github/workflows/ci.yaml similarity index 100% rename from crates/recorder/.github/workflows/ci.yaml rename to apps/recorder/.github/workflows/ci.yaml diff --git a/crates/recorder/.gitignore b/apps/recorder/.gitignore similarity index 100% rename from crates/recorder/.gitignore rename to apps/recorder/.gitignore diff --git a/crates/recorder/Cargo.toml b/apps/recorder/Cargo.toml similarity index 93% rename from crates/recorder/Cargo.toml rename to apps/recorder/Cargo.toml index a6e70cf..0ce4b1d 100644 --- a/crates/recorder/Cargo.toml +++ b/apps/recorder/Cargo.toml @@ -14,6 +14,8 @@ path = "src/bin/main.rs" required-features = [] [dependencies] +quirks_path = { path = "../../packages/quirks-path" } +torrent = { path = "../../packages/torrent" } loco-rs = { version = "0.13" } serde = { version = "1", features = ["derive"] } serde_json = "1" @@ -47,8 +49,6 @@ maplit = "1.0.2" lightningcss = "1.0.0-alpha.61" html-escape = "0.2.13" opendal = { version = "0.51.0", features = ["default", "services-fs"] } -quirks_path = { path = "../quirks-path" } -torrent = { path = "../torrent" } zune-image = "0.4.15" once_cell = "1.20.2" reqwest-middleware = "0.4.0" diff --git a/crates/recorder/examples/playground.rs b/apps/recorder/examples/playground.rs similarity index 100% rename from crates/recorder/examples/playground.rs rename to apps/recorder/examples/playground.rs diff --git a/crates/recorder/src/app.rs b/apps/recorder/src/app.rs similarity index 100% rename from crates/recorder/src/app.rs rename to apps/recorder/src/app.rs diff --git a/crates/recorder/src/bin/main.rs b/apps/recorder/src/bin/main.rs similarity index 100% rename from crates/recorder/src/bin/main.rs rename to apps/recorder/src/bin/main.rs diff --git a/crates/recorder/src/config/mod.rs b/apps/recorder/src/config/mod.rs similarity index 100% rename from crates/recorder/src/config/mod.rs rename to apps/recorder/src/config/mod.rs diff --git a/crates/recorder/src/controllers/mod.rs b/apps/recorder/src/controllers/mod.rs similarity index 100% rename from crates/recorder/src/controllers/mod.rs rename to apps/recorder/src/controllers/mod.rs diff --git a/crates/recorder/src/controllers/subscribers.rs b/apps/recorder/src/controllers/subscribers.rs similarity index 100% rename from crates/recorder/src/controllers/subscribers.rs rename to apps/recorder/src/controllers/subscribers.rs diff --git a/crates/recorder/src/dal/client.rs b/apps/recorder/src/dal/client.rs similarity index 100% rename from crates/recorder/src/dal/client.rs rename to apps/recorder/src/dal/client.rs diff --git a/crates/recorder/src/dal/config.rs b/apps/recorder/src/dal/config.rs similarity index 100% rename from crates/recorder/src/dal/config.rs rename to apps/recorder/src/dal/config.rs diff --git a/crates/recorder/src/dal/mod.rs b/apps/recorder/src/dal/mod.rs similarity index 100% rename from crates/recorder/src/dal/mod.rs rename to apps/recorder/src/dal/mod.rs diff --git a/crates/recorder/src/extract/defs.rs b/apps/recorder/src/extract/defs.rs similarity index 100% rename from crates/recorder/src/extract/defs.rs rename to apps/recorder/src/extract/defs.rs diff --git a/crates/recorder/src/extract/errors.rs b/apps/recorder/src/extract/errors.rs similarity index 100% rename from crates/recorder/src/extract/errors.rs rename to apps/recorder/src/extract/errors.rs diff --git a/crates/recorder/src/extract/html/mod.rs b/apps/recorder/src/extract/html/mod.rs similarity index 100% rename from crates/recorder/src/extract/html/mod.rs rename to apps/recorder/src/extract/html/mod.rs diff --git a/crates/recorder/src/extract/html/styles.rs b/apps/recorder/src/extract/html/styles.rs similarity index 100% rename from crates/recorder/src/extract/html/styles.rs rename to apps/recorder/src/extract/html/styles.rs diff --git a/crates/recorder/src/extract/mikan/client.rs b/apps/recorder/src/extract/mikan/client.rs similarity index 100% rename from crates/recorder/src/extract/mikan/client.rs rename to apps/recorder/src/extract/mikan/client.rs diff --git a/crates/recorder/src/extract/mikan/config.rs b/apps/recorder/src/extract/mikan/config.rs similarity index 100% rename from crates/recorder/src/extract/mikan/config.rs rename to apps/recorder/src/extract/mikan/config.rs diff --git a/crates/recorder/src/extract/mikan/constants.rs b/apps/recorder/src/extract/mikan/constants.rs similarity index 100% rename from crates/recorder/src/extract/mikan/constants.rs rename to apps/recorder/src/extract/mikan/constants.rs diff --git a/crates/recorder/src/extract/mikan/mod.rs b/apps/recorder/src/extract/mikan/mod.rs similarity index 100% rename from crates/recorder/src/extract/mikan/mod.rs rename to apps/recorder/src/extract/mikan/mod.rs diff --git a/crates/recorder/src/extract/mikan/rss_parser.rs b/apps/recorder/src/extract/mikan/rss_parser.rs similarity index 100% rename from crates/recorder/src/extract/mikan/rss_parser.rs rename to apps/recorder/src/extract/mikan/rss_parser.rs diff --git a/crates/recorder/src/extract/mikan/web_parser.rs b/apps/recorder/src/extract/mikan/web_parser.rs similarity index 100% rename from crates/recorder/src/extract/mikan/web_parser.rs rename to apps/recorder/src/extract/mikan/web_parser.rs diff --git a/crates/recorder/src/extract/mod.rs b/apps/recorder/src/extract/mod.rs similarity index 100% rename from crates/recorder/src/extract/mod.rs rename to apps/recorder/src/extract/mod.rs diff --git a/crates/recorder/src/extract/rawname/mod.rs b/apps/recorder/src/extract/rawname/mod.rs similarity index 100% rename from crates/recorder/src/extract/rawname/mod.rs rename to apps/recorder/src/extract/rawname/mod.rs diff --git a/crates/recorder/src/extract/rawname/parser.rs b/apps/recorder/src/extract/rawname/parser.rs similarity index 99% rename from crates/recorder/src/extract/rawname/parser.rs rename to apps/recorder/src/extract/rawname/parser.rs index 1fa8d26..ef597d0 100644 --- a/crates/recorder/src/extract/rawname/parser.rs +++ b/apps/recorder/src/extract/rawname/parser.rs @@ -282,7 +282,7 @@ pub fn parse_episode_meta_from_raw_name(s: &str) -> eyre::Result if movie_capture { title_body += title_episode; title_episode = ""; - } else if EP_COLLECTION_RE.is_match(&title_episode) { + } else if EP_COLLECTION_RE.is_match(title_episode) { title_episode = ""; } diff --git a/crates/recorder/src/extract/torrent/mod.rs b/apps/recorder/src/extract/torrent/mod.rs similarity index 100% rename from crates/recorder/src/extract/torrent/mod.rs rename to apps/recorder/src/extract/torrent/mod.rs diff --git a/crates/recorder/src/extract/torrent/parser.rs b/apps/recorder/src/extract/torrent/parser.rs similarity index 100% rename from crates/recorder/src/extract/torrent/parser.rs rename to apps/recorder/src/extract/torrent/parser.rs diff --git a/crates/recorder/src/fetch/bytes.rs b/apps/recorder/src/fetch/bytes.rs similarity index 100% rename from crates/recorder/src/fetch/bytes.rs rename to apps/recorder/src/fetch/bytes.rs diff --git a/crates/recorder/src/fetch/client.rs b/apps/recorder/src/fetch/client.rs similarity index 100% rename from crates/recorder/src/fetch/client.rs rename to apps/recorder/src/fetch/client.rs diff --git a/crates/recorder/src/fetch/core.rs b/apps/recorder/src/fetch/core.rs similarity index 100% rename from crates/recorder/src/fetch/core.rs rename to apps/recorder/src/fetch/core.rs diff --git a/crates/recorder/src/fetch/html.rs b/apps/recorder/src/fetch/html.rs similarity index 100% rename from crates/recorder/src/fetch/html.rs rename to apps/recorder/src/fetch/html.rs diff --git a/crates/recorder/src/fetch/image.rs b/apps/recorder/src/fetch/image.rs similarity index 100% rename from crates/recorder/src/fetch/image.rs rename to apps/recorder/src/fetch/image.rs diff --git a/crates/recorder/src/fetch/mod.rs b/apps/recorder/src/fetch/mod.rs similarity index 100% rename from crates/recorder/src/fetch/mod.rs rename to apps/recorder/src/fetch/mod.rs diff --git a/crates/recorder/src/lib.rs b/apps/recorder/src/lib.rs similarity index 100% rename from crates/recorder/src/lib.rs rename to apps/recorder/src/lib.rs diff --git a/crates/recorder/src/migrations/defs.rs b/apps/recorder/src/migrations/defs.rs similarity index 100% rename from crates/recorder/src/migrations/defs.rs rename to apps/recorder/src/migrations/defs.rs diff --git a/crates/recorder/src/migrations/m20220101_000001_init.rs b/apps/recorder/src/migrations/m20220101_000001_init.rs similarity index 100% rename from crates/recorder/src/migrations/m20220101_000001_init.rs rename to apps/recorder/src/migrations/m20220101_000001_init.rs diff --git a/crates/recorder/src/migrations/m20240224_082543_add_downloads.rs b/apps/recorder/src/migrations/m20240224_082543_add_downloads.rs similarity index 100% rename from crates/recorder/src/migrations/m20240224_082543_add_downloads.rs rename to apps/recorder/src/migrations/m20240224_082543_add_downloads.rs diff --git a/crates/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs b/apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs similarity index 100% rename from crates/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs rename to apps/recorder/src/migrations/m20240225_060853_subscriber_add_downloader.rs diff --git a/crates/recorder/src/migrations/mod.rs b/apps/recorder/src/migrations/mod.rs similarity index 100% rename from crates/recorder/src/migrations/mod.rs rename to apps/recorder/src/migrations/mod.rs diff --git a/crates/recorder/src/models/bangumi.rs b/apps/recorder/src/models/bangumi.rs similarity index 100% rename from crates/recorder/src/models/bangumi.rs rename to apps/recorder/src/models/bangumi.rs diff --git a/crates/recorder/src/models/downloaders.rs b/apps/recorder/src/models/downloaders.rs similarity index 100% rename from crates/recorder/src/models/downloaders.rs rename to apps/recorder/src/models/downloaders.rs diff --git a/crates/recorder/src/models/downloads.rs b/apps/recorder/src/models/downloads.rs similarity index 100% rename from crates/recorder/src/models/downloads.rs rename to apps/recorder/src/models/downloads.rs diff --git a/crates/recorder/src/models/entities/bangumi.rs b/apps/recorder/src/models/entities/bangumi.rs similarity index 100% rename from crates/recorder/src/models/entities/bangumi.rs rename to apps/recorder/src/models/entities/bangumi.rs diff --git a/crates/recorder/src/models/entities/downloaders.rs b/apps/recorder/src/models/entities/downloaders.rs similarity index 100% rename from crates/recorder/src/models/entities/downloaders.rs rename to apps/recorder/src/models/entities/downloaders.rs diff --git a/crates/recorder/src/models/entities/downloads.rs b/apps/recorder/src/models/entities/downloads.rs similarity index 100% rename from crates/recorder/src/models/entities/downloads.rs rename to apps/recorder/src/models/entities/downloads.rs diff --git a/crates/recorder/src/models/entities/episodes.rs b/apps/recorder/src/models/entities/episodes.rs similarity index 100% rename from crates/recorder/src/models/entities/episodes.rs rename to apps/recorder/src/models/entities/episodes.rs diff --git a/crates/recorder/src/models/entities/mod.rs b/apps/recorder/src/models/entities/mod.rs similarity index 100% rename from crates/recorder/src/models/entities/mod.rs rename to apps/recorder/src/models/entities/mod.rs diff --git a/crates/recorder/src/models/entities/subscribers.rs b/apps/recorder/src/models/entities/subscribers.rs similarity index 100% rename from crates/recorder/src/models/entities/subscribers.rs rename to apps/recorder/src/models/entities/subscribers.rs diff --git a/crates/recorder/src/models/entities/subscriptions.rs b/apps/recorder/src/models/entities/subscriptions.rs similarity index 100% rename from crates/recorder/src/models/entities/subscriptions.rs rename to apps/recorder/src/models/entities/subscriptions.rs diff --git a/crates/recorder/src/models/episodes.rs b/apps/recorder/src/models/episodes.rs similarity index 100% rename from crates/recorder/src/models/episodes.rs rename to apps/recorder/src/models/episodes.rs diff --git a/crates/recorder/src/models/mod.rs b/apps/recorder/src/models/mod.rs similarity index 100% rename from crates/recorder/src/models/mod.rs rename to apps/recorder/src/models/mod.rs diff --git a/crates/recorder/src/models/notifications.rs b/apps/recorder/src/models/notifications.rs similarity index 100% rename from crates/recorder/src/models/notifications.rs rename to apps/recorder/src/models/notifications.rs diff --git a/crates/recorder/src/models/prelude.rs b/apps/recorder/src/models/prelude.rs similarity index 100% rename from crates/recorder/src/models/prelude.rs rename to apps/recorder/src/models/prelude.rs diff --git a/crates/recorder/src/models/query/mod.rs b/apps/recorder/src/models/query/mod.rs similarity index 100% rename from crates/recorder/src/models/query/mod.rs rename to apps/recorder/src/models/query/mod.rs diff --git a/crates/recorder/src/models/subscribers.rs b/apps/recorder/src/models/subscribers.rs similarity index 100% rename from crates/recorder/src/models/subscribers.rs rename to apps/recorder/src/models/subscribers.rs diff --git a/crates/recorder/src/models/subscriptions.rs b/apps/recorder/src/models/subscriptions.rs similarity index 93% rename from crates/recorder/src/models/subscriptions.rs rename to apps/recorder/src/models/subscriptions.rs index f05672d..490d6ad 100644 --- a/crates/recorder/src/models/subscriptions.rs +++ b/apps/recorder/src/models/subscriptions.rs @@ -196,17 +196,17 @@ impl Model { if let MikanBangumiPosterMeta { poster_src: Some(poster_src), .. - } = parse_mikan_bangumi_poster_from_origin_poster_src_with_cache( - ctx, - origin_poster_src, - self.subscriber_id, - ) - .await? - { - am.poster_link = ActiveValue::Set(Some(poster_src)) + } = parse_mikan_bangumi_poster_from_origin_poster_src_with_cache( + ctx, + origin_poster_src, + self.subscriber_id, + ) + .await? + { + am.poster_link = ActiveValue::Set(Some(poster_src)) + } } - } - Ok(()) + Ok(()) }, ) .await?, diff --git a/crates/recorder/src/tasks/mod.rs b/apps/recorder/src/tasks/mod.rs similarity index 100% rename from crates/recorder/src/tasks/mod.rs rename to apps/recorder/src/tasks/mod.rs diff --git a/crates/recorder/src/views/mod.rs b/apps/recorder/src/views/mod.rs similarity index 100% rename from crates/recorder/src/views/mod.rs rename to apps/recorder/src/views/mod.rs diff --git a/crates/recorder/src/views/subscribers.rs b/apps/recorder/src/views/subscribers.rs similarity index 100% rename from crates/recorder/src/views/subscribers.rs rename to apps/recorder/src/views/subscribers.rs diff --git a/crates/recorder/src/workers/mod.rs b/apps/recorder/src/workers/mod.rs similarity index 100% rename from crates/recorder/src/workers/mod.rs rename to apps/recorder/src/workers/mod.rs diff --git a/crates/recorder/src/workers/subscription_worker.rs b/apps/recorder/src/workers/subscription_worker.rs similarity index 100% rename from crates/recorder/src/workers/subscription_worker.rs rename to apps/recorder/src/workers/subscription_worker.rs diff --git a/crates/recorder/tests/mod.rs b/apps/recorder/tests/mod.rs similarity index 100% rename from crates/recorder/tests/mod.rs rename to apps/recorder/tests/mod.rs diff --git a/crates/recorder/tests/models/mod.rs b/apps/recorder/tests/models/mod.rs similarity index 100% rename from crates/recorder/tests/models/mod.rs rename to apps/recorder/tests/models/mod.rs diff --git a/crates/recorder/tests/models/snapshots/can_find_by_pid@subscribers-2.snap b/apps/recorder/tests/models/snapshots/can_find_by_pid@subscribers-2.snap similarity index 100% rename from crates/recorder/tests/models/snapshots/can_find_by_pid@subscribers-2.snap rename to apps/recorder/tests/models/snapshots/can_find_by_pid@subscribers-2.snap diff --git a/crates/recorder/tests/models/snapshots/can_find_by_pid@subscribers.snap b/apps/recorder/tests/models/snapshots/can_find_by_pid@subscribers.snap similarity index 100% rename from crates/recorder/tests/models/snapshots/can_find_by_pid@subscribers.snap rename to apps/recorder/tests/models/snapshots/can_find_by_pid@subscribers.snap diff --git a/crates/recorder/tests/models/subscribers.rs b/apps/recorder/tests/models/subscribers.rs similarity index 100% rename from crates/recorder/tests/models/subscribers.rs rename to apps/recorder/tests/models/subscribers.rs diff --git a/crates/recorder/tests/requests/mod.rs b/apps/recorder/tests/requests/mod.rs similarity index 100% rename from crates/recorder/tests/requests/mod.rs rename to apps/recorder/tests/requests/mod.rs diff --git a/crates/recorder/tests/requests/subscribers.rs b/apps/recorder/tests/requests/subscribers.rs similarity index 58% rename from crates/recorder/tests/requests/subscribers.rs rename to apps/recorder/tests/requests/subscribers.rs index 5d06180..2ad05b2 100644 --- a/crates/recorder/tests/requests/subscribers.rs +++ b/apps/recorder/tests/requests/subscribers.rs @@ -1,3 +1,4 @@ +#![allow(unused_imports)] use insta::{assert_debug_snapshot, with_settings}; use loco_rs::testing; use recorder::app::App; @@ -5,14 +6,14 @@ use serial_test::serial; // TODO: see how to dedup / extract this to app-local test utils // not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("user_request"); - let _guard = settings.bind_to_scope(); - }; -} +// macro_rules! configure_insta { +// ($($expr:expr),*) => { +// let mut settings = insta::Settings::clone_current(); +// settings.set_prepend_module_to_snapshot(false); +// settings.set_snapshot_suffix("user_request"); +// let _guard = settings.bind_to_scope(); +// }; +// } #[tokio::test] #[serial] @@ -25,8 +26,8 @@ async fn can_get_current_user() { // with_settings!({ // filters => testing::cleanup_user_model() // }, { - // assert_debug_snapshot!((response.status_code(), response.text())); - // }); + // assert_debug_snapshot!((response.status_code(), + // response.text())); }); // }) // .await; } diff --git a/crates/recorder/tests/tasks/mod.rs b/apps/recorder/tests/tasks/mod.rs similarity index 100% rename from crates/recorder/tests/tasks/mod.rs rename to apps/recorder/tests/tasks/mod.rs diff --git a/crates/recorder/tests/tasks/seed.rs b/apps/recorder/tests/tasks/seed.rs similarity index 87% rename from crates/recorder/tests/tasks/seed.rs rename to apps/recorder/tests/tasks/seed.rs index c7d95ea..01f7f52 100644 --- a/crates/recorder/tests/tasks/seed.rs +++ b/apps/recorder/tests/tasks/seed.rs @@ -13,6 +13,7 @@ //! ```sh //! cargo run task seed_data refresh:true //! ``` +#![allow(unused_imports)] use loco_rs::{db, prelude::*}; use recorder::{app::App, migrations::Migrator}; @@ -27,8 +28,9 @@ impl Task for SeedData { } } - async fn run(&self, app_context: &AppContext, vars: &task::Vars) -> Result<()> { - // let refresh = vars.cli.get("refresh").is_some_and(|refresh| refresh == "true"); + async fn run(&self, _app_context: &AppContext, _vars: &task::Vars) -> Result<()> { + // let refresh = vars.cli.get("refresh").is_some_and(|refresh| refresh == + // "true"); // // if refresh { // db::reset::(&app_context.db).await?; diff --git a/apps/storybook/.gitignore b/apps/storybook/.gitignore new file mode 100644 index 0000000..d85f7c1 --- /dev/null +++ b/apps/storybook/.gitignore @@ -0,0 +1,45 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# env files (can opt-in for commiting if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +*storybook.log + +# storybook +storybook-static/ \ No newline at end of file diff --git a/apps/storybook/.storybook/main.ts b/apps/storybook/.storybook/main.ts new file mode 100644 index 0000000..0592005 --- /dev/null +++ b/apps/storybook/.storybook/main.ts @@ -0,0 +1,30 @@ +import { dirname, join } from 'node:path'; +import type { StorybookConfig } from '@storybook/nextjs'; + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +const getAbsolutePath = (value: string) => + dirname(require.resolve(join(value, 'package.json'))); + +const config: StorybookConfig = { + stories: [ + '../stories/**/*.mdx', + '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)', + ], + addons: [ + getAbsolutePath('@storybook/addon-onboarding'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@chromatic-com/storybook'), + getAbsolutePath('@storybook/addon-interactions'), + getAbsolutePath('@storybook/addon-themes'), + ], + framework: { + name: getAbsolutePath('@storybook/nextjs'), + options: {}, + }, + staticDirs: ['../public'], +}; + +export default config; diff --git a/apps/storybook/.storybook/preview-head.html b/apps/storybook/.storybook/preview-head.html new file mode 100644 index 0000000..5873c0b --- /dev/null +++ b/apps/storybook/.storybook/preview-head.html @@ -0,0 +1,17 @@ + + + + + + + diff --git a/apps/storybook/.storybook/preview.tsx b/apps/storybook/.storybook/preview.tsx new file mode 100644 index 0000000..7c2c1fd --- /dev/null +++ b/apps/storybook/.storybook/preview.tsx @@ -0,0 +1,53 @@ +import { Toaster } from '@konobangu/design-system/components/ui/sonner'; +import { TooltipProvider } from '@konobangu/design-system/components/ui/tooltip'; +import { ThemeProvider } from '@konobangu/design-system/providers/theme'; +import { withThemeByClassName } from '@storybook/addon-themes'; +import type { Preview } from '@storybook/react'; + +import '@konobangu/design-system/styles/globals.css'; + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + chromatic: { + modes: { + light: { + theme: 'light', + className: 'light', + }, + dark: { + theme: 'dark', + className: 'dark', + }, + }, + }, + }, + decorators: [ + withThemeByClassName({ + themes: { + light: 'light', + dark: 'dark', + }, + defaultTheme: 'light', + }), + (Story) => { + return ( +
+ + + + + + +
+ ); + }, + ], +}; + +export default preview; diff --git a/apps/storybook/README.md b/apps/storybook/README.md new file mode 100644 index 0000000..ef0e47e --- /dev/null +++ b/apps/storybook/README.md @@ -0,0 +1,40 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/pages/api-reference/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn-pages-router) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/pages/building-your-application/deploying) for more details. diff --git a/apps/storybook/next.config.ts b/apps/storybook/next.config.ts new file mode 100644 index 0000000..b08f02b --- /dev/null +++ b/apps/storybook/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from 'next'; + +const nextConfig: NextConfig = { + reactStrictMode: true, +}; + +export default nextConfig; diff --git a/apps/storybook/package.json b/apps/storybook/package.json new file mode 100644 index 0000000..1cb1e32 --- /dev/null +++ b/apps/storybook/package.json @@ -0,0 +1,39 @@ +{ + "name": "storybook", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "storybook dev -p 6006", + "build-storybook": "storybook build", + "chromatic": "chromatic --exit-zero-on-changes", + "clean": "git clean -xdf .cache .turbo dist node_modules", + "typecheck": "tsc --noEmit --emitDeclarationOnly false" + }, + "dependencies": { + "@konobangu/design-system": "workspace:*", + "lucide-react": "^0.468.0", + "next": "^15.1.3", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@chromatic-com/storybook": "^3.2.2", + "@konobangu/typescript-config": "workspace:*", + "@storybook/addon-essentials": "^8.4.7", + "@storybook/addon-interactions": "^8.4.7", + "@storybook/addon-onboarding": "^8.4.7", + "@storybook/addon-themes": "^8.4.7", + "@storybook/blocks": "^8.4.7", + "@storybook/nextjs": "^8.4.7", + "@storybook/react": "^8.4.7", + "@storybook/test": "^8.4.7", + "@types/node": "^22", + "@types/react": "^19", + "@types/react-dom": "^19", + "chromatic": "^11.20.1", + "postcss": "^8", + "storybook": "^8.4.7", + "tailwindcss": "^3.4.16", + "typescript": "^5" + } +} diff --git a/apps/storybook/postcss.config.mjs b/apps/storybook/postcss.config.mjs new file mode 100644 index 0000000..1a69fd2 --- /dev/null +++ b/apps/storybook/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/apps/webui/app/favicon.ico b/apps/storybook/public/favicon.ico similarity index 100% rename from apps/webui/app/favicon.ico rename to apps/storybook/public/favicon.ico diff --git a/apps/storybook/stories/accordion.stories.tsx b/apps/storybook/stories/accordion.stories.tsx new file mode 100644 index 0000000..c08c137 --- /dev/null +++ b/apps/storybook/stories/accordion.stories.tsx @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@konobangu/design-system/components/ui/accordion'; + +/** + * A vertically stacked set of interactive headings that each reveal a section + * of content. + */ +const meta = { + title: 'ui/Accordion', + component: Accordion, + tags: ['autodocs'], + argTypes: { + type: { + options: ['single', 'multiple'], + control: { type: 'radio' }, + }, + }, + args: { + type: 'single', + collapsible: true, + }, + render: (args) => ( + + + Is it accessible? + + Yes. It adheres to the WAI-ARIA design pattern. + + + + Is it styled? + + Yes. It comes with default styles that matches the other components' + aesthetic. + + + + Is it animated? + + Yes. It's animated by default, but you can disable it if you prefer. + + + + ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default behavior of the accordion allows only one item to be open. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/alert-dialog.stories.tsx b/apps/storybook/stories/alert-dialog.stories.tsx new file mode 100644 index 0000000..1df1f2d --- /dev/null +++ b/apps/storybook/stories/alert-dialog.stories.tsx @@ -0,0 +1,54 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@konobangu/design-system/components/ui/alert-dialog'; + +/** + * A modal dialog that interrupts the user with important content and expects + * a response. + */ +const meta = { + title: 'ui/AlertDialog', + component: AlertDialog, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + Open + + + Are you sure absolutely sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + Cancel + Continue + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the alert dialog. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/alert.stories.tsx b/apps/storybook/stories/alert.stories.tsx new file mode 100644 index 0000000..6cede53 --- /dev/null +++ b/apps/storybook/stories/alert.stories.tsx @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { AlertCircle } from 'lucide-react'; + +import { + Alert, + AlertDescription, + AlertTitle, +} from '@konobangu/design-system/components/ui/alert'; + +/** + * Displays a callout for user attention. + */ +const meta = { + title: 'ui/Alert', + component: Alert, + tags: ['autodocs'], + argTypes: { + variant: { + options: ['default', 'destructive'], + control: { type: 'radio' }, + }, + }, + args: { + variant: 'default', + }, + render: (args) => ( + + Heads up! + + You can add components to your app using the cli. + + + ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; +/** + * The default form of the alert. + */ +export const Default: Story = {}; + +/** + * Use the `destructive` alert to indicate a destructive action. + */ +export const Destructive: Story = { + render: (args) => ( + + + Error + + Your session has expired. Please log in again. + + + ), + args: { + variant: 'destructive', + }, +}; diff --git a/apps/storybook/stories/aspect-ratio.stories.tsx b/apps/storybook/stories/aspect-ratio.stories.tsx new file mode 100644 index 0000000..b99d442 --- /dev/null +++ b/apps/storybook/stories/aspect-ratio.stories.tsx @@ -0,0 +1,71 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import Image from 'next/image'; + +import { AspectRatio } from '@konobangu/design-system/components/ui/aspect-ratio'; + +/** + * Displays content within a desired ratio. + */ +const meta: Meta = { + title: 'ui/AspectRatio', + component: AspectRatio, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + Photo by Alvaro Pinot + + ), + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the aspect ratio. + */ +export const Default: Story = { + args: { + ratio: 16 / 9, + }, +}; + +/** + * Use the `1:1` aspect ratio to display a square image. + */ +export const Square: Story = { + args: { + ratio: 1, + }, +}; + +/** + * Use the `4:3` aspect ratio to display a landscape image. + */ +export const Landscape: Story = { + args: { + ratio: 4 / 3, + }, +}; + +/** + * Use the `2.35:1` aspect ratio to display a cinemascope image. + */ +export const Cinemascope: Story = { + args: { + ratio: 2.35 / 1, + }, +}; diff --git a/apps/storybook/stories/avatar.stories.tsx b/apps/storybook/stories/avatar.stories.tsx new file mode 100644 index 0000000..45100c5 --- /dev/null +++ b/apps/storybook/stories/avatar.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from '@konobangu/design-system/components/ui/avatar'; + +/** + * An image element with a fallback for representing the user. + */ +const meta = { + title: 'ui/Avatar', + component: Avatar, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + + CN + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the avatar. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/badge.stories.tsx b/apps/storybook/stories/badge.stories.tsx new file mode 100644 index 0000000..4a72991 --- /dev/null +++ b/apps/storybook/stories/badge.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Badge } from '@konobangu/design-system/components/ui/badge'; + +/** + * Displays a badge or a component that looks like a badge. + */ +const meta = { + title: 'ui/Badge', + component: Badge, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + }, + }, + args: { + children: 'Badge', + }, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the badge. + */ +export const Default: Story = {}; + +/** + * Use the `secondary` badge to call for less urgent information, blending + * into the interface while still signaling minor updates or statuses. + */ +export const Secondary: Story = { + args: { + variant: 'secondary', + }, +}; + +/** + * Use the `destructive` badge to indicate errors, alerts, or the need for + * immediate attention. + */ +export const Destructive: Story = { + args: { + variant: 'destructive', + }, +}; + +/** + * Use the `outline` badge for overlaying without obscuring interface details, + * emphasizing clarity and subtlety.. + */ +export const Outline: Story = { + args: { + variant: 'outline', + }, +}; diff --git a/apps/storybook/stories/breadcrumb.stories.tsx b/apps/storybook/stories/breadcrumb.stories.tsx new file mode 100644 index 0000000..bb4ca82 --- /dev/null +++ b/apps/storybook/stories/breadcrumb.stories.tsx @@ -0,0 +1,78 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { ArrowRightSquare } from 'lucide-react'; + +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@konobangu/design-system/components/ui/breadcrumb'; + +/** + * Displays the path to the current resource using a hierarchy of links. + */ +const meta = { + title: 'ui/Breadcrumb', + component: Breadcrumb, + tags: ['autodocs'], + argTypes: {}, + args: {}, + render: (args) => ( + + + + Home + + + + Components + + + + Breadcrumb + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * Displays the path of links to the current resource. + */ +export const Default: Story = {}; + +/** + * Displays the path with a custom icon for the separator. + */ +export const WithCustomSeparator: Story = { + render: (args) => ( + + + + Home + + + + + + Components + + + + + + Breadcrumb + + + + ), +}; diff --git a/apps/storybook/stories/button.stories.tsx b/apps/storybook/stories/button.stories.tsx new file mode 100644 index 0000000..5cb5839 --- /dev/null +++ b/apps/storybook/stories/button.stories.tsx @@ -0,0 +1,157 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Loader2, Mail } from 'lucide-react'; + +import { Button } from '@konobangu/design-system/components/ui/button'; + +/** + * Displays a button or a component that looks like a button. + */ +const meta = { + title: 'ui/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + }, + }, + parameters: { + layout: 'centered', + }, + args: { + variant: 'default', + size: 'default', + children: 'Button', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the button, used for primary actions and commands. + */ +export const Default: Story = {}; + +/** + * Use the `outline` button to reduce emphasis on secondary actions, such as + * canceling or dismissing a dialog. + */ +export const Outline: Story = { + args: { + variant: 'outline', + }, +}; + +/** + * Use the `ghost` button is minimalistic and subtle, for less intrusive + * actions. + */ +export const Ghost: Story = { + args: { + variant: 'ghost', + }, +}; + +/** + * Use the `secondary` button to call for less emphasized actions, styled to + * complement the primary button while being less conspicuous. + */ +export const Secondary: Story = { + args: { + variant: 'secondary', + }, +}; + +/** + * Use the `destructive` button to indicate errors, alerts, or the need for + * immediate attention. + */ +export const Destructive: Story = { + args: { + variant: 'destructive', + }, +}; + +/** + * Use the `link` button to reduce emphasis on tertiary actions, such as + * hyperlink or navigation, providing a text-only interactive element. + */ +export const Link: Story = { + args: { + variant: 'link', + }, +}; + +/** + * Add the `disabled` prop to a button to prevent interactions and add a + * loading indicator, such as a spinner, to signify an in-progress action. + */ +export const Loading: Story = { + render: (args) => ( + + ), + args: { + ...Outline.args, + disabled: true, + }, +}; + +/** + * Add an icon element to a button to enhance visual communication and + * providing additional context for the action. + */ +export const WithIcon: Story = { + render: (args) => ( + + ), + args: { + ...Secondary.args, + }, +}; + +/** + * Use the `sm` size for a smaller button, suitable for interfaces needing + * compact elements without sacrificing usability. + */ +export const Small: Story = { + args: { + size: 'sm', + }, +}; + +/** + * Use the `lg` size for a larger button, offering better visibility and + * easier interaction for users. + */ +export const Large: Story = { + args: { + size: 'lg', + }, +}; + +/** + * Use the "icon" size for a button with only an icon. + */ +export const Icon: Story = { + args: { + ...Secondary.args, + size: 'icon', + children: , + }, +}; + +/** + * Add the `disabled` prop to prevent interactions with the button. + */ +export const Disabled: Story = { + args: { + disabled: true, + }, +}; diff --git a/apps/storybook/stories/calendar.stories.tsx b/apps/storybook/stories/calendar.stories.tsx new file mode 100644 index 0000000..ddd5b3f --- /dev/null +++ b/apps/storybook/stories/calendar.stories.tsx @@ -0,0 +1,81 @@ +import { action } from '@storybook/addon-actions'; +import type { Meta, StoryObj } from '@storybook/react'; +import { addDays } from 'date-fns'; + +import { Calendar } from '@konobangu/design-system/components/ui/calendar'; + +/** + * A date field component that allows users to enter and edit date. + */ +const meta = { + title: 'ui/Calendar', + component: Calendar, + tags: ['autodocs'], + argTypes: {}, + args: { + mode: 'single', + selected: new Date(), + onSelect: action('onDayClick'), + className: 'rounded-md border w-fit', + }, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the calendar. + */ +export const Default: Story = {}; + +/** + * Use the `multiple` mode to select multiple dates. + */ +export const Multiple: Story = { + args: { + min: 1, + selected: [new Date(), addDays(new Date(), 2), addDays(new Date(), 8)], + mode: 'multiple', + }, +}; + +/** + * Use the `range` mode to select a range of dates. + */ +export const Range: Story = { + args: { + selected: { + from: new Date(), + to: addDays(new Date(), 7), + }, + mode: 'range', + }, +}; + +/** + * Use the `disabled` prop to disable specific dates. + */ +export const Disabled: Story = { + args: { + disabled: [ + addDays(new Date(), 1), + addDays(new Date(), 2), + addDays(new Date(), 3), + addDays(new Date(), 5), + ], + }, +}; + +/** + * Use the `numberOfMonths` prop to display multiple months. + */ +export const MultipleMonths: Story = { + args: { + numberOfMonths: 2, + showOutsideDays: false, + }, +}; diff --git a/apps/storybook/stories/card.stories.tsx b/apps/storybook/stories/card.stories.tsx new file mode 100644 index 0000000..7e0c04c --- /dev/null +++ b/apps/storybook/stories/card.stories.tsx @@ -0,0 +1,75 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { BellRing } from 'lucide-react'; + +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@konobangu/design-system/components/ui/card'; + +const notifications = [ + { + title: 'Your call has been confirmed.', + description: '1 hour ago', + }, + { + title: 'You have a new message!', + description: '1 hour ago', + }, + { + title: 'Your subscription is expiring soon!', + description: '2 hours ago', + }, +]; + +/** + * Displays a card with header, content, and footer. + */ +const meta = { + title: 'ui/Card', + component: Card, + tags: ['autodocs'], + argTypes: {}, + args: { + className: 'w-96', + }, + render: (args) => ( + + + Notifications + You have 3 unread messages. + + + {notifications.map((notification, index) => ( +
+ +
+

{notification.title}

+

{notification.description}

+
+
+ ))} +
+ + + +
+ ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the card. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/carousel.stories.tsx b/apps/storybook/stories/carousel.stories.tsx new file mode 100644 index 0000000..0e0ec68 --- /dev/null +++ b/apps/storybook/stories/carousel.stories.tsx @@ -0,0 +1,73 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from '@konobangu/design-system/components/ui/carousel'; + +/** + * A carousel with motion and swipe built using Embla. + */ +const meta: Meta = { + title: 'ui/Carousel', + component: Carousel, + tags: ['autodocs'], + argTypes: {}, + args: { + className: 'w-full max-w-xs', + }, + render: (args) => ( + + + {Array.from({ length: 5 }).map((_, index) => ( + +
+ {index + 1} +
+
+ ))} +
+ + +
+ ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the carousel. + */ +export const Default: Story = {}; + +/** + * Use the `basis` utility class to change the size of the carousel. + */ +export const Size: Story = { + render: (args) => ( + + + {Array.from({ length: 5 }).map((_, index) => ( + +
+ {index + 1} +
+
+ ))} +
+ + +
+ ), + args: { + className: 'mx-12 w-full max-w-xs', + }, +}; diff --git a/apps/storybook/stories/chart.stories.tsx b/apps/storybook/stories/chart.stories.tsx new file mode 100644 index 0000000..d90937f --- /dev/null +++ b/apps/storybook/stories/chart.stories.tsx @@ -0,0 +1,271 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { useMemo } from 'react'; +import { + Area, + AreaChart, + Bar, + BarChart, + CartesianGrid, + Label, + Line, + LineChart, + Pie, + PieChart, + XAxis, +} from 'recharts'; + +import { + type ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from '@konobangu/design-system/components/ui/chart'; + +const multiSeriesData = [ + { month: 'January', desktop: 186, mobile: 80 }, + { month: 'February', desktop: 305, mobile: 200 }, + { month: 'March', desktop: 237, mobile: 120 }, + { month: 'April', desktop: 73, mobile: 190 }, + { month: 'May', desktop: 209, mobile: 130 }, + { month: 'June', desktop: 214, mobile: 140 }, +]; + +const multiSeriesConfig = { + desktop: { + label: 'Desktop', + color: 'hsl(var(--chart-1))', + }, + mobile: { + label: 'Mobile', + color: 'hsl(var(--chart-2))', + }, +} satisfies ChartConfig; + +const singleSeriesData = [ + { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' }, + { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' }, + { browser: 'other', visitors: 190, fill: 'var(--color-other)' }, +]; + +const singleSeriesConfig = { + visitors: { + label: 'Visitors', + }, + chrome: { + label: 'Chrome', + color: 'hsl(var(--chart-1))', + }, + safari: { + label: 'Safari', + color: 'hsl(var(--chart-2))', + }, + other: { + label: 'Other', + color: 'hsl(var(--chart-5))', + }, +} satisfies ChartConfig; + +/** + * Beautiful charts. Built using Recharts. Copy and paste into your apps. + */ +const meta = { + title: 'ui/Chart', + component: ChartContainer, + tags: ['autodocs'], + argTypes: {}, + args: { + children:
, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * Combine multiple Area components to create a stacked area chart. + */ +export const StackedAreaChart: Story = { + args: { + config: multiSeriesConfig, + }, + render: (args) => ( + + + + value.slice(0, 3)} + /> + } + /> + + + + + ), +}; + +/** + * Combine multiple Bar components to create a stacked bar chart. + */ +export const StackedBarChart: Story = { + args: { + config: multiSeriesConfig, + }, + render: (args) => ( + + + + value.slice(0, 3)} + /> + } + /> + + + + + ), +}; + +/** + * Combine multiple Line components to create a single line chart. + */ +export const MultiLineChart: Story = { + args: { + config: multiSeriesConfig, + }, + render: (args) => ( + + + + value.slice(0, 3)} + /> + } + /> + + + + + ), +}; + +/** + * Combine Pie and Label components to create a doughnut chart. + */ +export const DoughnutChart: Story = { + args: { + config: singleSeriesConfig, + }, + render: (args) => { + const totalVisitors = useMemo(() => { + return singleSeriesData.reduce((acc, curr) => acc + curr.visitors, 0); + }, []); + return ( + + + } + /> + + + + + ); + }, +}; diff --git a/apps/storybook/stories/checkbox.stories.tsx b/apps/storybook/stories/checkbox.stories.tsx new file mode 100644 index 0000000..0415d10 --- /dev/null +++ b/apps/storybook/stories/checkbox.stories.tsx @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Checkbox } from '@konobangu/design-system/components/ui/checkbox'; + +/** + * A control that allows the user to toggle between checked and not checked. + */ +const meta: Meta = { + title: 'ui/Checkbox', + component: Checkbox, + tags: ['autodocs'], + argTypes: {}, + args: { + id: 'terms', + disabled: false, + }, + render: (args) => ( +
+ + +
+ ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the checkbox. + */ +export const Default: Story = {}; + +/** + * Use the `disabled` prop to disable the checkbox. + */ +export const Disabled: Story = { + args: { + id: 'disabled-terms', + disabled: true, + }, +}; diff --git a/apps/storybook/stories/collapsible.stories.tsx b/apps/storybook/stories/collapsible.stories.tsx new file mode 100644 index 0000000..e4d6bd9 --- /dev/null +++ b/apps/storybook/stories/collapsible.stories.tsx @@ -0,0 +1,55 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Info } from 'lucide-react'; + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from '@konobangu/design-system/components/ui/collapsible'; + +/** + * An interactive component which expands/collapses a panel. + */ +const meta = { + title: 'ui/Collapsible', + component: Collapsible, + tags: ['autodocs'], + argTypes: {}, + args: { + className: 'w-96', + disabled: false, + }, + render: (args) => ( + + +

Can I use this in my project?

+ +
+ + Yes. Free to use for personal and commercial projects. No attribution + required. + +
+ ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the collapsible. + */ +export const Default: Story = {}; + +/** + * Use the `disabled` prop to disable the interaction. + */ +export const Disabled: Story = { + args: { + disabled: true, + }, +}; diff --git a/apps/storybook/stories/command.stories.tsx b/apps/storybook/stories/command.stories.tsx new file mode 100644 index 0000000..ca2a6ad --- /dev/null +++ b/apps/storybook/stories/command.stories.tsx @@ -0,0 +1,55 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { CommandSeparator } from 'cmdk'; + +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from '@konobangu/design-system/components/ui/command'; + +/** + * Fast, composable, unstyled command menu for React. + */ +const meta = { + title: 'ui/Command', + component: Command, + tags: ['autodocs'], + argTypes: {}, + args: { + className: 'rounded-lg w-96 border shadow-md', + }, + render: (args) => ( + + + + No results found. + + Calendar + Search Emoji + Calculator + + + + Profile + Billing + Settings + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the command. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/context-menu.stories.tsx b/apps/storybook/stories/context-menu.stories.tsx new file mode 100644 index 0000000..0133300 --- /dev/null +++ b/apps/storybook/stories/context-menu.stories.tsx @@ -0,0 +1,153 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + ContextMenu, + ContextMenuCheckboxItem, + ContextMenuContent, + ContextMenuItem, + ContextMenuLabel, + ContextMenuRadioGroup, + ContextMenuRadioItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from '@konobangu/design-system/components/ui/context-menu'; + +/** + * Displays a menu to the user — such as a set of actions or functions — + * triggered by a button. + */ +const meta = { + title: 'ui/ContextMenu', + component: ContextMenu, + tags: ['autodocs'], + argTypes: {}, + args: {}, + render: (args) => ( + + + Right click here + + + Profile + Billing + Team + Subscription + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the context menu. + */ +export const Default: Story = {}; + +/** + * A context menu with shortcuts. + */ +export const WithShortcuts: Story = { + render: (args) => ( + + + Right click here + + + + Back + ⌘[ + + + Forward + ⌘] + + + Reload + ⌘R + + + + ), +}; + +/** + * A context menu with a submenu. + */ +export const WithSubmenu: Story = { + render: (args) => ( + + + Right click here + + + + New Tab + ⌘N + + + More Tools + + + Save Page As... + ⇧⌘S + + Create Shortcut... + Name Window... + + Developer Tools + + + + + ), +}; + +/** + * A context menu with checkboxes. + */ +export const WithCheckboxes: Story = { + render: (args) => ( + + + Right click here + + + + Show Comments + ⌘⇧C + + Show Preview + + + ), +}; + +/** + * A context menu with a radio group. + */ +export const WithRadioGroup: Story = { + render: (args) => ( + + + Right click here + + + + Theme + Light + Dark + + + + ), +}; diff --git a/apps/storybook/stories/dialog.stories.tsx b/apps/storybook/stories/dialog.stories.tsx new file mode 100644 index 0000000..9ffd6f1 --- /dev/null +++ b/apps/storybook/stories/dialog.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@konobangu/design-system/components/ui/dialog'; + +/** + * A window overlaid on either the primary window or another dialog window, + * rendering the content underneath inert. + */ +const meta = { + title: 'ui/Dialog', + component: Dialog, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + + + + + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the dialog. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/drawer.stories.tsx b/apps/storybook/stories/drawer.stories.tsx new file mode 100644 index 0000000..45c0d00 --- /dev/null +++ b/apps/storybook/stories/drawer.stories.tsx @@ -0,0 +1,58 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from '@konobangu/design-system/components/ui/drawer'; + +/** + * A drawer component for React. + */ +const meta: Meta = { + title: 'ui/Drawer', + component: Drawer, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + Open + + + Are you sure absolutely sure? + This action cannot be undone. + + + + + + + + + + ), + parameters: { + layout: 'centered', + }, +}; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the drawer. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/dropdown-menu.stories.tsx b/apps/storybook/stories/dropdown-menu.stories.tsx new file mode 100644 index 0000000..701ee9d --- /dev/null +++ b/apps/storybook/stories/dropdown-menu.stories.tsx @@ -0,0 +1,159 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Mail, Plus, PlusCircle, Search, UserPlus } from 'lucide-react'; + +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from '@konobangu/design-system/components/ui/dropdown-menu'; + +/** + * Displays a menu to the user — such as a set of actions or functions — + * triggered by a button. + */ +const meta = { + title: 'ui/DropdownMenu', + component: DropdownMenu, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + Open + + My Account + + Profile + Billing + Team + Subscription + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the dropdown menu. + */ +export const Default: Story = {}; + +/** + * A dropdown menu with shortcuts. + */ +export const WithShortcuts: Story = { + render: (args) => ( + + Open + + Controls + + Back + ⌘[ + + + Forward + ⌘] + + + + ), +}; + +/** + * A dropdown menu with submenus. + */ +export const WithSubmenus: Story = { + render: (args) => ( + + Open + + + + Search + + + + + + New Team + ⌘+T + + + + + Invite users + + + + + + Email + + + + + More... + + + + + + + + ), +}; + +/** + * A dropdown menu with radio items. + */ +export const WithRadioItems: Story = { + render: (args) => ( + + Open + + Status + + Info + Warning + Error + + + + ), +}; + +/** + * A dropdown menu with checkboxes. + */ +export const WithCheckboxes: Story = { + render: (args) => ( + + Open + + + Autosave + ⌘S + + Show Comments + + + ), +}; diff --git a/apps/storybook/stories/form.stories.tsx b/apps/storybook/stories/form.stories.tsx new file mode 100644 index 0000000..d7bc5e8 --- /dev/null +++ b/apps/storybook/stories/form.stories.tsx @@ -0,0 +1,85 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { action } from '@storybook/addon-actions'; +import type { Meta, StoryObj } from '@storybook/react'; +import { useForm } from 'react-hook-form'; +import * as z from 'zod'; + +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@konobangu/design-system/components/ui/form'; + +/** + * Building forms with React Hook Form and Zod. + */ +const meta: Meta = { + title: 'ui/Form', + component: Form, + tags: ['autodocs'], + argTypes: {}, + render: (args) => , +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +const formSchema = z.object({ + username: z.string().min(2, { + message: 'Username must be at least 2 characters.', + }), +}); + +const ProfileForm = (args: Story['args']) => { + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + username: '', + }, + }); + function onSubmit(values: z.infer) { + action('onSubmit')(values); + } + return ( +
+ + ( + + Username + + + + + This is your public display name. + + + + )} + /> + + + + ); +}; + +/** + * The default form of the form. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/hover-card.stories.tsx b/apps/storybook/stories/hover-card.stories.tsx new file mode 100644 index 0000000..4b8b1d0 --- /dev/null +++ b/apps/storybook/stories/hover-card.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from '@konobangu/design-system/components/ui/hover-card'; + +/** + * For sighted users to preview content available behind a link. + */ +const meta = { + title: 'ui/HoverCard', + component: HoverCard, + tags: ['autodocs'], + argTypes: {}, + args: {}, + render: (args) => ( + + Hover + + The React Framework - created and maintained by @vercel. + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the hover card. + */ +export const Default: Story = {}; + +/** + * Use the `openDelay` and `closeDelay` props to control the delay before the + * hover card opens and closes. + */ +export const Instant: Story = { + args: { + openDelay: 0, + closeDelay: 0, + }, +}; diff --git a/apps/storybook/stories/input-otp.stories.tsx b/apps/storybook/stories/input-otp.stories.tsx new file mode 100644 index 0000000..c2102ab --- /dev/null +++ b/apps/storybook/stories/input-otp.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { REGEXP_ONLY_DIGITS_AND_CHARS } from 'input-otp'; + +import { + InputOTP, + InputOTPGroup, + InputOTPSeparator, + InputOTPSlot, +} from '@konobangu/design-system/components/ui/input-otp'; + +/** + * Accessible one-time password component with copy paste functionality. + */ +const meta = { + title: 'ui/InputOTP', + component: InputOTP, + tags: ['autodocs'], + argTypes: {}, + args: { + maxLength: 6, + pattern: REGEXP_ONLY_DIGITS_AND_CHARS, + children: null, + }, + + render: (args) => ( + + + + + + + + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the InputOTP field. + */ +export const Default: Story = {}; + +/** + * Use multiple groups to separate the input slots. + */ +export const SeparatedGroup: Story = { + render: (args) => ( + + + + + + + + + + + + + + ), +}; diff --git a/apps/storybook/stories/input.stories.tsx b/apps/storybook/stories/input.stories.tsx new file mode 100644 index 0000000..42abeb8 --- /dev/null +++ b/apps/storybook/stories/input.stories.tsx @@ -0,0 +1,84 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Input } from '@konobangu/design-system/components/ui/input'; + +/** + * Displays a form input field or a component that looks like an input field. + */ +const meta = { + title: 'ui/Input', + component: Input, + tags: ['autodocs'], + argTypes: {}, + args: { + className: 'w-96', + type: 'email', + placeholder: 'Email', + disabled: false, + }, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the input field. + */ +export const Default: Story = {}; + +/** + * Use the `disabled` prop to make the input non-interactive and appears faded, + * indicating that input is not currently accepted. + */ +export const Disabled: Story = { + args: { disabled: true }, +}; + +/** + * Use the `Label` component to includes a clear, descriptive label above or + * alongside the input area to guide users. + */ +export const WithLabel: Story = { + render: (args) => ( +
+ + +
+ ), +}; + +/** + * Use a text element below the input field to provide additional instructions + * or information to users. + */ +export const WithHelperText: Story = { + render: (args) => ( +
+ + +

Enter your email address.

+
+ ), +}; + +/** + * Use the `Button` component to indicate that the input field can be submitted + * or used to trigger an action. + */ +export const WithButton: Story = { + render: (args) => ( +
+ + +
+ ), +}; diff --git a/apps/storybook/stories/label.stories.tsx b/apps/storybook/stories/label.stories.tsx new file mode 100644 index 0000000..8e63fea --- /dev/null +++ b/apps/storybook/stories/label.stories.tsx @@ -0,0 +1,30 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Label } from '@konobangu/design-system/components/ui/label'; + +/** + * Renders an accessible label associated with controls. + */ +const meta = { + title: 'ui/Label', + component: Label, + tags: ['autodocs'], + argTypes: { + children: { + control: { type: 'text' }, + }, + }, + args: { + children: 'Your email address', + htmlFor: 'email', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the label. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/menubar.stories.tsx b/apps/storybook/stories/menubar.stories.tsx new file mode 100644 index 0000000..59d6103 --- /dev/null +++ b/apps/storybook/stories/menubar.stories.tsx @@ -0,0 +1,126 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Menubar, + MenubarCheckboxItem, + MenubarContent, + MenubarGroup, + MenubarItem, + MenubarLabel, + MenubarMenu, + MenubarRadioGroup, + MenubarRadioItem, + MenubarSeparator, + MenubarShortcut, + MenubarSub, + MenubarSubContent, + MenubarSubTrigger, + MenubarTrigger, +} from '@konobangu/design-system/components/ui/menubar'; + +/** + * A visually persistent menu common in desktop applications that provides + * quick access to a consistent set of commands. + */ +const meta = { + title: 'ui/Menubar', + component: Menubar, + tags: ['autodocs'], + argTypes: {}, + + render: (args) => ( + + + File + + + New Tab ⌘T + + New Window + + Share + + Print + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the menubar. + */ +export const Default: Story = {}; + +/** + * A menubar with a submenu. + */ +export const WithSubmenu: Story = { + render: (args) => ( + + + Actions + + Download + + Share + + Email link + Messages + Notes + + + + + + ), +}; + +/** + * A menubar with radio items. + */ +export const WithRadioItems: Story = { + render: (args) => ( + + + View + + Device Size + + Small + Medium + Large + + + + + ), +}; + +/** + * A menubar with checkbox items. + */ +export const WithCheckboxItems: Story = { + render: (args) => ( + + + Filters + + Show All + + Unread + Important + Flagged + + + + + ), +}; diff --git a/apps/storybook/stories/navigation-menu.stories.tsx b/apps/storybook/stories/navigation-menu.stories.tsx new file mode 100644 index 0000000..e2f158c --- /dev/null +++ b/apps/storybook/stories/navigation-menu.stories.tsx @@ -0,0 +1,79 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + navigationMenuTriggerStyle, +} from '@konobangu/design-system/components/ui/navigation-menu'; + +/** + * A collection of links for navigating websites. + */ +const meta = { + title: 'ui/NavigationMenu', + component: NavigationMenu, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + + + + Overview + + + + + + Documentation + + +
    +
  • + + API Reference + +
  • +
  • + + Getting Started + +
  • +
  • + + Guides + +
  • +
+
+
+
+ + + External + + +
+
+ ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the navigation menu. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/pagination.stories.tsx b/apps/storybook/stories/pagination.stories.tsx new file mode 100644 index 0000000..4ecb778 --- /dev/null +++ b/apps/storybook/stories/pagination.stories.tsx @@ -0,0 +1,57 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from '@konobangu/design-system/components/ui/pagination'; + +/** + * Pagination with page navigation, next and previous links. + */ +const meta = { + title: 'ui/Pagination', + component: Pagination, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + + + + + + 1 + + + 2 + + + 3 + + + + + + + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the pagination. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/popover.stories.tsx b/apps/storybook/stories/popover.stories.tsx new file mode 100644 index 0000000..16212ec --- /dev/null +++ b/apps/storybook/stories/popover.stories.tsx @@ -0,0 +1,36 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@konobangu/design-system/components/ui/popover'; + +/** + * Displays rich content in a portal, triggered by a button. + */ +const meta = { + title: 'ui/Popover', + component: Popover, + tags: ['autodocs'], + argTypes: {}, + + render: (args) => ( + + Open + Place content for the popover here. + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the popover. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/progress.stories.tsx b/apps/storybook/stories/progress.stories.tsx new file mode 100644 index 0000000..6969c73 --- /dev/null +++ b/apps/storybook/stories/progress.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Progress } from '@konobangu/design-system/components/ui/progress'; + +/** + * Displays an indicator showing the completion progress of a task, typically + * displayed as a progress bar. + */ +const meta = { + title: 'ui/Progress', + component: Progress, + tags: ['autodocs'], + argTypes: {}, + args: { + value: 30, + max: 100, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the progress. + */ +export const Default: Story = {}; + +/** + * When the progress is indeterminate. + */ +export const Indeterminate: Story = { + args: { + value: undefined, + }, +}; + +/** + * When the progress is completed. + */ +export const Completed: Story = { + args: { + value: 100, + }, +}; diff --git a/apps/storybook/stories/radio-group.stories.tsx b/apps/storybook/stories/radio-group.stories.tsx new file mode 100644 index 0000000..66df39f --- /dev/null +++ b/apps/storybook/stories/radio-group.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + RadioGroup, + RadioGroupItem, +} from '@konobangu/design-system/components/ui/radio-group'; + +/** + * A set of checkable buttons—known as radio buttons—where no more than one of + * the buttons can be checked at a time. + */ +const meta = { + title: 'ui/RadioGroup', + component: RadioGroup, + tags: ['autodocs'], + argTypes: {}, + args: { + defaultValue: 'comfortable', + className: 'grid gap-2 grid-cols-[1rem_1fr] items-center', + }, + render: (args) => ( + + + + + + + + + ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the radio group. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/resizable.stories.tsx b/apps/storybook/stories/resizable.stories.tsx new file mode 100644 index 0000000..b60bcad --- /dev/null +++ b/apps/storybook/stories/resizable.stories.tsx @@ -0,0 +1,59 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from '@konobangu/design-system/components/ui/resizable'; + +/** + * Accessible resizable panel groups and layouts with keyboard support. + */ +const meta: Meta = { + title: 'ui/ResizablePanelGroup', + component: ResizablePanelGroup, + tags: ['autodocs'], + argTypes: { + onLayout: { + control: false, + }, + }, + args: { + className: 'max-w-96 rounded-lg border', + direction: 'horizontal', + }, + render: (args) => ( + + +
+ One +
+
+ + + + +
+ Two +
+
+ + +
+ Three +
+
+
+
+
+ ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the resizable panel group. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/scroll-area.stories.tsx b/apps/storybook/stories/scroll-area.stories.tsx new file mode 100644 index 0000000..d9d8a9e --- /dev/null +++ b/apps/storybook/stories/scroll-area.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ScrollArea } from '@konobangu/design-system/components/ui/scroll-area'; + +/** + * Augments native scroll functionality for custom, cross-browser styling. + */ +const meta = { + title: 'ui/ScrollArea', + component: ScrollArea, + tags: ['autodocs'], + argTypes: { + children: { + control: 'text', + }, + }, + args: { + className: 'h-32 w-80 rounded-md border p-4', + type: 'auto', + children: + "Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but he couldn't seem to stop Jokester. And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop. The king was so angry that he banished Jokester from the kingdom, but the people still laughed, and they laughed, and they laughed. And they all lived happily ever after.", + }, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the scroll area. + */ +export const Default: Story = {}; + +/** + * Use the `type` prop with `always` to always show the scroll area. + */ +export const Always: Story = { + args: { + type: 'always', + }, +}; + +/** + * Use the `type` prop with `hover` to show the scroll area on hover. + */ +export const Hover: Story = { + args: { + type: 'hover', + }, +}; + +/** + * Use the `type` prop with `scroll` to show the scroll area when scrolling. + */ +export const Scroll: Story = { + args: { + type: 'scroll', + }, +}; diff --git a/apps/storybook/stories/select.stories.tsx b/apps/storybook/stories/select.stories.tsx new file mode 100644 index 0000000..e92b779 --- /dev/null +++ b/apps/storybook/stories/select.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectSeparator, + SelectTrigger, + SelectValue, +} from '@konobangu/design-system/components/ui/select'; + +/** + * Displays a list of options for the user to pick from—triggered by a button. + */ +const meta: Meta = { + title: 'ui/Select', + component: Select, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the select. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/separator.stories.tsx b/apps/storybook/stories/separator.stories.tsx new file mode 100644 index 0000000..f088a94 --- /dev/null +++ b/apps/storybook/stories/separator.stories.tsx @@ -0,0 +1,43 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Separator } from '@konobangu/design-system/components/ui/separator'; + +/** + * Visually or semantically separates content. + */ +const meta = { + title: 'ui/Separator', + component: Separator, + tags: ['autodocs'], + argTypes: {}, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the separator. + */ +export const Horizontal: Story = { + render: () => ( +
+
Left
+ +
Right
+
+ ), +}; + +/** + * A vertical separator. + */ +export const Vertical: Story = { + render: () => ( +
+
Top
+ +
Bottom
+
+ ), +}; diff --git a/apps/storybook/stories/sheet.stories.tsx b/apps/storybook/stories/sheet.stories.tsx new file mode 100644 index 0000000..934d99f --- /dev/null +++ b/apps/storybook/stories/sheet.stories.tsx @@ -0,0 +1,72 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@konobangu/design-system/components/ui/sheet'; + +/** + * Extends the Dialog component to display content that complements the main + * content of the screen. + */ +const meta: Meta = { + title: 'ui/Sheet', + component: Sheet, + tags: ['autodocs'], + argTypes: { + side: { + options: ['top', 'bottom', 'left', 'right'], + control: { + type: 'radio', + }, + }, + }, + args: { + side: 'right', + }, + render: (args) => ( + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + + + + + + + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the sheet. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/sidebar.stories.tsx b/apps/storybook/stories/sidebar.stories.tsx new file mode 100644 index 0000000..debdc54 --- /dev/null +++ b/apps/storybook/stories/sidebar.stories.tsx @@ -0,0 +1,494 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { + AudioWaveform, + BadgeCheck, + Bell, + BookOpen, + Bot, + ChevronRight, + ChevronsUpDown, + Command, + CreditCard, + Folder, + Forward, + Frame, + GalleryVerticalEnd, + LogOut, + // biome-ignore lint/suspicious/noShadowRestrictedNames: "icon name" + Map, + MoreHorizontal, + PieChart, + Plus, + Settings2, + Sparkles, + SquareTerminal, + Trash2, +} from 'lucide-react'; + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from '@konobangu/design-system/components/ui/avatar'; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@konobangu/design-system/components/ui/breadcrumb'; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from '@konobangu/design-system/components/ui/collapsible'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from '@konobangu/design-system/components/ui/dropdown-menu'; +import { Separator } from '@konobangu/design-system/components/ui/separator'; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupLabel, + SidebarHeader, + SidebarInset, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, + SidebarProvider, + SidebarRail, + SidebarTrigger, +} from '@konobangu/design-system/components/ui/sidebar'; +import { useState } from 'react'; + +const meta: Meta = { + title: 'ui/Sidebar', + component: Sidebar, + tags: ['autodocs'], + argTypes: {}, +}; +export default meta; + +type Story = StoryObj; + +const data = { + user: { + name: 'shadcn', + email: 'm@example.com', + avatar: '/avatars/shadcn.jpg', + }, + teams: [ + { + name: 'Acme Inc', + logo: GalleryVerticalEnd, + plan: 'Enterprise', + }, + { + name: 'Acme Corp.', + logo: AudioWaveform, + plan: 'Startup', + }, + { + name: 'Evil Corp.', + logo: Command, + plan: 'Free', + }, + ], + navMain: [ + { + title: 'Playground', + url: '#', + icon: SquareTerminal, + isActive: true, + items: [ + { + title: 'History', + url: '#', + }, + { + title: 'Starred', + url: '#', + }, + { + title: 'Settings', + url: '#', + }, + ], + }, + { + title: 'Models', + url: '#', + icon: Bot, + items: [ + { + title: 'Genesis', + url: '#', + }, + { + title: 'Explorer', + url: '#', + }, + { + title: 'Quantum', + url: '#', + }, + ], + }, + { + title: 'Documentation', + url: '#', + icon: BookOpen, + items: [ + { + title: 'Introduction', + url: '#', + }, + { + title: 'Get Started', + url: '#', + }, + { + title: 'Tutorials', + url: '#', + }, + { + title: 'Changelog', + url: '#', + }, + ], + }, + { + title: 'Settings', + url: '#', + icon: Settings2, + items: [ + { + title: 'General', + url: '#', + }, + { + title: 'Team', + url: '#', + }, + { + title: 'Billing', + url: '#', + }, + { + title: 'Limits', + url: '#', + }, + ], + }, + ], + projects: [ + { + name: 'Design Engineering', + url: '#', + icon: Frame, + }, + { + name: 'Sales & Marketing', + url: '#', + icon: PieChart, + }, + { + name: 'Travel', + url: '#', + icon: Map, + }, + ], +}; + +export const Base: Story = { + render: () => { + const [activeTeam, setActiveTeam] = useState(data.teams[0]); + + return ( + + + + + + + + +
+ +
+
+ + {activeTeam.name} + + + {activeTeam.plan} + +
+ +
+
+ + + Teams + + {data.teams.map((team, index) => ( + setActiveTeam(team)} + className="gap-2 p-2" + > +
+ +
+ {team.name} + + ⌘{index + 1} + +
+ ))} + + +
+ +
+
+ Add team +
+
+
+
+
+
+
+ + + Platform + + {data.navMain.map((item) => ( + + + + + {item.icon && } + {item.title} + + + + + + {item.items?.map((subItem) => ( + + +
+ {subItem.title} + + + + ))} + + + + + ))} + + + + Projects + + {data.projects.map((item) => ( + + + + + {item.name} + + + + + + + More + + + + + + View Project + + + + Share Project + + + + + Delete Project + + + + + ))} + + + + More + + + + + + + + + + + + + + + CN + + +
+ + {data.user.name} + + + {data.user.email} + +
+ +
+
+ + +
+ + + + CN + + +
+ + {data.user.name} + + + {data.user.email} + +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
+
+ + + +
+
+ + + + + + + Building Your Application + + + + + Data Fetching + + + +
+
+
+
+
+
+
+
+
+
+ + + ); + }, + args: {}, +}; diff --git a/apps/storybook/stories/skeleton.stories.tsx b/apps/storybook/stories/skeleton.stories.tsx new file mode 100644 index 0000000..a3cbd6d --- /dev/null +++ b/apps/storybook/stories/skeleton.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Skeleton } from '@konobangu/design-system/components/ui/skeleton'; + +/** + * Use to show a placeholder while content is loading. + */ +const meta = { + title: 'ui/Skeleton', + component: Skeleton, + tags: ['autodocs'], + argTypes: {}, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the skeleton. + */ +export const Default: Story = { + render: (args) => ( +
+ +
+ + +
+
+ ), +}; diff --git a/apps/storybook/stories/slider.stories.tsx b/apps/storybook/stories/slider.stories.tsx new file mode 100644 index 0000000..e6aac4d --- /dev/null +++ b/apps/storybook/stories/slider.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Slider } from '@konobangu/design-system/components/ui/slider'; + +/** + * An input where the user selects a value from within a given range. + */ +const meta = { + title: 'ui/Slider', + component: Slider, + tags: ['autodocs'], + argTypes: {}, + args: { + defaultValue: [33], + max: 100, + step: 1, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the slider. + */ +export const Default: Story = {}; + +/** + * Use the `inverted` prop to have the slider fill from right to left. + */ +export const Inverted: Story = { + args: { + inverted: true, + }, +}; + +/** + * Use the `disabled` prop to disable the slider. + */ +export const Disabled: Story = { + args: { + disabled: true, + }, +}; diff --git a/apps/storybook/stories/sonner.stories.tsx b/apps/storybook/stories/sonner.stories.tsx new file mode 100644 index 0000000..befc40d --- /dev/null +++ b/apps/storybook/stories/sonner.stories.tsx @@ -0,0 +1,50 @@ +import { action } from '@storybook/addon-actions'; +import type { Meta, StoryObj } from '@storybook/react'; +import { toast } from 'sonner'; + +import { Toaster } from '@konobangu/design-system/components/ui/sonner'; + +/** + * An opinionated toast component for React. + */ +const meta: Meta = { + title: 'ui/Sonner', + component: Toaster, + tags: ['autodocs'], + argTypes: {}, + args: { + position: 'bottom-right', + }, + parameters: { + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the toaster. + */ +export const Default: Story = { + render: (args) => ( +
+ + +
+ ), +}; diff --git a/apps/storybook/stories/switch.stories.tsx b/apps/storybook/stories/switch.stories.tsx new file mode 100644 index 0000000..3a25b89 --- /dev/null +++ b/apps/storybook/stories/switch.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Switch } from '@konobangu/design-system/components/ui/switch'; + +/** + * A control that allows the user to toggle between checked and not checked. + */ +const meta = { + title: 'ui/Switch', + component: Switch, + tags: ['autodocs'], + argTypes: {}, + parameters: { + layout: 'centered', + }, + render: (args) => ( +
+ + +
+ ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the switch. + */ +export const Default: Story = { + args: { + id: 'default-switch', + }, +}; + +/** + * Use the `disabled` prop to disable the switch. + */ +export const Disabled: Story = { + args: { + id: 'disabled-switch', + disabled: true, + }, +}; diff --git a/apps/storybook/stories/table.stories.tsx b/apps/storybook/stories/table.stories.tsx new file mode 100644 index 0000000..1bf2cb7 --- /dev/null +++ b/apps/storybook/stories/table.stories.tsx @@ -0,0 +1,80 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@konobangu/design-system/components/ui/table'; + +const invoices = [ + { + invoice: 'INV001', + paymentStatus: 'Paid', + totalAmount: '$250.00', + paymentMethod: 'Credit Card', + }, + { + invoice: 'INV002', + paymentStatus: 'Pending', + totalAmount: '$150.00', + paymentMethod: 'PayPal', + }, + { + invoice: 'INV003', + paymentStatus: 'Unpaid', + totalAmount: '$350.00', + paymentMethod: 'Bank Transfer', + }, + { + invoice: 'INV004', + paymentStatus: 'Paid', + totalAmount: '$450.00', + paymentMethod: 'Credit Card', + }, +]; + +/** + * Powerful table and datagrids built using TanStack Table. + */ +const meta = { + title: 'ui/Table', + component: Table, + tags: ['autodocs'], + argTypes: {}, + render: (args) => ( + + A list of your recent invoices. + + + Invoice + Status + Method + Amount + + + + {invoices.map((invoice) => ( + + {invoice.invoice} + {invoice.paymentStatus} + {invoice.paymentMethod} + {invoice.totalAmount} + + ))} + +
+ ), +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the table. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/tabs.stories.tsx b/apps/storybook/stories/tabs.stories.tsx new file mode 100644 index 0000000..2359528 --- /dev/null +++ b/apps/storybook/stories/tabs.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from '@konobangu/design-system/components/ui/tabs'; + +/** + * A set of layered sections of content—known as tab panels—that are displayed + * one at a time. + */ +const meta = { + title: 'ui/Tabs', + component: Tabs, + tags: ['autodocs'], + argTypes: {}, + args: { + defaultValue: 'account', + className: 'w-96', + }, + render: (args) => ( + + + Account + Password + + + Make changes to your account here. + + Change your password here. + + ), + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the tabs. + */ +export const Default: Story = {}; diff --git a/apps/storybook/stories/textarea.stories.tsx b/apps/storybook/stories/textarea.stories.tsx new file mode 100644 index 0000000..49f5387 --- /dev/null +++ b/apps/storybook/stories/textarea.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Textarea } from '@konobangu/design-system/components/ui/textarea'; + +/** + * Displays a form textarea or a component that looks like a textarea. + */ +const meta = { + title: 'ui/Textarea', + component: Textarea, + tags: ['autodocs'], + argTypes: {}, + args: { + placeholder: 'Type your message here.', + disabled: false, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +/** + * The default form of the textarea. + */ +export const Default: Story = {}; + +/** + * Use the `disabled` prop to disable the textarea. + */ +export const Disabled: Story = { + args: { + disabled: true, + }, +}; + +/** + * Use the `Label` component to includes a clear, descriptive label above or + * alongside the text area to guide users. + */ +export const WithLabel: Story = { + render: (args) => ( +
+ +