diff --git a/.gitignore b/.gitignore index cacf0c4f..a09fccbc 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts -.idea \ No newline at end of file +.idea + +/public/r \ No newline at end of file diff --git a/README.md b/README.md index 24592e0e..cf3ca8b7 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ registry's `/r/${component_name}.json` endpoint. This endpoint will provide v0 t and metadata to start your v0 chat with your component, theme, and other related code. These `/r/${component_name}.json` files are generated using `shadcn/ui` during the `build` and `dev` based on the -repository's [`registry.json`](./registry.json). For more information, refer to the +repository's [`registry.json`](./registries/registry.json). For more information, refer to the [documentation](https://ui.shadcn.com/docs/registry/registry-json). ## Theming @@ -43,7 +43,7 @@ on [ui.shadcn.com/docs](https://ui.shadcn.com/docs). #### MCP -To use this registry with MCP, you must also edit [`registry.json`](./registry.json)'s first +To use this registry with MCP, you must also edit [`registry.json`](./registries/registry.json)'s first `registry-item` named `theme`. This `registry:theme` item not only contains the tailwind configuration, but it also contains your design tokens / CSS variables. diff --git a/package.json b/package.json index 2b7d7ef8..b2049930 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "registry-starter", - "version": "0.0.1", + "version": "0.0.2", "private": true, "scripts": { "dev": "npm run registry:build && next dev --turbopack", @@ -8,10 +8,15 @@ "start": "next start", "lint": "biome check", "lint:fix": "biome check --write", - "registry:build": "npx shadcn@latest build && cp registry.json public/r/registry.json" + "registry_core:build": "npx shadcn@latest build ./registries/registry.json --output ./public/r && copy registries\\registry.json public\\r\\registry.json", + "registry_marketplace_next:build": "npx shadcn@latest build ./registries/marketplace/next/registry.json --output ./public/r/marketplace/next && copy registries\\marketplace\\next\\registry.json public\\r\\marketplace\\next\\registry.json", + "registry_marketplace_react:build": "npx shadcn@latest build ./registries/marketplace/react/registry.json --output ./public/r/marketplace/react && copy registries\\marketplace\\react\\registry.json public\\r\\marketplace\\react\\registry.json", + "registry:build": "npm run registry_core:build && npm run registry_marketplace_next:build && npm run registry_marketplace_react:build" }, "dependencies": { "@hookform/resolvers": "^5.1.1", + "@mdi/js": "^7.4.47", + "@mdi/react": "^1.6.1", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", "@radix-ui/react-aspect-ratio": "^1.1.7", @@ -38,6 +43,9 @@ "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.10", "@radix-ui/react-tooltip": "^1.2.7", + "@sitecore-marketplace-sdk/client": "^0.2.0", + "@sitecore-marketplace-sdk/xmc": "^0.2.1", + "@tanstack/react-form": "^1.21.3", "@tanstack/react-table": "^8.21.3", "@vercel/analytics": "^1.5.0", "@vercel/speed-insights": "^1.2.0", @@ -62,6 +70,8 @@ "zod": "^3.25.76" }, "devDependencies": { + "@auth0/auth0-react": "^2.5.0", + "@auth0/nextjs-auth0": "^4.10.0", "@biomejs/biome": "1.9.4", "@tailwindcss/postcss": "^4.1.11", "@testing-library/dom": "^10.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5317ade2..5522804c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@hookform/resolvers': specifier: ^5.1.1 version: 5.1.1(react-hook-form@7.60.0(react@19.1.0)) + '@mdi/js': + specifier: ^7.4.47 + version: 7.4.47 + '@mdi/react': + specifier: ^1.6.1 + version: 1.6.1 '@radix-ui/react-accordion': specifier: ^1.2.11 version: 1.2.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -89,6 +95,15 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.2.7 version: 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@sitecore-marketplace-sdk/client': + specifier: ^0.2.0 + version: 0.2.0 + '@sitecore-marketplace-sdk/xmc': + specifier: ^0.2.1 + version: 0.2.1(@sitecore-marketplace-sdk/client@0.2.0) + '@tanstack/react-form': + specifier: ^1.21.3 + version: 1.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -156,6 +171,12 @@ importers: specifier: ^3.25.76 version: 3.25.76 devDependencies: + '@auth0/auth0-react': + specifier: ^2.5.0 + version: 2.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@auth0/nextjs-auth0': + specifier: ^4.10.0 + version: 4.10.0(next@15.4.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@biomejs/biome': specifier: 1.9.4 version: 1.9.4 @@ -218,6 +239,22 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@auth0/auth0-react@2.5.0': + resolution: {integrity: sha512-o2nuJ85D4ESRybh3zbA5Dl1Oe17fRZL+/Q17b1qQdS+0QWZrXTEzTMD0wb0tYGST5rJb8rt7pVh6Tj4cWhdTCQ==} + peerDependencies: + react: ^16.11.0 || ^17 || ^18 || ^19 + react-dom: ^16.11.0 || ^17 || ^18 || ^19 + + '@auth0/auth0-spa-js@2.4.1': + resolution: {integrity: sha512-GE1XPLEgEUeqYBw5VcA52+3ubJDh4VKZFqdu0mr6h7anu+rFZb389cDbfpW145I23T1knZB/jvQtuRrkcLuT+Q==} + + '@auth0/nextjs-auth0@4.10.0': + resolution: {integrity: sha512-4CBuMlPJ4boxrB5IYisqMh9VBn74PGsspMfZpLG5JvrgDklw2CZsThW+UeAi1YMhE4/3VHyeht2yzN1Fs95bug==} + peerDependencies: + next: ^14.2.25 || ^15.2.3 + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -314,6 +351,10 @@ packages: '@date-fns/tz@1.2.0': resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + '@edge-runtime/cookies@5.0.2': + resolution: {integrity: sha512-Sd8LcWpZk/SWEeKGE8LT6gMm5MGfX/wm+GPnh1eBEtCpya3vYqn37wYknwAHw92ONoyyREl1hJwxV/Qx2DWNOg==} + engines: {node: '>=16'} + '@emnapi/runtime@1.4.4': resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} @@ -470,6 +511,10 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@hey-api/client-fetch@0.8.3': + resolution: {integrity: sha512-EBVa8wwUMyBSeQ32PtCz6u5bFQZIMAufvwCT1ZtpjqT3caJQEza4NokbGU50q1ZVrMsM5Ot6GuDNJOF3TMo26Q==} + deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. + '@hookform/resolvers@5.1.1': resolution: {integrity: sha512-J/NVING3LMAEvexJkyTLjruSm7aOFx7QX21pzkiJfMoNG0wl5aFEjLTl7ay7IQb9EWY6AkrBy7tHL2Alijpdcg==} peerDependencies: @@ -614,6 +659,12 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@mdi/js@7.4.47': + resolution: {integrity: sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==} + + '@mdi/react@1.6.1': + resolution: {integrity: sha512-4qZeDcluDFGFTWkHs86VOlHkm6gnKaMql13/gpIcUQ8kzxHgpj31NuCkD8abECVfbULJ3shc7Yt4HJ6Wu6SN4w==} + '@next/env@15.4.4': resolution: {integrity: sha512-SJKOOkULKENyHSYXE5+KiFU6itcIb6wSBjgM92meK0HVKpo94dNOLZVdLLuS7/BxImROkGoPsjR4EnuDucqiiA==} @@ -665,6 +716,9 @@ packages: cpu: [x64] os: [win32] + '@panva/hkdf@1.2.1': + resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -1380,6 +1434,18 @@ packages: cpu: [x64] os: [win32] + '@sitecore-marketplace-sdk/client@0.2.0': + resolution: {integrity: sha512-qG9EHp/5BZS3OXlD2M762q5SK9Cq5uMCUodlgoGtmCzdYGHkw1zToLMHveT7b9sxsIzn9r88Urwk45JX3Z8qrg==} + engines: {node: '>=16'} + + '@sitecore-marketplace-sdk/core@0.2.1': + resolution: {integrity: sha512-VASAsahBRyL0yukCFY/JUb663RCowJxGrqDI0F0rsU24IRZtxdMKiKa6ypMmAelDIRKuDnn4Tl7uJKUKqF0yfA==} + + '@sitecore-marketplace-sdk/xmc@0.2.1': + resolution: {integrity: sha512-yx3BLibH51h59vLKlxkNmwKpllJfJSFHUNUui+DaJ7XjPze+DSFbCr6I7Dsz++Nv6GEdlLlJPuvJc9oIK0VPOw==} + peerDependencies: + '@sitecore-marketplace-sdk/client': 0.2.0 + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -1549,6 +1615,28 @@ packages: '@tailwindcss/postcss@4.1.11': resolution: {integrity: sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==} + '@tanstack/devtools-event-client@0.2.5': + resolution: {integrity: sha512-iVdqw879KETXyyPHc3gQR5Ld0GjlPLk7bKenBUhzr3+z1FiQZvsbfgYfRRokTSPcgwANAV7aA2Uv05nx5xWT8A==} + engines: {node: '>=18'} + + '@tanstack/form-core@1.21.3': + resolution: {integrity: sha512-vSBWmc2WyMH2KbDwPp7aEvvfPXOiCAv/jhJ9dFojdI0eGggSdW/2mF7lXe5V5xgYfNeCH2cSztu2EykJp3I8tg==} + + '@tanstack/react-form@1.21.3': + resolution: {integrity: sha512-bd5kttI3s8gJNZMF1l3VVs0CuDa930z/OKhErCS7BSNO3XY7q/nPCffueFp9nGx0wa9mCumqOuuEP+Z0PPCgFw==} + peerDependencies: + '@tanstack/react-start': ^1.130.10 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@tanstack/react-start': + optional: true + + '@tanstack/react-store@0.7.5': + resolution: {integrity: sha512-A+WZtEnHZpvbKXm8qR+xndNKywBLez2KKKKEQc7w0Qs45GvY1LpRI3BTZNmELwEVim8+Apf99iEDH2J+MUIzlQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-table@8.21.3': resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} engines: {node: '>=12'} @@ -1556,6 +1644,9 @@ packages: react: '>=16.8' react-dom: '>=16.8' + '@tanstack/store@0.7.5': + resolution: {integrity: sha512-qd/OjkjaFRKqKU4Yjipaen/EOB9MyEg6Wr9fW103RBPACf1ZcKhbhcu2S5mj5IgdPib6xFIgCUti/mKVkl+fRw==} + '@tanstack/table-core@8.21.3': resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} engines: {node: '>=12'} @@ -1708,6 +1799,9 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + browser-tabs-lock@1.3.0: + resolution: {integrity: sha512-g6nHaobTiT0eMZ7jh16YpD2kcjAp+PInbiVq3M1x6KKaEIVhT4v9oURNIpZLOZ3LQbQ3XYfNhMAb/9hzNLIWrw==} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1840,6 +1934,9 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-formdata@0.9.0: + resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1855,6 +1952,9 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + devalue@5.3.2: + resolution: {integrity: sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -1864,6 +1964,9 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dpop@2.1.1: + resolution: {integrity: sha512-J0Of2JTiM4h5si0tlbPQ/lkqfZ5wAEVkKYBhkwyyANnPJfWH4VsR5uIkZ+T+OSPIwDYUg1fbd5Mmodd25HjY1w==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1889,6 +1992,9 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + es-cookie@1.3.2: + resolution: {integrity: sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -2004,6 +2110,9 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true + jose@6.1.0: + resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2169,10 +2278,16 @@ packages: nwsapi@2.2.20: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} + oauth4webapi@3.8.1: + resolution: {integrity: sha512-olkZDELNycOWQf9LrsELFq8n05LwJgV8UkrS0cburk6FOwf8GvLam+YB+Uj5Qvryee+vwWOfQVeI5Vm0MVg7SA==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + openid-client@6.8.0: + resolution: {integrity: sha512-oG1d1nAVhIIE+JSjLS+7E9wY1QOJpZltkzlJdbZ7kEn7Hp3hqur2TEeQ8gLOHoHkhbRAGZJKoOnEQcLOQJuIyg==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -2354,6 +2469,11 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + swr@2.3.6: + resolution: {integrity: sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -2428,6 +2548,14 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + vaul@1.1.2: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: @@ -2530,6 +2658,30 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 + '@auth0/auth0-react@2.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@auth0/auth0-spa-js': 2.4.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@auth0/auth0-spa-js@2.4.1': + dependencies: + browser-tabs-lock: 1.3.0 + dpop: 2.1.1 + es-cookie: 1.3.2 + + '@auth0/nextjs-auth0@4.10.0(next@15.4.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@edge-runtime/cookies': 5.0.2 + '@panva/hkdf': 1.2.1 + jose: 6.1.0 + next: 15.4.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + oauth4webapi: 3.8.1 + openid-client: 6.8.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + swr: 2.3.6(react@19.1.0) + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -2597,6 +2749,8 @@ snapshots: '@date-fns/tz@1.2.0': {} + '@edge-runtime/cookies@5.0.2': {} + '@emnapi/runtime@1.4.4': dependencies: tslib: 2.8.1 @@ -2688,6 +2842,8 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@hey-api/client-fetch@0.8.3': {} + '@hookform/resolvers@5.1.1(react-hook-form@7.60.0(react@19.1.0))': dependencies: '@standard-schema/utils': 0.3.0 @@ -2797,6 +2953,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 + '@mdi/js@7.4.47': {} + + '@mdi/react@1.6.1': + dependencies: + prop-types: 15.8.1 + '@next/env@15.4.4': {} '@next/swc-darwin-arm64@15.4.4': @@ -2823,6 +2985,8 @@ snapshots: '@next/swc-win32-x64-msvc@15.4.4': optional: true + '@panva/hkdf@1.2.1': {} + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.2': {} @@ -3538,6 +3702,22 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.45.0': optional: true + '@sitecore-marketplace-sdk/client@0.2.0': + dependencies: + '@sitecore-marketplace-sdk/core': 0.2.1 + tslib: 2.8.1 + uuid: 11.1.0 + + '@sitecore-marketplace-sdk/core@0.2.1': + dependencies: + tslib: 2.8.1 + uuid: 11.1.0 + + '@sitecore-marketplace-sdk/xmc@0.2.1(@sitecore-marketplace-sdk/client@0.2.0)': + dependencies: + '@hey-api/client-fetch': 0.8.3 + '@sitecore-marketplace-sdk/client': 0.2.0 + '@standard-schema/utils@0.3.0': {} '@swc/core-darwin-arm64@1.12.14': @@ -3668,12 +3848,39 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.11 + '@tanstack/devtools-event-client@0.2.5': {} + + '@tanstack/form-core@1.21.3': + dependencies: + '@tanstack/devtools-event-client': 0.2.5 + '@tanstack/store': 0.7.5 + uuid: 13.0.0 + + '@tanstack/react-form@1.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/form-core': 1.21.3 + '@tanstack/react-store': 0.7.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + decode-formdata: 0.9.0 + devalue: 5.3.2 + react: 19.1.0 + transitivePeerDependencies: + - react-dom + + '@tanstack/react-store@0.7.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/store': 0.7.5 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + '@tanstack/react-table@8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@tanstack/table-core': 8.21.3 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) + '@tanstack/store@0.7.5': {} + '@tanstack/table-core@8.21.3': {} '@testing-library/dom@10.4.0': @@ -3789,6 +3996,10 @@ snapshots: asynckit@0.4.0: {} + browser-tabs-lock@1.3.0: + dependencies: + lodash: 4.17.21 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3914,6 +4125,8 @@ snapshots: decimal.js@10.6.0: {} + decode-formdata@0.9.0: {} + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -3922,6 +4135,8 @@ snapshots: detect-node-es@1.1.0: {} + devalue@5.3.2: {} + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -3931,6 +4146,8 @@ snapshots: '@babel/runtime': 7.27.6 csstype: 3.1.3 + dpop@2.1.1: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3956,6 +4173,8 @@ snapshots: entities@6.0.1: {} + es-cookie@1.3.2: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -4088,6 +4307,8 @@ snapshots: jiti@2.4.2: {} + jose@6.1.0: {} + js-tokens@4.0.0: {} jsdom@25.0.1: @@ -4233,8 +4454,15 @@ snapshots: nwsapi@2.2.20: {} + oauth4webapi@3.8.1: {} + object-assign@4.1.1: {} + openid-client@6.8.0: + dependencies: + jose: 6.1.0 + oauth4webapi: 3.8.1 + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -4458,6 +4686,12 @@ snapshots: dependencies: has-flag: 4.0.0 + swr@2.3.6(react@19.1.0): + dependencies: + dequal: 2.0.3 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + symbol-tree@3.2.4: {} tailwind-merge@3.3.1: {} @@ -4518,6 +4752,10 @@ snapshots: dependencies: react: 19.1.0 + uuid@11.1.0: {} + + uuid@13.0.0: {} + vaul@1.1.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) diff --git a/registries/marketplace/next/registry.json b/registries/marketplace/next/registry.json new file mode 100644 index 00000000..bdd1fa51 --- /dev/null +++ b/registries/marketplace/next/registry.json @@ -0,0 +1,153 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry.json", + "name": "Sitecore Marketplace", + "homepage": "https://blok-shadcn.vercel.app", + "items": [ + { + "name": "quickstart", + "type": "registry:block", + "title": "Quickstart for Next.js", + "description": "A quickstart for next.js Sitecore marketplace apps with marketplace sdk", + "dependencies": [ + "@sitecore-marketplace-sdk/client" + ], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/badge.json", + "https://blok-shadcn.vercel.app/r/card.json", + "https://blok-shadcn.vercel.app/r/collapsible.json" + ], + "files": [ + { + "path": "src/marketplace/next/components/providers/marketplace.tsx", + "type": "registry:component", + "target": "components/providers/marketplace.tsx" + }, + { + "path": "src/marketplace/next/components/examples/build-in-auth/application-context.tsx", + "type": "registry:component", + "target": "components/examples/build-in-auth/application-context.tsx" + }, + { + "path": "src/marketplace/next/layouts/layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/marketplace/next/components/examples/build-in-auth/page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "quickstart-with-custom-auth", + "type": "registry:block", + "title": "Quickstart for Next js with server side authentication", + "description": "A quickstart for next.js Sitecore marketplace apps with server side authentication", + "dependencies": [ + "@auth0/auth0-react" + ], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/marketplace/next/quickstart.json" + ], + "files": [ + { + "path": "src/marketplace/next/components/providers/auth.tsx", + "type": "registry:component", + "target": "components/providers/auth.tsx" + }, + { + "path": "src/marketplace/next/layouts/with-auth.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/marketplace/next/next.config.ts", + "type": "registry:file", + "target": "next.config.ts" + } + ], + "envVars": { + "NEXT_PUBLIC_AUTH0_DOMAIN": "https://auth.sitecorecloud.io", + "NEXT_PUBLIC_AUTH0_AUDIENCE": "https://api-webapp.sitecorecloud.io", + "NEXT_PUBLIC_AUTH0_SCOPE": "openid profile email offline_access", + "NEXT_PUBLIC_AUTH0_CLIENT_ID": "your-marketplace-client-id", + "NEXT_PUBLIC_SITECORE_APP_ID": "your-app-id", + "NEXT_PUBLIC_APP_BASE_URL": "https://localhost:3000", + "NEXT_PUBLIC_SITECORE_ORGANIZATION_ID": "your-organization-id", + "NEXT_PUBLIC_SITECORE_TENANT_ID": "marketplace-app-tenant-id-after-installation" + }, + "docs": "Your app needs to run in 'https'. We suggest to add '--experimental-https' in your dev script in package.json. Also, make sure to update your environment variables. Happy coding!" + }, + { + "name": "quickstart-with-client-side-xmc", + "type": "registry:block", + "title": "Quickstart for Next.js with XMC API examples", + "description": "A quickstart for next.js Sitecore marketplace apps with XMC API examples", + "dependencies": [ + "@sitecore-marketplace-sdk/xmc" + ], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/marketplace/next/quickstart.json", + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/alert.json", + "https://blok-shadcn.vercel.app/r/skeleton.json", + "https://blok-shadcn.vercel.app/r/separator.json" + ], + "files": [ + { + "path": "src/marketplace/next/components/providers/marketplace-w-xmc.tsx", + "type": "registry:component", + "target": "components/providers/marketplace.tsx" + }, + { + "path": "src/marketplace/next/components/examples/build-in-auth/with-xmc/list-languages.tsx", + "type": "registry:component", + "target": "components/examples/build-in-auth/with-xmc/list-languages.tsx" + }, + { + "path": "src/marketplace/next/components/examples/build-in-auth/with-xmc/page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "quickstart-with-full-stack-xmc", + "type": "registry:block", + "title": "Quickstart for Next.js with full-stack XMC APIs examples", + "description": "A quickstart for next.js Sitecore marketplace apps with full-stack XMC API examples", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/marketplace/next/quickstart-with-custom-auth.json", + "https://blok-shadcn.vercel.app/r/marketplace/next/quickstart-with-client-side-xmc.json" + ], + "files": [ + { + "path": "src/marketplace/next/components/examples/custom-auth/with-api-route/list-languages.tsx", + "type": "registry:component", + "target": "components/examples/custom-auth/with-api-route/list-languages.tsx" + }, + { + "path": "src/marketplace/next/components/examples/custom-auth/with-api-route/route.ts", + "type": "registry:file", + "target": "app/api/sites/languages/route.ts" + }, + { + "path": "src/marketplace/next/components/examples/custom-auth/with-server-action/list-languages.tsx", + "type": "registry:component", + "target": "components/examples/custom-auth/with-server-action/list-languages.tsx" + }, + { + "path": "src/marketplace/next/components/examples/custom-auth/with-server-action/action.ts", + "type": "registry:file", + "target": "components/examples/custom-auth/with-server-action/action.ts" + }, + { + "path": "src/marketplace/next/components/examples/custom-auth/page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + } + ] +} \ No newline at end of file diff --git a/registries/marketplace/react/registry.json b/registries/marketplace/react/registry.json new file mode 100644 index 00000000..71e84c82 --- /dev/null +++ b/registries/marketplace/react/registry.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry.json", + "name": "sitecore marketplace", + "homepage": "https://blok-shadcn.vercel.app", + "items": [ + { + "name": "quickstart", + "type": "registry:block", + "title": "Quickstart for React SPA Sitecore marketplace apps with marketplace sdk", + "description": "A quickstart for next.js Sitecore marketplace apps with marketplace sdk", + "dependencies": [ + "@sitecore-marketplace-sdk/client" + ], + "files": [ + { + "path": "src/marketplace/react/components/providers/marketplace.tsx", + "type": "registry:file", + "target": "app/providers/marketplace.tsx" + }, + { + "path": "src/marketplace/react/components/examples/example.tsx", + "type": "registry:file", + "target": "app/page.tsx" + } + ] + }, + { + "name": "quickstart-with-xmc", + "type": "registry:block", + "title": "Examples for React SPA Sitecore marketplace apps with marketplace sdk", + "description": "Examples for next.js Sitecore marketplace apps with marketplace sdk", + "dependencies": [ + "@sitecore-marketplace-sdk/xmc" + ], + "registryDependencies":[ + "https://blok-shadcn.vercel.app/r/marketplace/react/quickstart.json" + ], + "files": [ + { + "path": "src/marketplace/react/components/providers/marketplace-w-xmc.tsx", + "type": "registry:file", + "target": "components/providers/marketplace.tsx" + }, + { + "path": "src/marketplace/react/components/examples/with-xmc/list-languages.tsx", + "type": "registry:file", + "target": "components/examples/with-xmc/list-languages.tsx" + }, + { + "path": "src/marketplace/react/components/examples/with-xmc/example.tsx", + "type": "registry:file", + "target": "app/page.tsx" + } + ] + } + ] + } \ No newline at end of file diff --git a/registries/registry.json b/registries/registry.json new file mode 100644 index 00000000..d2aef824 --- /dev/null +++ b/registries/registry.json @@ -0,0 +1,1265 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry.json", + "name": "blok", + "homepage": "https://blok-shadcn.vercel.app", + "items": [ + { + "name": "theme", + "type": "registry:theme", + "title": "Blokcn Theme", + "description": "A custom Blokcn theme providing reusable UI components styled with Tailwind CSS and shadcn/ui variables, designed for consistency and efficiency across projects.", + "cssVars": { + "light": { + "background": "oklch(0.97 0.01 80.72)", + "foreground": "oklch(0.3 0.04 30.2)", + "card": "oklch(0.97 0.01 80.72)", + "card-foreground": "oklch(0.3 0.04 30.2)", + "popover": "oklch(0.97 0.01 80.72)", + "popover-foreground": "oklch(0.3 0.04 30.2)", + "primary": "oklch(0.52 0.13 144.17)", + "primary-foreground": "oklch(1.0 0 0)", + "secondary": "oklch(0.96 0.02 147.64)", + "secondary-foreground": "oklch(0.43 0.12 144.31)", + "muted": "oklch(0.94 0.01 74.42)", + "muted-foreground": "oklch(0.45 0.05 39.21)", + "accent": "oklch(0.9 0.05 146.04)", + "accent-foreground": "oklch(0.43 0.12 144.31)", + "destructive": "oklch(0.54 0.19 26.72)", + "destructive-foreground": "oklch(1.0 0 0)", + "border": "oklch(0.88 0.02 74.64)", + "input": "oklch(0.88 0.02 74.64)", + "ring": "oklch(0.52 0.13 144.17)", + "chart-1": "oklch(0.67 0.16 144.21)", + "chart-2": "oklch(0.58 0.14 144.18)", + "chart-3": "oklch(0.52 0.13 144.17)", + "chart-4": "oklch(0.43 0.12 144.31)", + "chart-5": "oklch(0.22 0.05 145.73)", + "sidebar": "oklch(0.94 0.01 74.42)", + "sidebar-foreground": "oklch(0.3 0.04 30.2)", + "sidebar-primary": "oklch(0.52 0.13 144.17)", + "sidebar-primary-foreground": "oklch(1.0 0 0)", + "sidebar-accent": "oklch(0.9 0.05 146.04)", + "sidebar-accent-foreground": "oklch(0.43 0.12 144.31)", + "sidebar-border": "oklch(0.88 0.02 74.64)", + "sidebar-ring": "oklch(0.52 0.13 144.17)", + "radius": "0.5rem" + }, + "dark": { + "background": "oklch(0.15 0.01 74.42)", + "foreground": "oklch(0.95 0.02 80.72)", + "card": "oklch(0.12 0.01 80.72)", + "card-foreground": "oklch(0.95 0.02 80.72)", + "popover": "oklch(0.12 0.01 80.72)", + "popover-foreground": "oklch(0.95 0.02 80.72)", + "primary": "oklch(0.58 0.15 144.17)", + "primary-foreground": "oklch(0.09 0.01 80.72)", + "secondary": "oklch(0.15 0.02 147.64)", + "secondary-foreground": "oklch(0.65 0.12 144.31)", + "muted": "oklch(0.18 0.01 74.42)", + "muted-foreground": "oklch(0.65 0.03 74.42)", + "accent": "oklch(0.22 0.04 146.04)", + "accent-foreground": "oklch(0.65 0.12 144.31)", + "destructive": "oklch(0.62 0.22 26.72)", + "destructive-foreground": "oklch(0.95 0.02 80.72)", + "border": "oklch(0.22 0.02 74.64)", + "input": "oklch(0.22 0.02 74.64)", + "ring": "oklch(0.58 0.15 144.17)", + "chart-1": "oklch(0.72 0.16 144.21)", + "chart-2": "oklch(0.63 0.14 144.18)", + "chart-3": "oklch(0.58 0.15 144.17)", + "chart-4": "oklch(0.48 0.12 144.31)", + "chart-5": "oklch(0.35 0.08 145.73)", + "sidebar": "oklch(0.15 0.01 74.42)", + "sidebar-foreground": "oklch(0.95 0.02 80.72)", + "sidebar-primary": "oklch(0.58 0.15 144.17)", + "sidebar-primary-foreground": "oklch(0.09 0.01 80.72)", + "sidebar-accent": "oklch(0.22 0.04 146.04)", + "sidebar-accent-foreground": "oklch(0.65 0.12 144.31)", + "sidebar-border": "oklch(0.22 0.02 74.64)", + "sidebar-ring": "oklch(0.58 0.15 144.17)", + "radius": "0.5rem" + } + }, + "files": [ + { + "path": "src/app/globals.css", + "type": "registry:style", + "target": "app/globals.css" + }, + { + "path": "src/app/colors.css", + "type": "registry:style", + "target": "app/colors.css" + }, + { + "path": "src/app/shadows.css", + "type": "registry:style", + "target": "app/shadows.css" + }, + { + "path": "src/app/borderRadius.css", + "type": "registry:style", + "target": "app/borderRadius.css" + }, + { + "path": "src/app/typography.css", + "type": "registry:style", + "target": "app/typography.css" + }, + { + "path": "src/app/breakpoints.css", + "type": "registry:style", + "target": "app/breakpoints.css" + }, + { + "path": "postcss.config.mjs", + "type": "registry:file", + "target": "postcss.config.mjs" + } + ] + }, + { + "name": "blok-components", + "type": "registry:component", + "title": "All Components", + "description": "This installs all components from the Blokcn registry", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/accordion.json", + "https://blok-shadcn.vercel.app/r/alert-dialog.json", + "https://blok-shadcn.vercel.app/r/alert.json", + "https://blok-shadcn.vercel.app/r/aspect-ratio.json", + "https://blok-shadcn.vercel.app/r/avatar.json", + "https://blok-shadcn.vercel.app/r/badge.json", + "https://blok-shadcn.vercel.app/r/breadcrumb.json", + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/calendar.json", + "https://blok-shadcn.vercel.app/r/card.json", + "https://blok-shadcn.vercel.app/r/carousel.json", + "https://blok-shadcn.vercel.app/r/chart.json", + "https://blok-shadcn.vercel.app/r/checkbox.json", + "https://blok-shadcn.vercel.app/r/collapsible.json", + "https://blok-shadcn.vercel.app/r/combobox.json", + "https://blok-shadcn.vercel.app/r/command.json", + "https://blok-shadcn.vercel.app/r/context-menu.json", + "https://blok-shadcn.vercel.app/r/date-picker.json", + "https://blok-shadcn.vercel.app/r/dialog.json", + "https://blok-shadcn.vercel.app/r/drawer.json", + "https://blok-shadcn.vercel.app/r/dropdown-menu.json", + "https://blok-shadcn.vercel.app/r/hover-card.json", + "https://blok-shadcn.vercel.app/r/input.json", + "https://blok-shadcn.vercel.app/r/inputOtp.json", + "https://blok-shadcn.vercel.app/r/label.json", + "https://blok-shadcn.vercel.app/r/navigation-menu.json", + "https://blok-shadcn.vercel.app/r/pagination.json", + "https://blok-shadcn.vercel.app/r/popover.json", + "https://blok-shadcn.vercel.app/r/progress.json", + "https://blok-shadcn.vercel.app/r/radio-group.json", + "https://blok-shadcn.vercel.app/r/resizable.json", + "https://blok-shadcn.vercel.app/r/scroll-area.json", + "https://blok-shadcn.vercel.app/r/select.json", + "https://blok-shadcn.vercel.app/r/separator.json", + "https://blok-shadcn.vercel.app/r/sheet.json", + "https://blok-shadcn.vercel.app/r/skeleton.json", + "https://blok-shadcn.vercel.app/r/switch.json", + "https://blok-shadcn.vercel.app/r/table.json", + "https://blok-shadcn.vercel.app/r/tabs.json", + "https://blok-shadcn.vercel.app/r/textarea.json", + "https://blok-shadcn.vercel.app/r/toggle.json", + "https://blok-shadcn.vercel.app/r/toggle-group.json", + "https://blok-shadcn.vercel.app/r/tooltip.json", + "https://blok-shadcn.vercel.app/r/input.json" + ] + }, + { + "name": "blank", + "type": "registry:block", + "title": "Blank", + "description": "A blank application with all brand components and code", + "registryDependencies": [ + "https://registry-starter.vercel.app/r/brand-header.json", + "https://registry-starter.vercel.app/r/brand-sidebar.json", + "https://registry-starter.vercel.app/r/product-grid.json", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "dashboard", + "type": "registry:block", + "title": "Dashboard", + "description": "A dashboard application with your brand themed components", + "registryDependencies": [ + "https://registry-starter.vercel.app/r/sonner.json", + "https://registry-starter.vercel.app/r/brand-header.json", + "https://registry-starter.vercel.app/r/brand-sidebar.json", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/layouts/shell-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/dashboard-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "store", + "type": "registry:block", + "title": "Store", + "description": "A store application with your brand themed components", + "registryDependencies": [ + "https://registry-starter.vercel.app/r/product-grid.json", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/store-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "brand-header", + "type": "registry:component", + "title": "Brand Header", + "description": "A styled, simple, reusable header", + "registryDependencies": [ + "button", + "input", + "avatar", + "sidebar", + "https://registry-starter.vercel.app/r/sonner.json", + "https://registry-starter.vercel.app/r/logo.json", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/brand-header.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/shell-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "brand-sidebar", + "type": "registry:component", + "title": "Brand Sidebar", + "description": "A styled, simple, reusable sidebar", + "registryDependencies": [ + "badge", + "button", + "sidebar", + "https://registry-starter.vercel.app/r/sonner.json", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/brand-sidebar.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/shell-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "login", + "type": "registry:component", + "title": "Login", + "description": "Username & password login section with customer quote.", + "registryDependencies": [ + "badge", + "button", + "https://registry-starter.vercel.app/r/theme.json", + "https://registry-starter.vercel.app/r/logo.json" + ], + "files": [ + { + "path": "src/components/login.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "logo", + "type": "registry:component", + "title": "Brand Logo", + "description": "A styled, simple, reusable logo", + "registryDependencies": [ + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/logo.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "hero", + "type": "registry:component", + "title": "Hero", + "description": "Attention-grabbing section for the top of your landing pages.", + "registryDependencies": [ + "badge", + "button", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/hero.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "promo", + "type": "registry:component", + "title": "Promo", + "description": "Attention-grabbing section to display the current promotional deal.", + "registryDependencies": [ + "button", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/promo.tsx", + "type": "registry:component" + }, + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + }, + { + "path": "src/app/demo/[name]/blocks/blank-page.tsx", + "type": "registry:page", + "target": "app/page.tsx" + } + ] + }, + { + "name": "product-grid", + "type": "registry:component", + "title": "Product Grid", + "description": "Product grid displaying all products with API to fetch data", + "registryDependencies": [ + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/product-grid.tsx", + "type": "registry:component" + }, + { + "path": "src/lib/products.ts", + "type": "registry:lib" + }, + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + } + ] + }, + { + "name": "accordion", + "type": "registry:ui", + "title": "Accordion", + "description": "A vertically stacked set of interactive headings that each reveal a section of content.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-accordion", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/accordion.tsx", + "type": "registry:ui", + "target": "src/components/ui/accordion.tsx" + } + ] + }, + { + "name": "alert-dialog", + "type": "registry:ui", + "title": "Alert Dialog", + "description": "A modal dialog that interrupts the user with important content and expects a response.", + "dependencies": [ + "@radix-ui/react-alert-dialog", + "class-variance-authority" + ], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/button.json" + ], + "files": [ + { + "path": "src/components/ui/alert-dialog.tsx", + "type": "registry:ui", + "target": "src/components/ui/alert-dialog.tsx" + } + ] + }, + { + "name": "alert", + "type": "registry:ui", + "title": "Alert", + "description": "Displays Alert Variants.", + "dependencies": ["@mdi/react", "@mdi/js", "class-variance-authority"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/alert.tsx", + "type": "registry:ui", + "target": "src/components/ui/alert.tsx" + } + ] + }, + { + "name": "aspect-ratio", + "type": "registry:ui", + "title": "Aspect Ratio", + "description": "Displays content within a desired ratio.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-aspect-ratio"], + "files": [ + { + "path": "src/components/ui/aspect-ratio.tsx", + "type": "registry:ui", + "target": "src/components/ui/aspect-ratio.tsx" + } + ] + }, + { + "name": "avatar", + "type": "registry:ui", + "title": "Avatar", + "description": "An image element with a fallback for representing the user.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-avatar"], + "files": [ + { + "path": "src/components/ui/avatar.tsx", + "type": "registry:ui", + "target": "src/components/ui/avatar.tsx" + } + ] + }, + { + "name": "badge", + "type": "registry:ui", + "title": "Badge", + "description": "Displays a small count or status indicator.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-slot", "class-variance-authority"], + "files": [ + { + "path": "src/components/ui/badge.tsx", + "type": "registry:ui", + "target": "src/components/ui/badge.tsx" + } + ] + }, + { + "name": "breadcrumb", + "type": "registry:ui", + "title": "Breadcrumb", + "description": "Displays the path to the current resource using a hierarchy of links.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-slot", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/breadcrumb.tsx", + "type": "registry:ui", + "target": "src/components/ui/breadcrumb.tsx" + } + ] + }, + { + "name": "button", + "type": "registry:ui", + "title": "Button", + "description": "Allows users to take actions with a single click or tap.", + "dependencies": ["@radix-ui/react-slot", "class-variance-authority"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/button.tsx", + "type": "registry:ui", + "target": "src/components/ui/button.tsx" + } + ] + }, + { + "name": "calendar", + "type": "registry:ui", + "title": "Calendar", + "description": "A date field component that allows users to enter and edit date.", + "dependencies": ["react-day-picker", "@mdi/react", "@mdi/js"], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/button.json" + ], + "files": [ + { + "path": "src/components/ui/calendar.tsx", + "type": "registry:ui", + "target": "src/components/ui/calendar.tsx" + } + ] + }, + { + "name": "card", + "type": "registry:ui", + "title": "Card", + "description": "Containers for displaying content and actions about a single subject.", + "dependencies": ["class-variance-authority"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/card.tsx", + "type": "registry:ui", + "target": "src/components/ui/card.tsx" + } + ] + }, + { + "name": "carousel", + "type": "registry:ui", + "title": "Carousel", + "description": "A carousel component for displaying a series of items in a sliding manner.", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/theme.json" + ], + "dependencies": ["embla-carousel-react", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/carousel.tsx", + "type": "registry:ui", + "target": "src/components/ui/carousel.tsx" + } + ] + }, + { + "name": "chart", + "type": "registry:ui", + "title": "Chart", + "description": "Beautiful charts. Built using Recharts. Copy and paste into your apps.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["recharts@2.15.4"], + "files": [ + { + "path": "src/components/ui/chart.tsx", + "type": "registry:file", + "target": "src/components/ui/chart.tsx" + } + ] + }, + { + "name": "checkbox", + "type": "registry:ui", + "title": "Checkbox", + "description": "Allows users to select multiple items from a list of options.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-checkbox", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/checkbox.tsx", + "type": "registry:ui", + "target": "src/components/ui/checkbox.tsx" + } + ] + }, + { + "name": "collapsible", + "type": "registry:ui", + "title": "Collapsible", + "description": "An interactive component which expands/collapses a panel.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-collapsible"], + "files": [ + { + "path": "src/components/ui/collapsible.tsx", + "type": "registry:ui", + "target": "src/components/ui/collapsible.tsx" + } + ] + }, + { + "name": "combobox", + "type": "registry:ui", + "title": "Combobox", + "description": "Autocomplete input and command palette with a list of suggestions.", + "dependencies": ["@mdi/js", "@mdi/react", "lucide-react"], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/avatar.json", + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/command.json", + "https://blok-shadcn.vercel.app/r/popover.json" + ], + "files": [ + { + "path": "src/components/ui/combobox.tsx", + "type": "registry:ui", + "target": "src/components/ui/combobox.tsx" + } + ] + }, + { + "name": "command", + "type": "registry:ui", + "title": "Command", + "description": "Fast, composable, unstyled command menu for React.", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/dialog.json" + ], + "dependencies": ["cmdk", "@mdi/js", "@mdi/react"], + "files": [ + { + "path": "src/components/ui/command.tsx", + "type": "registry:ui", + "target": "src/components/ui/command.tsx" + } + ] + }, + { + "name": "context-menu", + "type": "registry:ui", + "title": "Context Menu", + "description": "Displays a menu to the user — such as a set of actions or functions — triggered by a button.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-context-menu", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/context-menu.tsx", + "type": "registry:ui", + "target": "src/components/ui/context-menu.tsx" + } + ] + }, + { + "name": "data-table", + "type": "registry:ui", + "title": "Data Table", + "description": "Powerful table and datagrids built using TanStack Table.", + "registryDependencies": [ + "data-table", + "https://registry-starter.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/layouts/minimal-layout.tsx", + "type": "registry:file", + "target": "app/layout.tsx" + } + ] + }, + { + "name": "date-picker", + "type": "registry:ui", + "title": "Date Picker", + "description": "Displays the path to the current resource using a hierarchy of links.", + "dependencies": ["date-fns", "@mdi/js", "@mdi/react", "react-day-picker"], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/calendar.json", + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/popover.json" + ], + "files": [ + { + "path": "src/components/ui/date-picker.tsx", + "type": "registry:ui", + "target": "src/components/ui/date-picker.tsx" + } + ] + }, + { + "name": "dialog", + "type": "registry:ui", + "title": "Dialog", + "description": "A modal dialog that interrupts the user with important content.", + "dependencies": ["@mdi/js", "@mdi/react", "@radix-ui/react-dialog"], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/button.json" + ], + "files": [ + { + "path": "src/components/ui/dialog.tsx", + "type": "registry:ui", + "target": "src/components/ui/dialog.tsx" + } + ] + }, + { + "name": "drawer", + "type": "registry:ui", + "title": "Drawer", + "description": "A modal dialog that interrupts the user with important content.", + "dependencies": ["vaul"], + "registryDependencies": [ + "http://blok-shadcn.vercel.app/r/button.json", + "http://blok-shadcn.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/ui/drawer.tsx", + "type": "registry:ui", + "target": "src/components/ui/drawer.tsx" + } + ] + }, + { + "name": "dropdown-menu", + "type": "registry:ui", + "title": "Dropdown", + "description": "Displays a menu to the user triggered by a button.", + "dependencies": [ + "@mdi/react", + "@mdi/js", + "@radix-ui/react-dropdown-menu" + ], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/dropdown-menu.tsx", + "type": "registry:ui", + "target": "src/components/ui/dropdown-menu.tsx" + } + ] + }, + { + "name": "form", + "type": "registry:ui", + "title": "Form", + "description": "A form component for user input.", + "registryDependencies": [ + "http://blok-shadcn.vercel.app/r/input.json", + "http://blok-shadcn.vercel.app/r/button.json", + "http://blok-shadcn.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/ui/tanstack-form.tsx", + "type": "registry:ui", + "target": "src/components/ui/tanstack-form.tsx" + }, + { + "path": "src/components/ui/form.tsx", + "type": "registry:ui", + "target": "src/components/ui/form.tsx" + } + ] + }, + { + "name": "input", + "type": "registry:ui", + "title": "Input", + "description": "Displays a form input field or a component that looks like an input field.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/input.tsx", + "type": "registry:ui", + "target": "src/components/ui/input.tsx" + } + ] + }, + { + "name": "inputOtp", + "type": "registry:ui", + "title": "Input OTP", + "description": "A one-time password input component for verification codes.", + "dependencies": ["@mdi/js", "@mdi/react", "input-otp"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/inputOtp.tsx", + "type": "registry:ui", + "target": "src/components/ui/inputOtp.tsx" + } + ] + }, + { + "name": "label", + "type": "registry:ui", + "title": "Label", + "description": "Renders an accessible label associated with controls.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-label"], + "files": [ + { + "path": "src/components/ui/label.tsx", + "type": "registry:ui", + "target": "src/components/ui/label.tsx" + } + ] + }, + { + "name": "navigation-menu", + "type": "registry:ui", + "title": "Navigation Menu", + "description": "A collection of links for navigating websites.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": [ + "@mdi/react", + "@mdi/js", + "@radix-ui/react-navigation-menu", + "class-variance-authority" + ], + "files": [ + { + "path": "src/components/ui/navigation-menu.tsx", + "type": "registry:ui", + "target": "src/components/ui/navigation-menu.tsx" + } + ] + }, + { + "name": "pagination", + "type": "registry:ui", + "title": "Pagination", + "description": "Pagination with page navigation, next and previous links.", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/button.json" + ], + "dependencies": ["@radix-ui/react-popover", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/pagination.tsx", + "type": "registry:ui", + "target": "src/components/ui/pagination.tsx" + } + ] + }, + { + "name": "progress", + "type": "registry:ui", + "title": "Progress", + "description": "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-progress"], + "files": [ + { + "path": "src/components/ui/progress.tsx", + "type": "registry:ui", + "target": "src/components/ui/progress.tsx" + } + ] + }, + { + "name": "radio-group", + "type": "registry:ui", + "title": "Radio Group", + "description": "A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-radio-group", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/radio-group.tsx", + "type": "registry:ui", + "target": "src/components/ui/radio-group.tsx" + } + ] + }, + { + "name": "resizable", + "type": "registry:ui", + "title": "Resizable", + "description": "Accessible resizable panel groups and layouts with keyboard support.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["react-resizable-panels", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/resizable.tsx", + "type": "registry:ui", + "target": "src/components/ui/resizable.tsx" + } + ] + }, + { + "name": "scroll-area", + "type": "registry:ui", + "title": "Scroll Area", + "description": "Augments native scroll functionality for custom, cross-browser styling.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-scroll-area"], + "files": [ + { + "path": "src/components/ui/scroll-area.tsx", + "type": "registry:ui", + "target": "src/components/ui/scroll-area.tsx" + } + ] + }, + { + "name": "select", + "type": "registry:ui", + "title": "Select", + "description": "Displays a list of options for the user to pick from—triggered by a button.", + "dependencies": ["@radix-ui/react-select", "@mdi/react", "@mdi/js"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/select.tsx", + "type": "registry:ui" + } + ] + }, + { + "name": "separator", + "type": "registry:ui", + "title": "Separator", + "description": "Visually or semantically separates content.", + "dependencies": ["@radix-ui/react-separator"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/separator.tsx", + "type": "registry:ui", + "target": "src/components/ui/separator.tsx" + } + ] + }, + { + "name": "sheet", + "type": "registry:ui", + "title": "Sheet", + "description": "Visually or semantically separates content.", + "dependencies": ["@radix-ui/react-dialog", "@mdi/react", "@mdi/js"], + "registryDependencies": [ + "http://blok-shadcn.vercel.app/r/button.json", + "http://blok-shadcn.vercel.app/r/theme.json" + ], + "files": [ + { + "path": "src/components/ui/sheet.tsx", + "type": "registry:ui", + "target": "src/components/ui/sheet.tsx" + } + ] + }, + { + "name": "sidebar", + "type": "registry:ui", + "title": "Sidebar", + "description": "A styled, simple, reusable sidebar", + "dependencies": [ + "@mdi/react", + "@mdi/js", + "class-variance-authority", + "@radix-ui/react-slot" + ], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/tooltip.json", + "https://blok-shadcn.vercel.app/r/skeleton.json", + "https://blok-shadcn.vercel.app/r/separator.json", + "https://blok-shadcn.vercel.app/r/input.json", + "https://blok-shadcn.vercel.app/r/button.json" + ], + "files": [ + { + "path": "src/components/ui/sidebar.tsx", + "type": "registry:ui", + "target": "src/components/ui/sidebar.tsx" + } + ] + }, + { + "name": "skeleton", + "type": "registry:ui", + "title": "Skeleton", + "description": "Use to show a placeholder while content is loading.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/skeleton.tsx", + "type": "registry:ui", + "target": "src/components/ui/skeleton.tsx" + } + ] + }, + { + "name": "slider", + "type": "registry:ui", + "title": "Slider", + "description": "An input where the user selects a value from within a given range.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-slider"], + "files": [ + { + "path": "src/components/ui/slider.tsx", + "type": "registry:ui", + "target": "src/components/ui/slider.tsx" + } + ] + }, + { + "name": "sonner", + "type": "registry:ui", + "title": "Sonner", + "description": "An opinionated toast component for React.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["sonner", "next-themes", "@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/sonner.tsx", + "type": "registry:ui", + "target": "src/components/ui/sonner.tsx" + } + ] + }, + { + "name": "spinner", + "type": "registry:ui", + "title": "Spinner", + "description": "An opinionated toast component for React.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/spinner.tsx", + "type": "registry:ui", + "target": "src/components/ui/spinner.tsx" + } + ] + }, + { + "name": "switch", + "type": "registry:ui", + "title": "Switch", + "description": "A control that allows the user to toggle between checked and not checked.", + "dependencies": ["@radix-ui/react-switch", "class-variance-authority"], + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/label.json" + ], + "files": [ + { + "path": "src/components/ui/switch.tsx", + "type": "registry:ui", + "target": "src/components/ui/switch.tsx" + } + ] + }, + { + "name": "table", + "type": "registry:ui", + "title": "Table", + "description": "A responsive table component.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/table.tsx", + "type": "registry:ui", + "target": "src/components/ui/table.tsx" + } + ] + }, + { + "name": "tabs", + "type": "registry:ui", + "title": "Tabs", + "description": "A set of layered sections of content known as tab panels that are displayed one at a time.", + "dependencies": ["@radix-ui/react-tabs", "class-variance-authority"], + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/tabs.tsx", + "type": "registry:ui", + "target": "src/components/ui/tabs.tsx" + } + ] + }, + { + "name": "textarea", + "type": "registry:ui", + "title": "Textarea", + "description": "A textarea component for multi-line text input with various states and configurations.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "files": [ + { + "path": "src/components/ui/textarea.tsx", + "type": "registry:ui" + } + ] + }, + { + "name": "toggle-group", + "type": "registry:ui", + "title": "Toggle Group", + "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/toggle.json" + ], + "dependencies": [ + "@radix-ui/react-toggle-group", + "@mdi/react", + "@mdi/js", + "class-variance-authority" + ], + "files": [ + { + "path": "src/components/ui/toggle-group.tsx", + "type": "registry:ui" + } + ] + }, + { + "name": "tooltip", + "type": "registry:ui", + "title": "Tooltip", + "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-tooltip"], + "files": [ + { + "path": "src/components/ui/tooltip.tsx", + "type": "registry:ui", + "target": "src/components/ui/tooltip.tsx" + } + ] + }, + { + "name": "toggle", + "type": "registry:ui", + "title": "Toggle", + "description": "A two-state button that can be either on or off.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": [ + "@radix-ui/react-toggle", + "@mdi/react", + "@mdi/js", + "class-variance-authority" + ], + "files": [ + { + "path": "src/components/ui/toggle.tsx", + "type": "registry:ui" + } + ] + }, + { + "name": "topbar", + "type": "registry:ui", + "title": "Topbar", + "description": "A topbar application with your brand themed components", + "registryDependencies": [ + "https://blok-shadcn.vercel.app/r/theme.json", + "https://blok-shadcn.vercel.app/r/avatar.json", + "https://blok-shadcn.vercel.app/r/button.json", + "https://blok-shadcn.vercel.app/r/navigation-menu.json" + ], + "dependencies": ["@mdi/react", "@mdi/js"], + "files": [ + { + "path": "src/components/ui/top-bar.tsx", + "type": "registry:ui", + "target": "src/components/ui/top-bar.tsx" + } + ] + }, + { + "name": "popover", + "type": "registry:ui", + "title": "Popover", + "description": "Displays rich content in a portal, triggered by a button.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-popover"], + "files": [ + { + "path": "src/components/ui/popover.tsx", + "type": "registry:ui" + } + ] + }, + { + "name": "hover-card", + "type": "registry:ui", + "title": "Hover Card", + "description": "For sighted users to preview content available behind a link.", + "registryDependencies": ["https://blok-shadcn.vercel.app/r/theme.json"], + "dependencies": ["@radix-ui/react-hover-card"], + "files": [ + { + "path": "src/components/ui/hover-card.tsx", + "type": "registry:ui", + "target": "src/components/ui/hover-card.tsx" + } + ] + } + ] +} diff --git a/registry.json b/registry.json deleted file mode 100644 index f7d9e553..00000000 --- a/registry.json +++ /dev/null @@ -1,804 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema/registry.json", - "name": "Registry Starter", - "homepage": "https://registry-starter.vercel.app", - "items": [ - { - "name": "theme", - "type": "registry:theme", - "title": "Nature Theme", - "description": "A nature theme and styles with greens and browns using Tailwind and shadcn/ui variable names", - "cssVars": { - "light": { - "background": "oklch(0.97 0.01 80.72)", - "foreground": "oklch(0.3 0.04 30.2)", - "card": "oklch(0.97 0.01 80.72)", - "card-foreground": "oklch(0.3 0.04 30.2)", - "popover": "oklch(0.97 0.01 80.72)", - "popover-foreground": "oklch(0.3 0.04 30.2)", - "primary": "oklch(0.52 0.13 144.17)", - "primary-foreground": "oklch(1.0 0 0)", - "secondary": "oklch(0.96 0.02 147.64)", - "secondary-foreground": "oklch(0.43 0.12 144.31)", - "muted": "oklch(0.94 0.01 74.42)", - "muted-foreground": "oklch(0.45 0.05 39.21)", - "accent": "oklch(0.9 0.05 146.04)", - "accent-foreground": "oklch(0.43 0.12 144.31)", - "destructive": "oklch(0.54 0.19 26.72)", - "destructive-foreground": "oklch(1.0 0 0)", - "border": "oklch(0.88 0.02 74.64)", - "input": "oklch(0.88 0.02 74.64)", - "ring": "oklch(0.52 0.13 144.17)", - "chart-1": "oklch(0.67 0.16 144.21)", - "chart-2": "oklch(0.58 0.14 144.18)", - "chart-3": "oklch(0.52 0.13 144.17)", - "chart-4": "oklch(0.43 0.12 144.31)", - "chart-5": "oklch(0.22 0.05 145.73)", - "sidebar": "oklch(0.94 0.01 74.42)", - "sidebar-foreground": "oklch(0.3 0.04 30.2)", - "sidebar-primary": "oklch(0.52 0.13 144.17)", - "sidebar-primary-foreground": "oklch(1.0 0 0)", - "sidebar-accent": "oklch(0.9 0.05 146.04)", - "sidebar-accent-foreground": "oklch(0.43 0.12 144.31)", - "sidebar-border": "oklch(0.88 0.02 74.64)", - "sidebar-ring": "oklch(0.52 0.13 144.17)", - "radius": "0.5rem" - }, - "dark": { - "background": "oklch(0.15 0.01 74.42)", - "foreground": "oklch(0.95 0.02 80.72)", - "card": "oklch(0.12 0.01 80.72)", - "card-foreground": "oklch(0.95 0.02 80.72)", - "popover": "oklch(0.12 0.01 80.72)", - "popover-foreground": "oklch(0.95 0.02 80.72)", - "primary": "oklch(0.58 0.15 144.17)", - "primary-foreground": "oklch(0.09 0.01 80.72)", - "secondary": "oklch(0.15 0.02 147.64)", - "secondary-foreground": "oklch(0.65 0.12 144.31)", - "muted": "oklch(0.18 0.01 74.42)", - "muted-foreground": "oklch(0.65 0.03 74.42)", - "accent": "oklch(0.22 0.04 146.04)", - "accent-foreground": "oklch(0.65 0.12 144.31)", - "destructive": "oklch(0.62 0.22 26.72)", - "destructive-foreground": "oklch(0.95 0.02 80.72)", - "border": "oklch(0.22 0.02 74.64)", - "input": "oklch(0.22 0.02 74.64)", - "ring": "oklch(0.58 0.15 144.17)", - "chart-1": "oklch(0.72 0.16 144.21)", - "chart-2": "oklch(0.63 0.14 144.18)", - "chart-3": "oklch(0.58 0.15 144.17)", - "chart-4": "oklch(0.48 0.12 144.31)", - "chart-5": "oklch(0.35 0.08 145.73)", - "sidebar": "oklch(0.15 0.01 74.42)", - "sidebar-foreground": "oklch(0.95 0.02 80.72)", - "sidebar-primary": "oklch(0.58 0.15 144.17)", - "sidebar-primary-foreground": "oklch(0.09 0.01 80.72)", - "sidebar-accent": "oklch(0.22 0.04 146.04)", - "sidebar-accent-foreground": "oklch(0.65 0.12 144.31)", - "sidebar-border": "oklch(0.22 0.02 74.64)", - "sidebar-ring": "oklch(0.58 0.15 144.17)", - "radius": "0.5rem" - } - }, - "files": [ - { - "path": "src/app/globals.css", - "type": "registry:style", - "target": "app/globals.css" - }, - { - "path": "postcss.config.mjs", - "type": "registry:file", - "target": "postcss.config.mjs" - } - ] - }, - { - "name": "blank", - "type": "registry:block", - "title": "Blank", - "description": "A blank application with all brand components and code", - "registryDependencies": [ - "https://registry-starter.vercel.app/r/brand-header.json", - "https://registry-starter.vercel.app/r/brand-sidebar.json", - "https://registry-starter.vercel.app/r/product-grid.json", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "dashboard", - "type": "registry:block", - "title": "Dashboard", - "description": "A dashboard application with your brand themed components", - "registryDependencies": [ - "https://registry-starter.vercel.app/r/sonner.json", - "https://registry-starter.vercel.app/r/brand-header.json", - "https://registry-starter.vercel.app/r/brand-sidebar.json", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/shell-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/dashboard-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "store", - "type": "registry:block", - "title": "Store", - "description": "A store application with your brand themed components", - "registryDependencies": [ - "https://registry-starter.vercel.app/r/product-grid.json", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/store-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "brand-header", - "type": "registry:component", - "title": "Brand Header", - "description": "A styled, simple, reusable header", - "registryDependencies": [ - "button", - "input", - "avatar", - "sidebar", - "https://registry-starter.vercel.app/r/sonner.json", - "https://registry-starter.vercel.app/r/logo.json", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/brand-header.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/shell-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "brand-sidebar", - "type": "registry:component", - "title": "Brand Sidebar", - "description": "A styled, simple, reusable sidebar", - "registryDependencies": [ - "badge", - "button", - "sidebar", - "https://registry-starter.vercel.app/r/sonner.json", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/brand-sidebar.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/shell-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "login", - "type": "registry:component", - "title": "Login", - "description": "Username & password login section with customer quote.", - "registryDependencies": [ - "badge", - "button", - "https://registry-starter.vercel.app/r/theme.json", - "https://registry-starter.vercel.app/r/logo.json" - ], - "files": [ - { - "path": "src/components/login.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "logo", - "type": "registry:component", - "title": "Brand Logo", - "description": "A styled, simple, reusable logo", - "registryDependencies": [ - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/logo.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "hero", - "type": "registry:component", - "title": "Hero", - "description": "Attention-grabbing section for the top of your landing pages.", - "registryDependencies": [ - "badge", - "button", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/hero.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "promo", - "type": "registry:component", - "title": "Promo", - "description": "Attention-grabbing section to display the current promotional deal.", - "registryDependencies": [ - "button", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/promo.tsx", - "type": "registry:component" - }, - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/app/demo/[name]/blocks/blank-page.tsx", - "type": "registry:page", - "target": "app/page.tsx" - } - ] - }, - { - "name": "product-grid", - "type": "registry:component", - "title": "Product Grid", - "description": "Product grid displaying all products with API to fetch data", - "registryDependencies": [ - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/components/product-grid.tsx", - "type": "registry:component" - }, - { - "path": "src/lib/products.ts", - "type": "registry:lib" - }, - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "accordion", - "type": "registry:ui", - "title": "Accordion", - "description": "A vertically stacked set of interactive headings that each reveal a section of content.", - "registryDependencies": [ - "accordion", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "alert", - "type": "registry:ui", - "title": "Alert", - "description": "Displays a callout for user attention.", - "registryDependencies": [ - "alert", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "avatar", - "type": "registry:ui", - "title": "Avatar", - "description": "An image element with a fallback for representing the user.", - "registryDependencies": [ - "avatar", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "badge", - "type": "registry:ui", - "title": "Badge", - "description": "Displays a small count or status indicator.", - "registryDependencies": [ - "badge", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "breadcrumb", - "type": "registry:ui", - "title": "Breadcrumb", - "description": "Displays the path to the current resource using a hierarchy of links.", - "registryDependencies": [ - "breadcrumb", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "button", - "type": "registry:ui", - "title": "Button", - "description": "Allows users to take actions with a single click or tap.", - "registryDependencies": [ - "button", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "calendar", - "type": "registry:ui", - "title": "Calendar", - "description": "A date field component that allows users to enter and edit date.", - "registryDependencies": [ - "calendar", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "card", - "type": "registry:ui", - "title": "Card", - "description": "Containers for displaying content and actions about a single subject.", - "registryDependencies": [ - "card", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "chart", - "type": "registry:ui", - "title": "Chart", - "description": "Beautiful charts. Built using Recharts. Copy and paste into your apps.", - "registryDependencies": [ - "chart", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "checkbox", - "type": "registry:ui", - "title": "Checkbox", - "description": "Allows users to select multiple items from a list of options.", - "registryDependencies": [ - "checkbox", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "data-table", - "type": "registry:ui", - "title": "Data Table", - "description": "Powerful table and datagrids built using TanStack Table.", - "registryDependencies": [ - "data-table", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "date-picker", - "type": "registry:ui", - "title": "Date Picker", - "description": "Displays the path to the current resource using a hierarchy of links.", - "registryDependencies": [ - "date-picker", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "dialog", - "type": "registry:ui", - "title": "Dialog", - "description": "A modal dialog that interrupts the user with important content.", - "registryDependencies": [ - "dialog", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "dropdown-menu", - "type": "registry:ui", - "title": "Dropdown", - "description": "Displays a menu to the user triggered by a button.", - "registryDependencies": [ - "dropdown-menu", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "input", - "type": "registry:ui", - "title": "Input", - "description": "Displays a form input field or a component that looks like an input field.", - "registryDependencies": [ - "input", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "menu-bar", - "type": "registry:ui", - "title": "Menu Bar", - "description": "A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.", - "registryDependencies": [ - "menu-bar", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "select", - "type": "registry:ui", - "title": "Select", - "description": "Displays a list of options for the user to pick from—triggered by a button.", - "registryDependencies": [ - "select", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "separator", - "type": "registry:ui", - "title": "Separator", - "description": "Visually or semantically separates content.", - "registryDependencies": [ - "separator", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "skeleton", - "type": "registry:ui", - "title": "Skeleton", - "description": "Use to show a placeholder while content is loading.", - "registryDependencies": [ - "skeleton", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "slider", - "type": "registry:ui", - "title": "Slider", - "description": "An input where the user selects a value from within a given range.", - "registryDependencies": [ - "slider", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "sonner", - "type": "registry:ui", - "title": "Sonner", - "description": "An opinionated toast component for React.", - "registryDependencies": [ - "sonner", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - }, - { - "path": "src/components/ui/sonner.tsx", - "type": "registry:file", - "target": "components/ui/sonner.tsx" - } - ] - }, - { - "name": "switch", - "type": "registry:ui", - "title": "Switch", - "description": "A control that allows the user to toggle between checked and not checked.", - "registryDependencies": [ - "switch", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "table", - "type": "registry:ui", - "title": "Table", - "description": "A responsive table component.", - "registryDependencies": [ - "table", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "tabs", - "type": "registry:ui", - "title": "Tabs", - "description": "A set of layered sections of content—known as tab panels—that are displayed one at a time.", - "registryDependencies": [ - "tabs", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "toggle-group", - "type": "registry:ui", - "title": "Toggle Group", - "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", - "registryDependencies": [ - "toggle-group", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - }, - { - "name": "tooltip", - "type": "registry:ui", - "title": "Tooltip", - "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", - "registryDependencies": [ - "tooltip", - "https://registry-starter.vercel.app/r/theme.json" - ], - "files": [ - { - "path": "src/layouts/minimal-layout.tsx", - "type": "registry:file", - "target": "app/layout.tsx" - } - ] - } - ] -} diff --git a/src/app/(registry)/layout.tsx b/src/app/(registry)/layout.tsx index a7479d56..5446f24d 100644 --- a/src/app/(registry)/layout.tsx +++ b/src/app/(registry)/layout.tsx @@ -1,4 +1,4 @@ -import { SidebarProvider } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/registry/docsite-sidebar"; import type { ReactNode } from "react"; import { @@ -16,7 +16,7 @@ export default function RegistryLayout({ -
{children}
+
{children}
); diff --git a/src/app/(registry)/page.tsx b/src/app/(registry)/page.tsx index 452ad872..1dca257d 100644 --- a/src/app/(registry)/page.tsx +++ b/src/app/(registry)/page.tsx @@ -1,197 +1,93 @@ -import { ArrowRight, Blocks, Component, ToyBrick } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Codeblocks } from "@/components/registry/code-block"; import Link from "next/link"; - import { MCPTabs } from "@/components/registry/mcp-tabs"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { getBlocks, getComponents, getUIPrimitives } from "@/lib/registry"; -const uiItems = getUIPrimitives().slice(0, 5); -const componentItems = getComponents().slice(0, 5); -const blockItems = getBlocks().slice(0, 5); +const InstallationCode = `npx shadcn@latest add https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}/r/blok-components.json `; + +const sampleButtonCode = `import { Button } from "@/components/ui/button" +export function ButtonDemo() { + return ( +
+ +
+ ) +}`; export default function Home() { return ( -
-
-
-

- Registry +
+
+
+

+ Build better products faster

-

- Distribute your design system tokens, custom components, hooks, - pages, and other files to any React project. +

+ Blok is Sitecore's product design system: the UI framework and style + guide we use to build great apps. It's publicly available, so that + anyone can easily build software in the Sitecore product design + language.

-
-
- - - -
- Blocks -
- -
+
+ {/* + */}
- - Pre-built starter kits for consistent, repeatable generations - - - - -
- {blockItems.map((item) => ( -
- - {item.title} - - -
- ))} -
-
- - -
- - -
- UI Primitives -
- -
-
- - Reusable UI primitives to build your components - -
- - -
- {uiItems.map((item) => ( -
- - {item.title} - - -
- ))} -
-
-
- - - -
- Components -
- -
-
- - Compound components using common patterns - -
- - -
- {componentItems.map((item) => ( -
- - {item.title} - - -
- ))} -
-
-
+
- -
-
-

MCP

-

- Integrate this registry with AI IDEs using Model Context Protocol - (MCP) using the following configuration. This utilizes this - Registry's theme tokens and CSS variables with the Shadcn CLI. To - ensure this works, double check that the{" "} - - - style:theme - - {" "} - contains the same colors as your{" "} - tokens.css +

+
+

+ Add registry +

+

+ Start by adding all Blok components from the registry to your + codebase.

- +
-
- -
-
-

About

-

- This registry serves as a central repository for all UI components - and blocks used in your applications. It helps maintain consistency - across your products and speeds up development by providing - ready-to-use components. Each component and block is documented with - examples. You can browse components by category, search for specific - components, and view examples of how they are used in different - contexts. -

-

- To get begin, select a{" "} - - starter - {" "} - and click the Open in v0 button. - You can also open individual components or blocks in v0 if you want - a smaller or more specific starting point. +

+

+ Add component to page +

+

+ The command above will add the components to your project. You can + then import component onto pages like this.

+

(example used: button):

+ -

- - - - - GitHub Repository - -

+
+

+ MCP +

+

+ Integrate this registry with AI IDEs using Model Context Protocol + (MCP) using the following configuration. This utilizes this + Registry's theme tokens and CSS variables with the Shadcn CLI. To + ensure this works, double check that the{" "} + + + style:theme + + {" "} + contains the same colors as your{" "} + tokens.css +

+ +
+ +
+
diff --git a/src/app/(registry)/tokens/color-block.tsx b/src/app/(registry)/tokens/color-block.tsx deleted file mode 100644 index 38aee41f..00000000 --- a/src/app/(registry)/tokens/color-block.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { cn } from "@/lib/utils"; - -interface SimpleColorBlockProps { - name: string; - className: string; -} - -export function ColorBlock({ name, className }: SimpleColorBlockProps) { - return ( -
-
-
-
{name}
- - --{className.slice(3)} - -
-
- ); -} diff --git a/src/app/(registry)/tokens/component-wrapper.tsx b/src/app/(registry)/tokens/component-wrapper.tsx new file mode 100644 index 00000000..244c7b61 --- /dev/null +++ b/src/app/(registry)/tokens/component-wrapper.tsx @@ -0,0 +1,84 @@ +"use client"; + +import * as React from "react"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@radix-ui/react-accordion"; + +import { cn } from "@/lib/utils"; + +export function ComponentWrapper({ + className, + name, + children, + ...props +}: React.ComponentPropsWithoutRef<"div"> & { name: string }) { + return ( + + +
+ + +
+
+ {getComponentName(name)} +
+
+
+ +
+ {children} +
+
+
+
+
+
+ ); +} + +class ComponentErrorBoundary extends React.Component< + { children: React.ReactNode; name: string }, + { hasError: boolean } +> { + constructor(props: { children: React.ReactNode; name: string }) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error(`Error in component ${this.props.name}:`, error, errorInfo); + } + + render() { + if (this.state.hasError) { + return ( +
+ Something went wrong in component: {this.props.name} +
+ ); + } + + return this.props.children; + } +} + +function getComponentName(name: string) { + // convert kebab-case to title case + return name.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase()); +} diff --git a/src/app/(registry)/tokens/components/border-radius-theme.tsx b/src/app/(registry)/tokens/components/border-radius-theme.tsx new file mode 100644 index 00000000..91545962 --- /dev/null +++ b/src/app/(registry)/tokens/components/border-radius-theme.tsx @@ -0,0 +1,96 @@ +"use client"; + +import { convertCssVariablesToObject } from "@/lib/token-utils"; + +type Props = { + content: string; // The CSS content containing your @theme breakpoints +}; + +const NOTES: Record = { + md: "The most common rounded. Used on many elements, such as inputs, cards, tags, and more.", + lg: "The preferred larger rounded. Used on modals and large panels.", + full: "Used for circular elements, such as avatars and buttons.", +}; + +const BorderroundedDemo = ({ content }: Props) => { + const borderRadiuses = convertCssVariablesToObject(content, "--rounded-"); + + return ( +
+
+ + + + + + + + + + + + {Object.entries(borderRadiuses).map(([key, value]) => { + const pxValue = parseFloat(value) * 16; + + return ( + + + + + + + + ); + })} + +
ExampleToken + Value (rem) + + Value (px) + Notes
+
+
{key} + + {value} + + + + {pxValue}px + + + + {NOTES[key] ?? ""} + +
+
+
+ ); +}; + +export default BorderroundedDemo; diff --git a/src/app/(registry)/tokens/components/breakpoint-theme.tsx b/src/app/(registry)/tokens/components/breakpoint-theme.tsx new file mode 100644 index 00000000..868f42ce --- /dev/null +++ b/src/app/(registry)/tokens/components/breakpoint-theme.tsx @@ -0,0 +1,182 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { convertCssVariablesToObject } from "@/lib/token-utils"; + +type Props = { + content: string; // The CSS content containing your @theme breakpoints +}; + +// Helper function to get the current breakpoint name +const getCurrentBreakpoint = ( + width: number, + breakpoints: { [key: string]: string } +): string | null => { + let activeBreakpoint: string | null = null; + + const pxBreakpoints: { [key: string]: number } = Object.fromEntries( + Object.entries(breakpoints).map(([key, value]) => { + const remValue = parseFloat(value); + return [key, isNaN(remValue) ? 0 : remValue * 16]; + }) + ); + + const sortedBreakpoints = Object.entries(pxBreakpoints) + .filter(([, val]) => typeof val === "number" && val >= 0) + .sort(([, valA], [, valB]) => valA - valB); + + for (const [name, breakpointPx] of sortedBreakpoints) { + if (width >= breakpointPx) { + activeBreakpoint = name; + } else { + break; + } + } + + return activeBreakpoint; +}; + +const BreakpointsDemo = ({ content }: Props) => { + const rawBreakpoints = convertCssVariablesToObject(content, "--breakpoint-"); + + const filteredBreakpoints = Object.fromEntries( + Object.entries(rawBreakpoints).filter(([key]) => key !== "*") + ); + + const [windowWidth, setWindowWidth] = useState(0); + const [currentBreakpointName, setCurrentBreakpointName] = useState< + string | null + >(null); + + // Define a mapping for device names. + // You'll need to update these based on your actual breakpoint names. + const deviceMap: { [key: string]: string } = { + sm: "Small Phone", + md: "Tablet (Portrait)", + lg: "Tablet (Landscape)", + xl: "Desktop", + "2xl": "Large Desktop", + // Add any other custom breakpoints you have + }; + + useEffect(() => { + const handleResize = () => { + const newWidth = window.innerWidth; + setWindowWidth(newWidth); + setCurrentBreakpointName( + getCurrentBreakpoint(newWidth, filteredBreakpoints) + ); + }; + + if (typeof window !== "undefined") { + setWindowWidth(window.innerWidth); + setCurrentBreakpointName( + getCurrentBreakpoint(window.innerWidth, filteredBreakpoints) + ); + window.addEventListener("resize", handleResize); + } + + return () => { + if (typeof window !== "undefined") { + window.removeEventListener("resize", handleResize); + } + }; + }, [filteredBreakpoints]); + + return ( +
+

Window width: {windowWidth}px

+ +
+

Active breakpoint:

+ {Object.entries(filteredBreakpoints).map(([key]) => { + const isActive = currentBreakpointName === key; + + return ( +
+ {key} - {deviceMap[key] || "N/A"} +
+ ); + })} + {currentBreakpointName === null && ( +
(Below smallest breakpoint)
+ )} +
+ +
+ + + + + + + + + + + {Object.entries(filteredBreakpoints).map(([key, value]) => { + // const isActiveRow = currentBreakpointName === key + const pxValue = parseFloat(value) * 16; + + return ( + + + + + + + ); + })} + +
TokenDevice + Value (rem) + + Value (px) +
+ {key} + + {deviceMap[key] || "N/A"} + {/* Display device name, or 'N/A' if not mapped */} + + + {value} + + + + {pxValue}px + +
+
+
+ ); +}; + +export default BreakpointsDemo; diff --git a/src/app/(registry)/tokens/components/colors-theme.tsx b/src/app/(registry)/tokens/components/colors-theme.tsx new file mode 100644 index 00000000..009b2c4b --- /dev/null +++ b/src/app/(registry)/tokens/components/colors-theme.tsx @@ -0,0 +1,57 @@ +import { convertCssVariablesToObject } from "@/lib/token-utils"; + +type Props = { + content: string; +}; + +const ColorsDemo = ({ content }: Props) => { + const colors = convertCssVariablesToObject(content, "--color-"); + + return ( +
+ + + + + + + + + + {Object.entries(colors).map(([key, value]) => ( + + + + + + ))} + +
NameColorValue
{key} +
+
+ + {value} + +
+
+ ); +}; + +export default ColorsDemo; diff --git a/src/app/(registry)/tokens/components/shadow-theme.tsx b/src/app/(registry)/tokens/components/shadow-theme.tsx new file mode 100644 index 00000000..caa67e5e --- /dev/null +++ b/src/app/(registry)/tokens/components/shadow-theme.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { convertCssVariablesToObject } from "@/lib/token-utils"; + +type Props = { + content: string; // The CSS content containing your @theme breakpoints +}; + +const NOTES: Record = { + xs: "Looks like a light 1px border", + base: "Top bar", + lg: "Modal, Drawer", + outline: "Used as focus ring", + "dark-lg": "Only used in dark mode", +}; + +const ShadowDemo = ({ content }: Props) => { + const shadows = convertCssVariablesToObject(content, "--shadow-"); + + return ( +
+ + + + + + + + + + + {Object.entries(shadows).map(([key, value]) => { + return ( + + + + + + + + ); + })} + +
ExampleTokenValueNotes
+
+
{key} + + {value} + + + + {NOTES[key] ?? ""} + +
+
+ ); +}; + +export default ShadowDemo; diff --git a/src/app/(registry)/tokens/components/typography-theme.tsx b/src/app/(registry)/tokens/components/typography-theme.tsx new file mode 100644 index 00000000..986927b3 --- /dev/null +++ b/src/app/(registry)/tokens/components/typography-theme.tsx @@ -0,0 +1,67 @@ +import { convertCssVariablesToObject } from "@/lib/token-utils"; + +type Props = { + content: string; +}; +const TypographyDemo = ({ content }: Props) => { + const typography = convertCssVariablesToObject(content, "--text-"); + + return ( +
+

Font sizes

+ +
+ + + + + + + + + + + {Object.entries(typography).map(([key, value]) => ( + + + + + + + ))} + +
TokenValuePXExample
{key} + + {value} + + + + {parseFloat(value) * 16}px + + +

text-{key}

+
+
+
+ ); +}; + +export default TypographyDemo; diff --git a/src/app/(registry)/tokens/font-block.tsx b/src/app/(registry)/tokens/font-block.tsx deleted file mode 100644 index 761b1d13..00000000 --- a/src/app/(registry)/tokens/font-block.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { cn } from "@/lib/utils"; - -export function FontBlock({ - className, -}: { - className: string; -}) { - return ( -
-
-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. -

- - --{className} - -
-
- ); -} diff --git a/src/app/(registry)/tokens/page.tsx b/src/app/(registry)/tokens/page.tsx index 35c09681..dde6a722 100644 --- a/src/app/(registry)/tokens/page.tsx +++ b/src/app/(registry)/tokens/page.tsx @@ -1,172 +1,68 @@ -"use client"; +import fs from "fs"; +import path from "path"; import { ArrowLeft } from "lucide-react"; +import { Button } from "@/components/ui/button"; import Link from "next/link"; -import type React from "react"; +import BorderRadiusDemo from "./components/border-radius-theme"; +import ColorsDemo from "./components/colors-theme"; +import { ComponentWrapper } from "./component-wrapper"; +import ShadowDemo from "./components/shadow-theme"; +import TypographyDemo from "./components/typography-theme"; +import BreakpointsDemo from "./components/breakpoint-theme"; -import { FontBlock } from "@/app/(registry)/tokens/font-block"; -import { Button } from "@/components/ui/button"; -import { ColorBlock } from "./color-block"; +let cssPath = path.join(process.cwd(), "src", "app", "colors.css"); +const colorsContent = fs.readFileSync(cssPath, "utf-8"); -export default function TokensPage() { - return ( -
-
- +cssPath = path.join(process.cwd(), "src", "app", "typography.css"); +const typographyContent = fs.readFileSync(cssPath, "utf-8"); -

Design Tokens

-

- A comprehensive overview of all color tokens used in the design system -

-
+cssPath = path.join(process.cwd(), "src", "app", "borderRadius.css"); +const borderRadiusContent = fs.readFileSync(cssPath, "utf-8"); - {/* Fonts */} -
-

Fonts

-

- The core font families that define the primary typography. -

-
- - - -
-
+cssPath = path.join(process.cwd(), "src", "app", "shadows.css"); +const shadowsContent = fs.readFileSync(cssPath, "utf-8"); - {/* Primary Theme */} -
-

Primary Theme

-

- The core colors that define the primary theme and overall look of the - interface. -

-
- - - - -
-
- {/* Secondary & Accent */} -
-

Secondary & Accent

-

- Colors used for secondary elements and accents throughout the - interface. -

-
- - - - -
-
+cssPath = path.join(process.cwd(), "src", "app", "breakpoints.css"); +const breakpoints = fs.readFileSync(cssPath, "utf-8"); - {/* UI Component */} -
-

UI Component

-

- Colors used for specific UI components like cards, popovers, and muted - elements. -

-
- - - - - - -
-
- - {/* Utility & Form */} -
-

Utility & Form

-

- Colors used for borders, inputs, and other utility elements. -

-
- - - -
-
- - {/* Status & Feedback */} -
-

Status & Feedback

-

- Colors used to indicate different states and provide feedback to - users. -

-
- - -
-
+export default function TokensPage() { + return ( +
+
+
+ - {/* Chart & Visualization */} -
-

Chart & Visualization

-

- Colors used for data visualization and charts. -

-
- - - - - +

Design Tokens

+

+ A comprehensive overview of all color tokens used in the design + system +

-
- - {/* Sidebar & Navigation */} -
-

Sidebar & Navigation

-

- Colors specific to the sidebar and navigation components. -

-
- - - - - - - - +
+ + + + + + + + + + + + + + +
-
+
); } diff --git a/src/app/borderRadius.css b/src/app/borderRadius.css new file mode 100644 index 00000000..be8473fb --- /dev/null +++ b/src/app/borderRadius.css @@ -0,0 +1,50 @@ +@theme { + /* resetting everything */ + /* --rounded-*: initial; */ + + /* You can define custom breakpoint names, e.g.: */ + --rounded-none: 0; + --rounded-sm: 0.125rem; + --rounded-base: 0.25rem; + --rounded-md: 0.375rem; + --rounded-lg: 0.5rem; + --rounded-xl: 0.75rem; + --rounded-2xl: 1rem; + --rounded-3xl: 1.5rem; + --rounded-full: 624.938rem; + + /* To remove default breakpoints, set them to `initial` */ + /* --rounded-sm: initial; */ + /* --rounded-md: initial; */ + /* etc. */ +} + +@layer utilities { + .rounded-none { + border-radius: var(--rounded-none); + } + .rounded-sm { + border-radius: var(--rounded-sm); + } + .rounded-base { + border-radius: var(--rounded-base); + } + .rounded-md { + border-radius: var(--rounded-md); + } + .rounded-lg { + border-radius: var(--rounded-lg); + } + .rounded-xl { + border-radius: var(--rounded-xl); + } + .rounded-2xl { + border-radius: var(--rounded-2xl); + } + .rounded-3xl { + border-radius: var(--rounded-3xl); + } + .rounded-full { + border-radius: var(--rounded-full); + } +} diff --git a/src/app/breakpoints.css b/src/app/breakpoints.css new file mode 100644 index 00000000..0d65f361 --- /dev/null +++ b/src/app/breakpoints.css @@ -0,0 +1,26 @@ +/* https://tailwindcss.com/docs/responsive-design#customizing-your-theme */ +@theme { + /* resetting everything */ + /* --breakpoint-*: initial; */ + + /* You can define custom breakpoint names, e.g.: */ + /* 0px */ + --breakpoint-base: 0rem; + + /* Override default ones with custom breakpoints here in rem */ + /* 480px Phone */ + --breakpoint-sm: 30rem; + /* 768px Tablet (portrait) */ + --breakpoint-md: 48rem; + /* 992px Tablet (landscape) */ + --breakpoint-lg: 62rem; + /* 1280px Desktop */ + --breakpoint-xl: 80rem; + /* 1536px Desktop (large) */ + --breakpoint-2xl: 96rem; + + /* To remove default breakpoints, set them to `initial` */ + /* --breakpoint-sm: initial; */ + /* --breakpoint-md: initial; */ + /* etc. */ +} diff --git a/src/app/colors.css b/src/app/colors.css new file mode 100644 index 00000000..b03233a4 --- /dev/null +++ b/src/app/colors.css @@ -0,0 +1,342 @@ +@import "tailwindcss"; + +@theme { + /* override all tailwind colors */ + /* --color-*: initial; */ + + /* Chakra theme colors as CSS variables */ + --color-transparent: transparent; + --color-current: currentColor; + --color-black: #000000; + --color-white: #ffffff; + --color-whiteAlpha-50: rgba(255, 255, 255, 0.04); + --color-whiteAlpha-100: rgba(255, 255, 255, 0.06); + --color-whiteAlpha-200: rgba(255, 255, 255, 0.11); + --color-whiteAlpha-300: rgba(255, 255, 255, 0.29); + --color-whiteAlpha-400: rgba(255, 255, 255, 0.42); + --color-whiteAlpha-500: rgba(255, 255, 255, 0.55); + --color-whiteAlpha-600: rgba(255, 255, 255, 0.68); + --color-whiteAlpha-700: rgba(255, 255, 255, 0.76); + --color-whiteAlpha-800: rgba(255, 255, 255, 0.78); + --color-whiteAlpha-900: rgba(255, 255, 255, 0.94); + --color-blackAlpha-50: rgba(0, 0, 0, 0.04); + --color-blackAlpha-100: rgba(0, 0, 0, 0.06); + --color-blackAlpha-200: rgba(0, 0, 0, 0.11); + --color-blackAlpha-300: rgba(0, 0, 0, 0.29); + --color-blackAlpha-400: rgba(0, 0, 0, 0.42); + --color-blackAlpha-500: rgba(0, 0, 0, 0.55); + --color-blackAlpha-600: rgba(0, 0, 0, 0.68); + --color-blackAlpha-700: rgba(0, 0, 0, 0.76); + --color-blackAlpha-800: rgba(0, 0, 0, 0.78); + --color-blackAlpha-900: rgba(0, 0, 0, 0.94); + + --color-blue-50: #f4f7ff; + --color-blue-100: #e1eaff; + --color-blue-200: #c9d8ff; + --color-blue-300: #9cb3fd; + --color-blue-400: #6987f9; + --color-blue-500: #4a65e8; + --color-blue-600: #344bc3; + --color-blue-700: #293ba1; + --color-blue-800: #1f2d7f; + --color-blue-900: #16215f; + --color-cyan-50: #eafaff; + --color-cyan-100: #c6f1ff; + --color-cyan-200: #a0e3fd; + --color-cyan-300: #5cc0f1; + --color-cyan-400: #2695de; + --color-cyan-500: #0873c8; + --color-cyan-600: #0059a1; + --color-cyan-700: #004783; + --color-cyan-800: #003767; + --color-cyan-900: #00294d; + --color-danger-50: #fff5f4; + --color-danger-100: #ffe4e2; + --color-danger-200: #ffccc8; + --color-danger-300: #ff9a94; + --color-danger-400: #f4595a; + --color-danger-500: #d92739; + --color-danger-600: #b30426; + --color-danger-700: #92001f; + --color-danger-800: #730019; + --color-danger-900: #580113; + --color-gray-50: #f7f7f7; + --color-gray-100: #e9e9e9; + --color-gray-200: #d8d8d8; + --color-gray-300: #b5b5b5; + --color-gray-400: #8e8e8e; + --color-gray-500: #717171; + --color-gray-600: #535353; + --color-gray-700: #3b3b3b; + --color-gray-800: #282828; + --color-gray-900: #212121; + --color-green-50: #e8fcf5; + --color-green-100: #bef6e3; + --color-green-200: #8bebd0; + --color-green-300: #44cbac; + --color-green-400: #0ea184; + --color-green-500: #007f66; + --color-green-600: #006450; + --color-green-700: #085040; + --color-green-800: #0d3e31; + --color-green-900: #0f2d25; + --color-info-50: #f7f6ff; + --color-info-100: #eae7ff; + --color-info-200: #d9d4ff; + --color-info-300: #b8a9ff; + --color-info-400: #9373ff; + --color-info-500: #6e3fff; + --color-info-600: #5319e0; + --color-info-700: #4715af; + --color-info-800: #401791; + --color-info-900: #2f1469; + --color-orange-50: #fff6e7; + --color-orange-100: #ffe6bd; + --color-orange-200: #fdd291; + --color-orange-300: #ffa037; + --color-orange-400: #e26e00; + --color-orange-500: #ba5200; + --color-orange-600: #953d00; + --color-orange-700: #7a2f00; + --color-orange-800: #612300; + --color-orange-900: #491901; + --color-pink-50: #fff4fe; + --color-pink-100: #ffe2fb; + --color-pink-200: #fec7f8; + --color-pink-300: #f592f3; + --color-pink-400: #de53e0; + --color-pink-500: #bc29bd; + --color-pink-600: #9d039e; + --color-pink-700: #800081; + --color-pink-800: #640664; + --color-pink-900: #470e46; + --color-primary-50: #f7f6ff; + --color-primary-100: #eae7ff; + --color-primary-200: #d9d4ff; + --color-primary-300: #b8a9ff; + --color-primary-400: #9373ff; + --color-primary-500: #6e3fff; + --color-primary-600: #5319e0; + --color-primary-700: #4715af; + --color-primary-800: #401791; + --color-primary-900: #2f1469; + --color-purple-50: #f7f6ff; + --color-purple-100: #eae7ff; + --color-purple-200: #d9d4ff; + --color-purple-300: #b8a9ff; + --color-purple-400: #9373ff; + --color-purple-500: #6e3fff; + --color-purple-600: #5319e0; + --color-purple-700: #4715af; + --color-purple-800: #401791; + --color-purple-900: #2f1469; + --color-red-50: #fff5f4; + --color-red-100: #ffe4e2; + --color-red-200: #ffccc8; + --color-red-300: #ff9a94; + --color-red-400: #f4595a; + --color-red-500: #d92739; + --color-red-600: #b30426; + --color-red-700: #92001f; + --color-red-800: #730019; + --color-red-900: #580113; + --color-success-50: #e8fcf5; + --color-success-100: #bef6e3; + --color-success-200: #8bebd0; + --color-success-300: #44cbac; + --color-success-400: #0ea184; + --color-success-500: #007f66; + --color-success-600: #006450; + --color-success-700: #085040; + --color-success-800: #0d3e31; + --color-success-900: #0f2d25; + --color-teal-50: #e7fbfb; + --color-teal-100: #bbf4f3; + --color-teal-200: #8be9e8; + --color-teal-300: #3cc8cb; + --color-teal-400: #019ea5; + --color-teal-500: #007c85; + --color-teal-600: #00626b; + --color-teal-700: #0a4e57; + --color-teal-800: #103b44; + --color-teal-900: #102c33; + --color-warning-50: #fff6e7; + --color-warning-100: #ffe6bd; + --color-warning-200: #fdd291; + --color-warning-300: #ffa037; + --color-warning-400: #e26e00; + --color-warning-500: #ba5200; + --color-warning-600: #953d00; + --color-warning-700: #7a2f00; + --color-warning-800: #612300; + --color-warning-900: #491901; + --color-yellow-50: #fdf8d2; + --color-yellow-100: #faec79; + --color-yellow-200: #f8d904; + --color-yellow-300: #d7b300; + --color-yellow-400: #ae8a00; + --color-yellow-500: #8b6b00; + --color-yellow-600: #705300; + --color-yellow-700: #5b4300; + --color-yellow-800: #483300; + --color-yellow-900: #362500; + + /* SEMANTIC TOKENS */ + --color-body-bg: var(--color-white); + --color-subtle-bg: var(--color-gray-50); + --color-body-text: var(--color-blackAlpha-900); + --color-subtle-text: var(--color-blackAlpha-500); + --color-placeholder-color: var(--color-blackAlpha-400); + --color-inverse-text: var(--color-white); + --color-border-color: var(--color-blackAlpha-200); + --color-border-color-a11y: var(--color-blackAlpha-400); + --color-primary-fg: var(--color-primary-600); + --color-danger-fg: var(--color-danger-600); + --color-warning-fg: var(--color-warning-600); + --color-success-fg: var(--color-success-600); + --color-info-fg: var(--color-info-600); + --color-neutral-fg: var(--color-blackAlpha-600); + --color-primary-bg: var(--color-primary-100); + --color-danger-bg: var(--color-danger-100); + --color-warning-bg: var(--color-warning-100); + --color-success-bg: var(--color-success-100); + --color-info-bg: var(--color-info-100); + --color-neutral-bg: var(--color-blackAlpha-100); + --color-primary-bg-active: var(--color-primary-200); + --color-danger-bg-active: var(--color-danger-200); + --color-warning-bg-active: var(--color-warning-200); + --color-success-bg-active: var(--color-success-200); + --color-info-bg-active: var(--color-info-200); + --color-neutral-bg-active: var(--color-blackAlpha-200); + --color-primary: var(--color-primary-500); + --color-danger: var(--color-danger-500); + --color-success: var(--color-success-500); + --color-warning: var(--color-warning-500); + --color-info: var(--color-info-500); + --color-neutral: var(--color-blackAlpha-500); + --color-gray: var(--color-gray-500); + --color-red: var(--color-red-500); + --color-orange: var(--color-orange-500); + --color-yellow: var(--color-yellow-500); + --color-green: var(--color-green-500); + --color-teal: var(--color-teal-500); + --color-cyan: var(--color-cyan-500); + --color-blue: var(--color-blue-500); + --color-purple: var(--color-purple-500); + --color-pink: var(--color-pink-500); + --color-neutral-50: var(--color-blackAlpha-50); + --color-neutral-100: var(--color-blackAlpha-100); + --color-neutral-200: var(--color-blackAlpha-200); + --color-neutral-300: var(--color-blackAlpha-300); + --color-neutral-400: var(--color-blackAlpha-400); + --color-neutral-500: var(--color-blackAlpha-500); + --color-neutral-600: var(--color-blackAlpha-600); + --color-neutral-700: var(--color-blackAlpha-700); + --color-neutral-800: var(--color-blackAlpha-800); + --color-neutral-900: var(--color-blackAlpha-900); +} + +@layer utilities { + .ai { + background-image: linear-gradient( + to top right, + var(--color-purple-500), + var(--color-red-500) + ); + } + .ai-50 { + background-image: linear-gradient( + to top right, + var(--color-purple-50), + var(--color-red-50) + ); + } + .ai-100 { + background-image: linear-gradient( + to top right, + var(--color-purple-100), + var(--color-red-100) + ); + } + .ai-200 { + background-image: linear-gradient( + to top right, + var(--color-purple-200), + var(--color-red-200) + ); + } + .ai-300 { + background-image: linear-gradient( + to top right, + var(--color-purple-300), + var(--color-red-300) + ); + } + .ai-400 { + background-image: linear-gradient( + to top right, + var(--color-purple-400), + var(--color-red-400) + ); + } + .ai-500 { + background-image: linear-gradient( + to top right, + var(--color-purple-500), + var(--color-red-500) + ); + } + .ai-600 { + background-image: linear-gradient( + to top right, + var(--color-purple-600), + var(--color-red-600) + ); + } + .hover\:ai-600:hover { + background-image: linear-gradient( + to top right, + var(--color-purple-600), + var(--color-red-600) + ); + } + .text-ai-600 { + background-image: linear-gradient( + to top right, + var(--color-purple-600), + var(--color-red-600) + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + color: transparent; + } + .ai-700 { + background-image: linear-gradient( + to top right, + var(--color-purple-700), + var(--color-red-700) + ); + } + .active\:ai-700:active { + background-image: linear-gradient( + to top right, + var(--color-purple-700), + var(--color-red-700) + ); + } + .ai-800 { + background-image: linear-gradient( + to top right, + var(--color-purple-800), + var(--color-red-800) + ); + } + .ai-900 { + background-image: linear-gradient( + to top right, + var(--color-purple-900), + var(--color-red-900) + ); + } +} diff --git a/src/app/demo/[name]/blocks/shell-layout.tsx b/src/app/demo/[name]/blocks/shell-layout.tsx index e4a8e175..e0343103 100644 --- a/src/app/demo/[name]/blocks/shell-layout.tsx +++ b/src/app/demo/[name]/blocks/shell-layout.tsx @@ -2,7 +2,7 @@ import React, { type ReactNode } from "react"; import { BrandHeader } from "@/components/brand-header"; import { BrandSidebar } from "@/components/brand-sidebar"; -import { SidebarProvider } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/registry/docsite-sidebar"; import { Toaster } from "@/components/ui/sonner"; export default function ShellLayout({ diff --git a/src/app/demo/[name]/blocks/top-bar.tsx b/src/app/demo/[name]/blocks/top-bar.tsx new file mode 100644 index 00000000..f01bf33c --- /dev/null +++ b/src/app/demo/[name]/blocks/top-bar.tsx @@ -0,0 +1,13 @@ +import Topbar from "@/components/ui/top-bar"; +import MinimalLayout from "./minimal-layout"; + +export const topbar = { + name: "topbar", + components: { + Default: ( + + + + ), + }, +}; diff --git a/src/app/demo/[name]/components/brand-header.tsx b/src/app/demo/[name]/components/brand-header.tsx index 01075c4c..5c992b17 100644 --- a/src/app/demo/[name]/components/brand-header.tsx +++ b/src/app/demo/[name]/components/brand-header.tsx @@ -1,5 +1,5 @@ import { BrandHeader } from "@/components/brand-header"; -import { SidebarProvider } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/registry/docsite-sidebar"; export const brandHeader = { name: "brand-header", diff --git a/src/app/demo/[name]/components/brand-sidebar.tsx b/src/app/demo/[name]/components/brand-sidebar.tsx index 0b7af46a..8504a597 100644 --- a/src/app/demo/[name]/components/brand-sidebar.tsx +++ b/src/app/demo/[name]/components/brand-sidebar.tsx @@ -1,5 +1,5 @@ import { BrandSidebar } from "@/components/brand-sidebar"; -import { SidebarProvider } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/registry/docsite-sidebar"; export const brandSidebar = { name: "brand-sidebar", diff --git a/src/app/demo/[name]/index.tsx b/src/app/demo/[name]/index.tsx index 63bcb5ad..53d6ad84 100644 --- a/src/app/demo/[name]/index.tsx +++ b/src/app/demo/[name]/index.tsx @@ -15,35 +15,60 @@ import { productGrid } from "@/app/demo/[name]/components/product-grid"; import { promo } from "@/app/demo/[name]/components/promo"; // ui +// import { menuBar } from "@/app/demo/[name]/ui/menu-bar"; import { accordion } from "@/app/demo/[name]/ui/accordion"; import { alert } from "@/app/demo/[name]/ui/alert"; +import { alertDialog } from "@/app/demo/[name]/ui/alert-dialog"; +import { aspectRatio } from "@/app/demo/[name]/ui/aspect-ratio"; import { avatar } from "@/app/demo/[name]/ui/avatar"; import { badge } from "@/app/demo/[name]/ui/badge"; import { breadcrumb } from "@/app/demo/[name]/ui/breadcrumb"; import { button } from "@/app/demo/[name]/ui/button"; import { calendar } from "@/app/demo/[name]/ui/calendar"; import { card } from "@/app/demo/[name]/ui/card"; +import { carousel } from "@/app/demo/[name]/ui/carousel"; import { chart } from "@/app/demo/[name]/ui/chart"; import { checkbox } from "@/app/demo/[name]/ui/checkbox"; +import { collapsible } from "@/app/demo/[name]/ui/collapsible"; +import { combobox } from "@/app/demo/[name]/ui/combobox"; +import { command } from "@/app/demo/[name]/ui/command"; +import { contextMenu } from "@/app/demo/[name]/ui/context-menu"; import { dataTable } from "@/app/demo/[name]/ui/data-table"; import { datePicker } from "@/app/demo/[name]/ui/date-picker"; import { dialog } from "@/app/demo/[name]/ui/dialog"; +import { drawer } from "@/app/demo/[name]/ui/drawer"; import { dropdownMenu } from "@/app/demo/[name]/ui/dropdown-menu"; +import { form } from "@/app/demo/[name]/ui/forms/form"; +import { hoverCard } from "@/app/demo/[name]/ui/hover-card"; import { input } from "@/app/demo/[name]/ui/input"; -import { menuBar } from "@/app/demo/[name]/ui/menu-bar"; +import { inputOtp } from "@/app/demo/[name]/ui/inputOtp"; +import { label } from "@/app/demo/[name]/ui/label"; +import { navigationMenu } from "@/app/demo/[name]/ui/navigation-menu"; +import { pagination } from "@/app/demo/[name]/ui/pagination"; +import { popover } from "@/app/demo/[name]/ui/popover"; +import { progress } from "@/app/demo/[name]/ui/progress"; +import { radioGroup } from "@/app/demo/[name]/ui/radio-group"; +import { resizable } from "@/app/demo/[name]/ui/resizable"; +import { scrollArea } from "@/app/demo/[name]/ui/scroll-area"; import { select } from "@/app/demo/[name]/ui/select"; import { separator } from "@/app/demo/[name]/ui/separator"; +import { sheet } from "@/app/demo/[name]/ui/sheet"; +import { sidebar } from "@/app/demo/[name]/ui/sidebar"; import { skeleton } from "@/app/demo/[name]/ui/skeleton"; import { slider } from "@/app/demo/[name]/ui/slider"; import { sonner } from "@/app/demo/[name]/ui/sonner"; +import { spinner } from "@/app/demo/[name]/ui/spinner"; import { switchComponent } from "@/app/demo/[name]/ui/switch"; import { table } from "@/app/demo/[name]/ui/table"; import { tabs } from "@/app/demo/[name]/ui/tabs"; +import { textarea } from "@/app/demo/[name]/ui/textarea"; +import { toggle } from "@/app/demo/[name]/ui/toggle"; import { toggleGroup } from "@/app/demo/[name]/ui/toggle-group"; import { tooltip } from "@/app/demo/[name]/ui/tooltip"; +import { topbar } from "@/app/demo/[name]/blocks/top-bar"; interface Demo { - name: string; // this must match the `registry.json` name + name: string; // this must match the `/registries/registry.json` name components?: { [name: string]: ReactNode | ReactElement; }; @@ -66,29 +91,54 @@ export const demos: { [name: string]: Demo } = { // ui accordion, + "alert-dialog": alertDialog, alert, + "aspect-ratio": aspectRatio, avatar, badge, breadcrumb, button, calendar, card, + carousel, chart, checkbox, + collapsible, + combobox, + "context-menu": contextMenu, + command, dialog, "date-picker": datePicker, "data-table": dataTable, + drawer, "dropdown-menu": dropdownMenu, + form, input, - "menu-bar": menuBar, + inputOtp, + label, + // "menu-bar": menuBar, + "navigation-menu": navigationMenu, + progress, + "scroll-area": scrollArea, + "radio-group": radioGroup, + resizable, select, separator, + sheet, + sidebar, skeleton, slider, + spinner, switch: switchComponent, sonner, table, tabs, + textarea, "toggle-group": toggleGroup, tooltip, + toggle, + topbar, + pagination, + popover, + "hover-card": hoverCard, }; diff --git a/src/app/demo/[name]/page.tsx b/src/app/demo/[name]/page.tsx index 42cbd10e..c34961ca 100644 --- a/src/app/demo/[name]/page.tsx +++ b/src/app/demo/[name]/page.tsx @@ -27,7 +27,7 @@ export default async function DemoPage({ const { components } = demos[name]; return ( -
+
{components && Object.entries(components).map(([key, node]) => (
diff --git a/src/app/demo/[name]/ui/alert-closable.tsx b/src/app/demo/[name]/ui/alert-closable.tsx new file mode 100644 index 00000000..dd28d68c --- /dev/null +++ b/src/app/demo/[name]/ui/alert-closable.tsx @@ -0,0 +1,25 @@ +"use client"; +import * as React from "react"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; + +export function ClosableAlert() { + const [isOpen, setIsOpen] = React.useState(true); + + if (!isOpen) return null; + + return ( + + Closable Danger Alert + This is a closable alert with a title and description. + + + ); +} \ No newline at end of file diff --git a/src/app/demo/[name]/ui/alert-dialog.tsx b/src/app/demo/[name]/ui/alert-dialog.tsx new file mode 100644 index 00000000..7c59321c --- /dev/null +++ b/src/app/demo/[name]/ui/alert-dialog.tsx @@ -0,0 +1,44 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; +import { Button } from "@/components/ui/button"; + +export const alertDialog = { + name: "Alert Dialog", + components: { + Default: ( +
+
+ + + + + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete + your account and remove your data from our servers. + + + + Cancel + Delete + + + +
+
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/alert.tsx b/src/app/demo/[name]/ui/alert.tsx index c5d0bd5c..5204f636 100644 --- a/src/app/demo/[name]/ui/alert.tsx +++ b/src/app/demo/[name]/ui/alert.tsx @@ -1,26 +1,58 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { AlertCircle, Terminal } from "lucide-react"; +import { ClosableAlert } from "@/app/demo/[name]/ui/alert-closable"; export const alert = { name: "alert", components: { - Default: ( - - - Heads up! + Primary: ( + + Primary Alert - You can add components to your app using the cli. + This is a primary alert with a title and description. ), - Destructive: ( - - - Error + Success: ( + + Success Alert - Your session has expired. Please log in again. + This is a success alert with a title and description. ), + Danger: ( + + Danger Alert + + This is a danger alert with a title and description. + + + ), + Warning: ( + + Warning Alert + + This is a warning alert with a title and description. + + + ), + Closable: , + Descriptive: ( + + + This is an extremely long alert title that spans multiple lines to + demonstrate how the component handles very lengthy headings while + maintaining readability and proper text wrapping behavior + + + This is an equally long description that contains detailed information + about the alert. It shows how the component can accommodate extensive + content while preserving proper spacing, alignment, and readability + across different screen sizes and viewport widths. This helps ensure + the user experience remains consistent regardless of the content + length. + + + ) }, }; diff --git a/src/app/demo/[name]/ui/area-chart.tsx b/src/app/demo/[name]/ui/area-chart.tsx index d63e97f2..1ebd0298 100644 --- a/src/app/demo/[name]/ui/area-chart.tsx +++ b/src/app/demo/[name]/ui/area-chart.tsx @@ -1,263 +1,94 @@ "use client"; -import * as React from "react"; +import { TrendingUp } from "lucide-react"; import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"; import { Card, CardContent, CardDescription, + CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { - type ChartConfig, + ChartConfig, ChartContainer, - ChartLegend, - ChartLegendContent, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; + +export const description = "A simple area chart"; + const chartData = [ - { date: "2024-04-01", desktop: 222, mobile: 150 }, - { date: "2024-04-02", desktop: 97, mobile: 180 }, - { date: "2024-04-03", desktop: 167, mobile: 120 }, - { date: "2024-04-04", desktop: 242, mobile: 260 }, - { date: "2024-04-05", desktop: 373, mobile: 290 }, - { date: "2024-04-06", desktop: 301, mobile: 340 }, - { date: "2024-04-07", desktop: 245, mobile: 180 }, - { date: "2024-04-08", desktop: 409, mobile: 320 }, - { date: "2024-04-09", desktop: 59, mobile: 110 }, - { date: "2024-04-10", desktop: 261, mobile: 190 }, - { date: "2024-04-11", desktop: 327, mobile: 350 }, - { date: "2024-04-12", desktop: 292, mobile: 210 }, - { date: "2024-04-13", desktop: 342, mobile: 380 }, - { date: "2024-04-14", desktop: 137, mobile: 220 }, - { date: "2024-04-15", desktop: 120, mobile: 170 }, - { date: "2024-04-16", desktop: 138, mobile: 190 }, - { date: "2024-04-17", desktop: 446, mobile: 360 }, - { date: "2024-04-18", desktop: 364, mobile: 410 }, - { date: "2024-04-19", desktop: 243, mobile: 180 }, - { date: "2024-04-20", desktop: 89, mobile: 150 }, - { date: "2024-04-21", desktop: 137, mobile: 200 }, - { date: "2024-04-22", desktop: 224, mobile: 170 }, - { date: "2024-04-23", desktop: 138, mobile: 230 }, - { date: "2024-04-24", desktop: 387, mobile: 290 }, - { date: "2024-04-25", desktop: 215, mobile: 250 }, - { date: "2024-04-26", desktop: 75, mobile: 130 }, - { date: "2024-04-27", desktop: 383, mobile: 420 }, - { date: "2024-04-28", desktop: 122, mobile: 180 }, - { date: "2024-04-29", desktop: 315, mobile: 240 }, - { date: "2024-04-30", desktop: 454, mobile: 380 }, - { date: "2024-05-01", desktop: 165, mobile: 220 }, - { date: "2024-05-02", desktop: 293, mobile: 310 }, - { date: "2024-05-03", desktop: 247, mobile: 190 }, - { date: "2024-05-04", desktop: 385, mobile: 420 }, - { date: "2024-05-05", desktop: 481, mobile: 390 }, - { date: "2024-05-06", desktop: 498, mobile: 520 }, - { date: "2024-05-07", desktop: 388, mobile: 300 }, - { date: "2024-05-08", desktop: 149, mobile: 210 }, - { date: "2024-05-09", desktop: 227, mobile: 180 }, - { date: "2024-05-10", desktop: 293, mobile: 330 }, - { date: "2024-05-11", desktop: 335, mobile: 270 }, - { date: "2024-05-12", desktop: 197, mobile: 240 }, - { date: "2024-05-13", desktop: 197, mobile: 160 }, - { date: "2024-05-14", desktop: 448, mobile: 490 }, - { date: "2024-05-15", desktop: 473, mobile: 380 }, - { date: "2024-05-16", desktop: 338, mobile: 400 }, - { date: "2024-05-17", desktop: 499, mobile: 420 }, - { date: "2024-05-18", desktop: 315, mobile: 350 }, - { date: "2024-05-19", desktop: 235, mobile: 180 }, - { date: "2024-05-20", desktop: 177, mobile: 230 }, - { date: "2024-05-21", desktop: 82, mobile: 140 }, - { date: "2024-05-22", desktop: 81, mobile: 120 }, - { date: "2024-05-23", desktop: 252, mobile: 290 }, - { date: "2024-05-24", desktop: 294, mobile: 220 }, - { date: "2024-05-25", desktop: 201, mobile: 250 }, - { date: "2024-05-26", desktop: 213, mobile: 170 }, - { date: "2024-05-27", desktop: 420, mobile: 460 }, - { date: "2024-05-28", desktop: 233, mobile: 190 }, - { date: "2024-05-29", desktop: 78, mobile: 130 }, - { date: "2024-05-30", desktop: 340, mobile: 280 }, - { date: "2024-05-31", desktop: 178, mobile: 230 }, - { date: "2024-06-01", desktop: 178, mobile: 200 }, - { date: "2024-06-02", desktop: 470, mobile: 410 }, - { date: "2024-06-03", desktop: 103, mobile: 160 }, - { date: "2024-06-04", desktop: 439, mobile: 380 }, - { date: "2024-06-05", desktop: 88, mobile: 140 }, - { date: "2024-06-06", desktop: 294, mobile: 250 }, - { date: "2024-06-07", desktop: 323, mobile: 370 }, - { date: "2024-06-08", desktop: 385, mobile: 320 }, - { date: "2024-06-09", desktop: 438, mobile: 480 }, - { date: "2024-06-10", desktop: 155, mobile: 200 }, - { date: "2024-06-11", desktop: 92, mobile: 150 }, - { date: "2024-06-12", desktop: 492, mobile: 420 }, - { date: "2024-06-13", desktop: 81, mobile: 130 }, - { date: "2024-06-14", desktop: 426, mobile: 380 }, - { date: "2024-06-15", desktop: 307, mobile: 350 }, - { date: "2024-06-16", desktop: 371, mobile: 310 }, - { date: "2024-06-17", desktop: 475, mobile: 520 }, - { date: "2024-06-18", desktop: 107, mobile: 170 }, - { date: "2024-06-19", desktop: 341, mobile: 290 }, - { date: "2024-06-20", desktop: 408, mobile: 450 }, - { date: "2024-06-21", desktop: 169, mobile: 210 }, - { date: "2024-06-22", desktop: 317, mobile: 270 }, - { date: "2024-06-23", desktop: 480, mobile: 530 }, - { date: "2024-06-24", desktop: 132, mobile: 180 }, - { date: "2024-06-25", desktop: 141, mobile: 190 }, - { date: "2024-06-26", desktop: 434, mobile: 380 }, - { date: "2024-06-27", desktop: 448, mobile: 490 }, - { date: "2024-06-28", desktop: 149, mobile: 200 }, - { date: "2024-06-29", desktop: 103, mobile: 160 }, - { date: "2024-06-30", desktop: 446, mobile: 400 }, + { month: "January", desktop: 186 }, + { month: "February", desktop: 305 }, + { month: "March", desktop: 237 }, + { month: "April", desktop: 73 }, + { month: "May", desktop: 209 }, + { month: "June", desktop: 214 }, ]; const chartConfig = { - visitors: { - label: "Visitors", - }, desktop: { label: "Desktop", color: "var(--chart-1)", }, - mobile: { - label: "Mobile", - color: "var(--chart-4)", - }, } satisfies ChartConfig; export function AreaChartComponent() { - const [timeRange, setTimeRange] = React.useState("90d"); - - const filteredData = chartData.filter((item) => { - const date = new Date(item.date); - const referenceDate = new Date("2024-06-30"); - let daysToSubtract = 90; - if (timeRange === "30d") { - daysToSubtract = 30; - } else if (timeRange === "7d") { - daysToSubtract = 7; - } - const startDate = new Date(referenceDate); - startDate.setDate(startDate.getDate() - daysToSubtract); - return date >= startDate; - }); - return ( - + Area Chart - Showing total visitors for the last 3 months + Showing total visitors for the last 6 months - - - - - - - - - - - - - - - - + + + { - const date = new Date(value); - return date.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - }); - }} + tickFormatter={(value) => value.slice(0, 3)} /> { - return new Date(value).toLocaleDateString("en-US", { - month: "short", - day: "numeric", - }); - }} - indicator="dot" - /> - } - /> - } /> - } /> + +
+
+
+ Trending up by 5.2% this month +
+
+ January - June 2024 +
+
+
+
); } diff --git a/src/app/demo/[name]/ui/aspect-ratio.tsx b/src/app/demo/[name]/ui/aspect-ratio.tsx new file mode 100644 index 00000000..c8e268e7 --- /dev/null +++ b/src/app/demo/[name]/ui/aspect-ratio.tsx @@ -0,0 +1,15 @@ +import { AspectRatio } from "@/components/ui/aspect-ratio"; + +export const aspectRatio = { + name: "aspect-ratio", + components: { + Default: ( + +

16:9

+
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/avatar.tsx b/src/app/demo/[name]/ui/avatar.tsx index 03703617..4e8d04ba 100644 --- a/src/app/demo/[name]/ui/avatar.tsx +++ b/src/app/demo/[name]/ui/avatar.tsx @@ -3,21 +3,58 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; export const avatar = { name: "avatar", components: { - Default: ( + default: ( - + CN ), - Fallback: ( + fallback: ( - - - CN - + BM ), - }, + large:( +
+ + CN + + + + MS + + + + OO + +
+ ), + interactive: ( +
+ + + CN + + + + CV + + + + ES + +
+ ) + } }; diff --git a/src/app/demo/[name]/ui/badge.tsx b/src/app/demo/[name]/ui/badge.tsx index bce5a826..ec3d3784 100644 --- a/src/app/demo/[name]/ui/badge.tsx +++ b/src/app/demo/[name]/ui/badge.tsx @@ -1,46 +1,118 @@ -import { Badge } from "@/components/ui/badge"; -import { ArrowRight } from "lucide-react"; -import Link from "next/link"; +import { Badge } from "@/components/ui/badge" +import { ArrowRightIcon } from "lucide-react" export const badge = { name: "badge", components: { - Default: Badge, - Secondary: Secondary, - Outline: Secondary, - Destructive: Destructive, + // Sizes + SizeSm: Size sm, + SizeMd: Size md, + SizeLg: Size lg, + // Default (neutral + colorSchemes) + DefaultNeutral: Default Neutral, + DefaultPrimary: Default Primary, + DefaultDanger: Default Danger, + DefaultSuccess: Default Success, + DefaultWarning: Default Warning, + DefaultYellow: Default Yellow, + DefaultTeal: Default Teal, + DefaultCyan: Default Cyan, + DefaultBlue: Default Blue, + DefaultPink: Default Pink, + + // Bold variants + BoldNeutral: Bold Neutral, + BoldPrimary: ( + + Bold Primary + + ), + BoldDanger: ( + + Bold Danger + + ), + BoldSuccess: ( + + Bold Success + + ), + BoldWarning: ( + + Bold Warning + + ), + BoldYellow: ( + + Bold Yellow + + ), + BoldTeal: ( + + Bold Teal + + ), + BoldCyan: ( + + Bold Cyan + + ), + BoldBlue: ( + + Bold Blue + + ), + BoldPink: ( + + Bold Pink + + ), + + // Default links DefaultLink: ( - - - Link - - + + + Default Link + + + ), + DefaultLinkPrimary: ( + + + Default Link + ), - SecondaryLink: ( - - - Link - - + DefaultLinkDanger: ( + + + Default Link + + + ), + + // Bold links + BoldLink: ( + + + Bold Link + ), - OutlineLink: ( - - - Link - - + BoldLinkPrimary: ( + + + Bold Link + ), - DestructiveLink: ( - - - Link - - + BoldLinkDanger: ( + + + Bold Link + ), }, -}; +} diff --git a/src/app/demo/[name]/ui/bar-chart.tsx b/src/app/demo/[name]/ui/bar-chart.tsx index ec393c50..e8d2515f 100644 --- a/src/app/demo/[name]/ui/bar-chart.tsx +++ b/src/app/demo/[name]/ui/bar-chart.tsx @@ -1,23 +1,24 @@ "use client"; +import { TrendingUp } from "lucide-react"; import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"; import { Card, CardContent, CardDescription, + CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { - type ChartConfig, + ChartConfig, ChartContainer, - ChartLegend, - ChartLegendContent, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; -import * as React from "react"; + +export const description = "A multiple bar chart"; const chartData = [ { month: "January", desktop: 186, mobile: 80 }, @@ -29,43 +30,51 @@ const chartData = [ ]; const chartConfig = { - visitors: { - label: "Total Visitors", - }, desktop: { label: "Desktop", color: "var(--chart-1)", }, mobile: { label: "Mobile", - color: "var(--chart-4)", + color: "var(--chart-2)", }, } satisfies ChartConfig; export function BarChartComponent() { return ( - + - Bar Chart + Bar Chart - Multiple January - June 2024 - value.slice(0, 3)} /> - } /> - } /> + } + /> + +
+ Trending up by 5.2% this month +
+
+ Showing total visitors for the last 6 months +
+
); } diff --git a/src/app/demo/[name]/ui/bar-mixed-chart.tsx b/src/app/demo/[name]/ui/bar-mixed-chart.tsx new file mode 100644 index 00000000..ab0f8aa7 --- /dev/null +++ b/src/app/demo/[name]/ui/bar-mixed-chart.tsx @@ -0,0 +1,103 @@ +"use client" + +import { TrendingUp } from "lucide-react"; +import { Bar, BarChart, XAxis, YAxis } from "recharts"; + +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/components/ui/chart"; + +export const description = "A mixed bar chart"; + +const chartData = [ + { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" }, + { browser: "safari", visitors: 200, fill: "var(--color-safari)" }, + { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" }, + { browser: "edge", visitors: 173, fill: "var(--color-edge)" }, + { browser: "other", visitors: 90, fill: "var(--color-other)" }, +] + +const chartConfig = { + visitors: { + label: "Visitors", + }, + chrome: { + label: "Chrome", + color: "var(--chart-1)", + }, + safari: { + label: "Safari", + color: "var(--chart-2)", + }, + firefox: { + label: "Firefox", + color: "var(--chart-3)", + }, + edge: { + label: "Edge", + color: "var(--chart-4)", + }, + other: { + label: "Other", + color: "var(--chart-5)", + }, +} satisfies ChartConfig + +export function BarMixedChartComponent() { + return ( + + + Bar Chart - Mixed + January - June 2024 + + + + + + chartConfig[value as keyof typeof chartConfig]?.label + } + /> + + } + /> + + + + + +
+ Trending up by 5.2% this month +
+
+ Showing total visitors for the last 6 months +
+
+
+ ); +} diff --git a/src/app/demo/[name]/ui/button.tsx b/src/app/demo/[name]/ui/button.tsx index 90b82515..3f563981 100644 --- a/src/app/demo/[name]/ui/button.tsx +++ b/src/app/demo/[name]/ui/button.tsx @@ -1,10 +1,49 @@ import { Button } from "@/components/ui/button"; +import { mdiInformationOutline } from "@mdi/js"; +import Icon from "@mdi/react"; export const button = { name: "button", components: { - Primary: , - Secondary: , - Outline: , + Variants: ( +
+ + + + +
+ ), + Sizing: ( +
+ + + + +
+ ), + ColorSchemes: ( +
+ + + + +
+ ), + IconSizing: ( +
+ + + + +
+ ), }, }; diff --git a/src/app/demo/[name]/ui/calendar.tsx b/src/app/demo/[name]/ui/calendar.tsx index c93f3c38..53c7ddb5 100644 --- a/src/app/demo/[name]/ui/calendar.tsx +++ b/src/app/demo/[name]/ui/calendar.tsx @@ -5,6 +5,7 @@ export const calendar = { name: "calendar", components: { Default: , - Multi: , + TwoMonths: , + ThreeMonths: , }, }; diff --git a/src/app/demo/[name]/ui/card.tsx b/src/app/demo/[name]/ui/card.tsx index 0290130f..c51f9a61 100644 --- a/src/app/demo/[name]/ui/card.tsx +++ b/src/app/demo/[name]/ui/card.tsx @@ -12,20 +12,195 @@ export const card = { name: "card", components: { Default: ( - + - Create project + Default Card + Style: flat, Elevation: none + + +

This is a default card with flat style and no elevation.

+
+ + + +
+ ), + // Elevation Variants + ElevationNone: ( + + + none Elevation + Style: outline, Elevation: none + + +

This card demonstrates the none elevation variant with outline style.

+
+ + + +
+ ), + ElevationXs: ( + + + xs Elevation + Style: outline, Elevation: xs + + +

This card demonstrates the xs elevation variant with outline style.

+
+ + + +
+ ), + ElevationSm: ( + + + sm Elevation + Style: outline, Elevation: sm + + +

This card demonstrates the sm elevation variant with outline style.

+
+ + + +
+ ), + ElevationBase: ( + + + base Elevation + Style: outline, Elevation: base + + +

This card demonstrates the base elevation variant with outline style.

+
+ + + +
+ ), + ElevationMd: ( + + + md Elevation + Style: outline, Elevation: md + + +

This card demonstrates the md elevation variant with outline style.

+
+ + + +
+ ), + ElevationLg: ( + + + lg Elevation + Style: outline, Elevation: lg + + +

This card demonstrates the lg elevation variant with outline style.

+
+ + + +
+ ), + + // Style Variants + StyleFlat: ( + + + flat Style + Style: flat, Elevation: base + + +

This card demonstrates the flat style variant with base elevation.

+
+ + + +
+ ), + StyleOutline: ( + + + outline Style + Style: outline, Elevation: base + + +

This card demonstrates the outline style variant with base elevation.

+
+ + + +
+ ), + StyleFilled: ( + + + filled Style + Style: filled, Elevation: base + + +

This card demonstrates the filled style variant with base elevation.

+
+ + + +
+ ), + + // Padding Variants + PaddingSm: ( + + + Padding: sm - Deploy your new project in one-click. + Style: outline, Elevation: md, Padding: sm -

This is the content of a card!

+

This card demonstrates the sm padding variant with outline style and md elevation.

- - - - + + + +
+ ), + PaddingMd: ( + + + Padding: md + + Style: outline, Elevation: md, Padding: md + + + +

This card demonstrates the md padding variant with outline style and md elevation.

+
+ + + +
+ ), + PaddingLg: ( + + + Padding: lg + + Style: outline, Elevation: md, Padding: lg + + + +

This card demonstrates the lg padding variant with outline style and md elevation.

+
+ +
), diff --git a/src/app/demo/[name]/ui/carousel.tsx b/src/app/demo/[name]/ui/carousel.tsx new file mode 100644 index 00000000..17395539 --- /dev/null +++ b/src/app/demo/[name]/ui/carousel.tsx @@ -0,0 +1,87 @@ +import { Card, CardContent } from "@/components/ui/card"; +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@/components/ui/carousel"; + +export const carousel = { + name: "carousel", + components: { + // Default Carousel + Default: ( +
+ + + {Array.from({ length: 5 }).map((_, index) => ( + +
+ + + {index + 1} + + +
+
+ ))} +
+ + +
+
+ ), + + // Start-aligned Carousel + StartAligned: ( +
+ + + {Array.from({ length: 5 }).map((_, index) => ( + +
+ + + {index + 1} + + +
+
+ ))} +
+ + +
+
+ ), + + // Carousel with negative margin + half-width items + NegativeMargin: ( +
+ + + {Array.from({ length: 5 }).map((_, index) => ( + +
+ + + {index + 1} + + +
+
+ ))} +
+ + +
+
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/chart.tsx b/src/app/demo/[name]/ui/chart.tsx index 48fcbfe9..774eedb2 100644 --- a/src/app/demo/[name]/ui/chart.tsx +++ b/src/app/demo/[name]/ui/chart.tsx @@ -1,12 +1,16 @@ import { AreaChartComponent } from "@/app/demo/[name]/ui/area-chart"; import { BarChartComponent } from "@/app/demo/[name]/ui/bar-chart"; import { PieChartComponent } from "@/app/demo/[name]/ui/pie-chart"; +import { BarMixedChartComponent } from "@/app/demo/[name]/ui/bar-mixed-chart"; +import { LineChartComponent } from "@/app/demo/[name]/ui/line-chart"; export const chart = { name: "chart", components: { - BarChart: , AreaChart: , + BarChart: , + MixedBarChart: , + LineChart: , PieChart: , }, }; diff --git a/src/app/demo/[name]/ui/checkbox.tsx b/src/app/demo/[name]/ui/checkbox.tsx index 99ed4a3c..931703a6 100644 --- a/src/app/demo/[name]/ui/checkbox.tsx +++ b/src/app/demo/[name]/ui/checkbox.tsx @@ -1,18 +1,49 @@ import { Checkbox } from "@/components/ui/checkbox"; +import { Label } from "@/components/ui/label"; export const checkbox = { name: "checkbox", components: { Default: ( -
+
- +
), + WithDescriptionCheckBox: ( +
+ +
+ +

+ By clicking this checkbox, you agree to the terms and conditions. +

+
+
+ ), + DisabledCheckBox: ( +
+ + +
+ ), + EnabledLabelCheckBox: ( + + ) + }, }; diff --git a/src/app/demo/[name]/ui/collapsible.tsx b/src/app/demo/[name]/ui/collapsible.tsx new file mode 100644 index 00000000..f69a9f70 --- /dev/null +++ b/src/app/demo/[name]/ui/collapsible.tsx @@ -0,0 +1,8 @@ +import { CollapsibleDemo } from "@/app/demo/[name]/ui/collapsibleDemo"; + +export const collapsible = { + name: "Collapsible", + components: { + Default: , + }, +}; diff --git a/src/app/demo/[name]/ui/collapsibleDemo.tsx b/src/app/demo/[name]/ui/collapsibleDemo.tsx new file mode 100644 index 00000000..dae03a4d --- /dev/null +++ b/src/app/demo/[name]/ui/collapsibleDemo.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { ChevronsUpDown } from "lucide-react"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; +import React from "react"; + +export function CollapsibleDemo() { + const [isOpen, setIsOpen] = React.useState(false); + + return ( +
+ +
+

+ @peduarte starred 3 repositories +

+ + + +
+
+ @radix-ui/primitives +
+ +
+ @radix-ui/colors +
+
+ @stitches/react +
+
+
+
+ ); +} diff --git a/src/app/demo/[name]/ui/combobox.tsx b/src/app/demo/[name]/ui/combobox.tsx new file mode 100644 index 00000000..fdf31646 --- /dev/null +++ b/src/app/demo/[name]/ui/combobox.tsx @@ -0,0 +1,107 @@ +import { + ComboboxWithCheckbox, + FrameworkCombobox, + TimezoneCombobox, + UserCombobox, +} from "@/components/ui/combobox"; + +const frameworks = [ + { + value: "next.js", + label: "Next.js", + }, + { + value: "sveltekit", + label: "SvelteKit", + }, + { + value: "nuxt.js", + label: "Nuxt.js", + }, + { + value: "remix", + label: "Remix", + }, + { + value: "astro", + label: "Astro", + }, +]; +const users = [ + { + id: "1", + username: "shadcn", + }, + { + id: "2", + username: "leerob", + }, + { + id: "3", + username: "evilrabbit", + }, +] as const; +const timezones = [ + { + label: "Americas", + timezones: [ + { value: "America/New_York", label: "(GMT-5) New York" }, + { value: "America/Los_Angeles", label: "(GMT-8) Los Angeles" }, + { value: "America/Chicago", label: "(GMT-6) Chicago" }, + { value: "America/Toronto", label: "(GMT-5) Toronto" }, + { value: "America/Vancouver", label: "(GMT-8) Vancouver" }, + { value: "America/Sao_Paulo", label: "(GMT-3) São Paulo" }, + ], + }, + { + label: "Europe", + timezones: [ + { value: "Europe/London", label: "(GMT+0) London" }, + { value: "Europe/Paris", label: "(GMT+1) Paris" }, + { value: "Europe/Berlin", label: "(GMT+1) Berlin" }, + { value: "Europe/Rome", label: "(GMT+1) Rome" }, + { value: "Europe/Madrid", label: "(GMT+1) Madrid" }, + { value: "Europe/Amsterdam", label: "(GMT+1) Amsterdam" }, + ], + }, + { + label: "Asia/Pacific", + timezones: [ + { value: "Asia/Tokyo", label: "(GMT+9) Tokyo" }, + { value: "Asia/Shanghai", label: "(GMT+8) Shanghai" }, + { value: "Asia/Singapore", label: "(GMT+8) Singapore" }, + { value: "Asia/Dubai", label: "(GMT+4) Dubai" }, + { value: "Australia/Sydney", label: "(GMT+11) Sydney" }, + { value: "Asia/Seoul", label: "(GMT+9) Seoul" }, + ], + }, +] as const; + +export const combobox = { + name: "combobox", + components: { + FrameworkCombobox: ( +
+ +
+ ), + UserCombobox: ( +
+ +
+ ), + TimezoneCombobox: ( +
+ +
+ ), + ComboboxWithCheckbox: ( +
+ +
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/command.tsx b/src/app/demo/[name]/ui/command.tsx new file mode 100644 index 00000000..52043dd0 --- /dev/null +++ b/src/app/demo/[name]/ui/command.tsx @@ -0,0 +1,8 @@ +import CommandDemo from "@/app/demo/[name]/ui//commandDemo"; + +export const command = { + name: "Command", + components: { + Default: , + }, +}; diff --git a/src/app/demo/[name]/ui/commandDemo.tsx b/src/app/demo/[name]/ui/commandDemo.tsx new file mode 100644 index 00000000..e4f951fb --- /dev/null +++ b/src/app/demo/[name]/ui/commandDemo.tsx @@ -0,0 +1,93 @@ +"use client"; + +import React from "react"; +import { + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, + CommandShortcut, +} from "@/components/ui/command"; +import { + mdiCalendarBlankOutline, + mdiCalculator, + mdiCreditCardCheckOutline, + mdiCog, + mdiEmoticonHappyOutline, + mdiAccountOutline, +} from "@mdi/js"; +import Icon from "@mdi/react"; + +const CommandDemo = () => { + const [open, setOpen] = React.useState(false); + + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === "j" && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + setOpen((open) => !open); + } + }; + document.addEventListener("keydown", down); + return () => document.removeEventListener("keydown", down); + }, []); + + return ( +
+
+ <> +

+ Press{" "} + + J + +

+ + + + No results found. + + + + Calendar + + + + Search Emoji + + + + Calculator + + + + + + + Profile + ⌘P + + + + Billing + ⌘B + + + + + Settings + ⌘S + + + + + +
+
+ ); +}; + +export default CommandDemo; diff --git a/src/app/demo/[name]/ui/context-menu.tsx b/src/app/demo/[name]/ui/context-menu.tsx new file mode 100644 index 00000000..32101769 --- /dev/null +++ b/src/app/demo/[name]/ui/context-menu.tsx @@ -0,0 +1,67 @@ +import { + ContextMenu, + ContextMenuCheckboxItem, + ContextMenuContent, + ContextMenuItem, + ContextMenuLabel, + ContextMenuRadioGroup, + ContextMenuRadioItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from "@/components/ui/context-menu"; + +export const contextMenu = { + name: "context-menu", + components: { + Default: ( + + + Right click here + + + + Back + ⌘[ + + + Forward + ⌘] + + + Reload + ⌘R + + + More Tools + + Save Page... + Create Shortcut... + Name Window... + + Developer Tools + + Delete + + + + + Show Bookmarks + + Show Full URLs + + + People + + Pedro Duarte + + Colm Tuite + + + + ), + }, +}; diff --git a/src/app/demo/[name]/ui/date-picker.tsx b/src/app/demo/[name]/ui/date-picker.tsx index 06e3b3b4..420c3c9a 100644 --- a/src/app/demo/[name]/ui/date-picker.tsx +++ b/src/app/demo/[name]/ui/date-picker.tsx @@ -1,39 +1,9 @@ -import { format } from "date-fns"; -import { CalendarIcon } from "lucide-react"; -import * as React from "react"; - -import { Button } from "@/components/ui/button"; -import { Calendar } from "@/components/ui/calendar"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { cn } from "@/lib/utils"; - -const date = new Date(); +import { DatePickerSimple, DatePickerWithRange } from "@/components/ui/date-picker"; export const datePicker = { name: "date-picker", components: { - Default: ( - - - - - - - - - ), + DatePickerSimple: , + DatePickerWithRange: , }, }; diff --git a/src/app/demo/[name]/ui/dialog.tsx b/src/app/demo/[name]/ui/dialog.tsx index a29b261a..f299420a 100644 --- a/src/app/demo/[name]/ui/dialog.tsx +++ b/src/app/demo/[name]/ui/dialog.tsx @@ -1,6 +1,7 @@ import { Button } from "@/components/ui/button"; import { Dialog, + DialogClose, DialogContent, DialogDescription, DialogFooter, @@ -17,7 +18,7 @@ export const dialog = { Default: ( - + @@ -26,33 +27,91 @@ export const dialog = { Make changes to your profile here. Click save when you're done. -
-
- - +
+
+ +
-
- - +
+ +
+ + +
), + Scrollable: ( + + + + + + + Scrollable Content + + This is a dialog with scrollable content. + + +
+

+ Lorem Ipsum +

+ {Array.from({ length: 10 }).map((_, index) => ( +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut + enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor + in reprehenderit in voluptate velit esse cillum dolore eu fugiat + nulla pariatur. Excepteur sint occaecat cupidatat non proident, + sunt in culpa qui officia deserunt mollit anim id est laborum. +

+ ))} +
+
+
+ ), + StickyFooter: ( + + + + + + + Scrollable Content + + This is a dialog with scrollable content. + + +
+

+ Lorem Ipsum +

+ {Array.from({ length: 10 }).map((_, index) => ( +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut + enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor + in reprehenderit in voluptate velit esse cillum dolore eu fugiat + nulla pariatur. Excepteur sint occaecat cupidatat non proident, + sunt in culpa qui officia deserunt mollit anim id est laborum. +

+ ))} +
+ + + + + +
+
+ ), }, }; diff --git a/src/app/demo/[name]/ui/drawer-default.tsx b/src/app/demo/[name]/ui/drawer-default.tsx new file mode 100644 index 00000000..390f33cf --- /dev/null +++ b/src/app/demo/[name]/ui/drawer-default.tsx @@ -0,0 +1,138 @@ +"use client"; + +import * as React from "react"; +import { Minus, Plus } from "lucide-react" +import { Bar, BarChart, ResponsiveContainer } from "recharts"; + +import { Button } from "@/components/ui/button"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; + +const data = [ + { + goal: 400, + }, + { + goal: 300, + }, + { + goal: 200, + }, + { + goal: 300, + }, + { + goal: 200, + }, + { + goal: 278, + }, + { + goal: 189, + }, + { + goal: 239, + }, + { + goal: 300, + }, + { + goal: 200, + }, + { + goal: 278, + }, + { + goal: 189, + }, + { + goal: 349, + }, +] + +export function DrawerDefault() { + const [goal, setGoal] = React.useState(350); + + const onClick = React.useCallback((adjustment: number) => { + setGoal((prevGoal) => Math.max(200, Math.min(400, prevGoal + adjustment))) + }, []); + + return ( + + + + + +
+ + Move Goal + Set your daily activity goal. + +
+
+ +
+
+ {goal} +
+
+ Calories/day +
+
+ +
+
+ + + + + +
+
+ + + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/demo/[name]/ui/drawer-direction.tsx b/src/app/demo/[name]/ui/drawer-direction.tsx new file mode 100644 index 00000000..e115fa09 --- /dev/null +++ b/src/app/demo/[name]/ui/drawer-direction.tsx @@ -0,0 +1,61 @@ +"use client"; + +import * as React from "react"; + +import { Button } from "@/components/ui/button"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; + +const directions = ["top", "right", "bottom", "left"] as const; + +export function DrawerDirections() { + return ( +
+ {directions.map((direction) => ( + + + + + + + Move Goal + + Set your daily activity goal. + + +
+ {Array.from({ length: 10 }).map((_, index) => ( +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed + do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute + irure dolor in reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint occaecat + cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. +

+ ))} +
+ + + + + + +
+
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/app/demo/[name]/ui/drawer-scrollable.tsx b/src/app/demo/[name]/ui/drawer-scrollable.tsx new file mode 100644 index 00000000..bd83169e --- /dev/null +++ b/src/app/demo/[name]/ui/drawer-scrollable.tsx @@ -0,0 +1,52 @@ + +"use client"; + +import * as React from "react"; + +import { Button } from "@/components/ui/button"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; + +export function DrawerScrollableContent() { + return ( + + + + + + + Move Goal + Set your daily activity goal. + +
+

Lorem Ipsum

+ {Array.from({ length: 10 }).map((_, index) => ( +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut + enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum dolore eu fugiat + nulla pariatur. Excepteur sint occaecat cupidatat non proident, + sunt in culpa qui officia deserunt mollit anim id est laborum. +

+ ))} +
+ + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/src/app/demo/[name]/ui/drawer.tsx b/src/app/demo/[name]/ui/drawer.tsx new file mode 100644 index 00000000..74a21b95 --- /dev/null +++ b/src/app/demo/[name]/ui/drawer.tsx @@ -0,0 +1,21 @@ +import { DrawerDefault } from "./drawer-default"; +import { DrawerScrollableContent } from "./drawer-scrollable"; +import { DrawerDirections } from "./drawer-direction"; + + +export const drawer = { + name: "drawer", + components: { + Default: ( + + ), + ScrollableDrawer: ( + + ), + DrawerDirections: ( + + ) + } +}; + + diff --git a/src/app/demo/[name]/ui/dropdown-menu.tsx b/src/app/demo/[name]/ui/dropdown-menu.tsx index b3c7d708..406855d5 100644 --- a/src/app/demo/[name]/ui/dropdown-menu.tsx +++ b/src/app/demo/[name]/ui/dropdown-menu.tsx @@ -1,123 +1,20 @@ import { - Cloud, - CreditCard, - Github, - Keyboard, - LifeBuoy, - LogOut, - Mail, - MessageSquare, - Plus, - PlusCircle, - Settings, - User, - Users, -} from "lucide-react"; - -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuPortal, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; + DropdownMenuAvatarOnly, + DropdownMenuCheckboxes, + DropdownMenuIconColor, + DropdownMenuRadioGroupDemo, + DropdownMenuSimple, + DropdownMenuWithAvatar, +} from "./dropdownMenu-options"; export const dropdownMenu = { name: "dropdown-menu", components: { - Default: ( - - - - - - My Account - - - - - Profile - ⇧⌘P - - - - Billing - ⌘B - - - - Settings - ⌘S - - - - Keyboard shortcuts - ⌘K - - - - - - - Team - - - - New Team - ⌘+T - - - - - Invite users - - - - - - Email - - - - Message - - - - - More... - - - - - - - - GitHub - - - - Support - - - - API - - - - - Log out - ⇧⌘Q - - - - ), + Default: , + DropdownMenuCheckboxes: , + DropdownMenuRadioGroupDemo: , + DropdownMenuWithAvatar: , + DropdownMenuAvatarOnly: , + DropdownMenuIconColor: , }, }; diff --git a/src/app/demo/[name]/ui/dropdownMenu-options.tsx b/src/app/demo/[name]/ui/dropdownMenu-options.tsx new file mode 100644 index 00000000..762a7c68 --- /dev/null +++ b/src/app/demo/[name]/ui/dropdownMenu-options.tsx @@ -0,0 +1,364 @@ +"use client"; + +import * as React from "react"; +import { + mdiAccount, + mdiBell, + mdiChevronDown, + mdiCreditCard, + mdiLogout, + mdiDotsHorizontal, + mdiPencil, + mdiCog, + mdiShare, + mdiStar, + mdiDelete, + mdiCheck, +} from "@mdi/js"; +import Icon from "@mdi/react"; + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +function DropdownMenuSimple() { + return ( + + + + + + My Account + + + Profile + ⇧⌘P + + + Billing + ⌘B + + + Settings + ⌘S + + + Keyboard shortcuts + ⌘K + + + + + Team + + Invite users + + + Email + Message + + More... + + + + + New Team + ⌘+T + + + + GitHub + Support + API + + + Log out + ⇧⌘Q + + + + ); +} + +function DropdownMenuCheckboxes() { + const [showStatusBar, setShowStatusBar] = React.useState(true); + const [showActivityBar, setShowActivityBar] = React.useState(false); + const [showPanel, setShowPanel] = React.useState(false); + + return ( + + + + + + + Account + + Profile + + + Billing + + + Settings + + + + + Appearance + + Status Bar + + + Activity Bar + + + Panel + + + + + + Sign Out + + + + + ); +} + +function DropdownMenuRadioGroupDemo() { + const [position, setPosition] = React.useState("bottom"); + + return ( + + + + + + Panel Position + + + Top + Bottom + + Right + + + + + + ); +} + +function DropdownMenuWithAvatar() { + return ( + + + + + + +
+ + + CN + +
+ shadcn + + shadcn@example.com + +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Sign Out + +
+
+ ); +} + +function DropdownMenuAvatarOnly() { + return ( + + + + + + +
+ + + LR + +
+ leerob + + leerob@example.com + +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Sign Out + +
+
+ ); +} + +function DropdownMenuIconColor() { + return ( + + + + + + + + + Edit + + + + Share + + + + + Delete + + + + + ); +} + +export { + DropdownMenuSimple, + DropdownMenuCheckboxes, + DropdownMenuRadioGroupDemo, + DropdownMenuWithAvatar, + DropdownMenuAvatarOnly, + DropdownMenuIconColor, +}; diff --git a/src/app/demo/[name]/ui/forms/data.ts b/src/app/demo/[name]/ui/forms/data.ts new file mode 100644 index 00000000..d3f7c574 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/data.ts @@ -0,0 +1,39 @@ +import * as zod from "zod"; + +export const defaultValues: FormDataType = { + firstName: "John", + middleName: "", + lastName: "", +}; + +export type FieldDataType = { + id: string; + label: string; + helptext?: string; + required?: boolean; +}; + +export const data: FieldDataType[] = [ + { + id: "firstName", + label: "Firstname", + }, + { + id: "middleName", + label: "Middlename", + }, + { + id: "lastName", + label: "Surname", + required: true, + helptext: "This is your family name", + }, +]; + +export const schema = zod.object({ + firstName: zod.string().max(12), + middleName: zod.string().max(12).optional(), + lastName: zod.string().max(12).nonempty({ message: "Last name is required" }), +}); + +export type FormDataType = zod.infer; diff --git a/src/app/demo/[name]/ui/forms/form.tsx b/src/app/demo/[name]/ui/forms/form.tsx new file mode 100644 index 00000000..37b1c406 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/form.tsx @@ -0,0 +1,20 @@ +import TanstackFormWrapper from "./tanstack/FormWrapper"; +import ReactHookFormWrapper from "./reacthookform/FormWrapper"; + +export const form = { + name: "form", + components: { + ReactHookForm: ( + <> +

React Hook Form

+ + + ), + TanstackForm: ( + <> +

Tanstack Form

+ + + ), + }, +}; diff --git a/src/app/demo/[name]/ui/forms/reacthookform/FormControls.tsx b/src/app/demo/[name]/ui/forms/reacthookform/FormControls.tsx new file mode 100644 index 00000000..217a5d16 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/reacthookform/FormControls.tsx @@ -0,0 +1,26 @@ +"use client"; +import { Button } from "@/components/ui/button"; +import { useFormContext } from "react-hook-form"; + +const FormControls = () => { + const form = useFormContext(); + const { isDirty, isSubmitting } = form.formState; + + return ( +
+ + +
+ ); +}; +export default FormControls; diff --git a/src/app/demo/[name]/ui/forms/reacthookform/FormField.tsx b/src/app/demo/[name]/ui/forms/reacthookform/FormField.tsx new file mode 100644 index 00000000..7137ab12 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/reacthookform/FormField.tsx @@ -0,0 +1,46 @@ +"use client"; + +import * as React from "react"; + +import { Input } from "@/components/ui/input"; +import { + FormDescription, + FormField as ReactFormField, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { FieldDataType } from "../data"; + +const FormField = ({ label, id, helptext, required }: FieldDataType) => { + return ( + { + return ( +
+ + {label} + {required && *} + + + { + field.field.onChange(e.target.value); + }} + /> + +
+ {helptext} +
+ + +
+ ); + }} + /> + ); +}; + +export default FormField; diff --git a/src/app/demo/[name]/ui/forms/reacthookform/FormWrapper.tsx b/src/app/demo/[name]/ui/forms/reacthookform/FormWrapper.tsx new file mode 100644 index 00000000..652a73ab --- /dev/null +++ b/src/app/demo/[name]/ui/forms/reacthookform/FormWrapper.tsx @@ -0,0 +1,49 @@ +"use client"; + +import * as React from "react"; + +import FormField from "./FormField"; +import FormControls from "./FormControls"; +import { useForm } from "react-hook-form"; +import { Form } from "@/components/ui/form"; +import { data, defaultValues, FormDataType, schema } from "../data"; +import { zodResolver } from "@hookform/resolvers/zod"; + +const FormWrapper = () => { + const form = useForm({ + defaultValues: defaultValues, + resolver: zodResolver(schema), + mode: "onSubmit", + }); + + const handleSubmit = async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }; + + return ( +
+ { + event.preventDefault(); + void form.handleSubmit(handleSubmit)(); + }} + > +
+ {data.map((item) => ( + + ))} +
+ + + + + ); +}; + +export default FormWrapper; diff --git a/src/app/demo/[name]/ui/forms/tanstack/FormControls.tsx b/src/app/demo/[name]/ui/forms/tanstack/FormControls.tsx new file mode 100644 index 00000000..5aeb3ab1 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/tanstack/FormControls.tsx @@ -0,0 +1,29 @@ +"use client"; +import { Button } from "@/components/ui/button"; +import { useFormContext } from "@/components/ui/tanstack-form"; + +const FormControls = () => { + const form = useFormContext(); + return ( + [state.isDirty, state.isSubmitting]} + children={([isDirty, isSubmitting]) => ( +
+ + +
+ )} + /> + ); +}; +export default FormControls; diff --git a/src/app/demo/[name]/ui/forms/tanstack/FormField.tsx b/src/app/demo/[name]/ui/forms/tanstack/FormField.tsx new file mode 100644 index 00000000..aae9ca00 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/tanstack/FormField.tsx @@ -0,0 +1,40 @@ +"use client"; + +import * as React from "react"; + +import { Input } from "@/components/ui/input"; +import { FormType, useFormContext } from "@/components/ui/tanstack-form"; +import { FieldDataType, FormDataType } from "../data"; + +const FormField = ({ label, id, helptext }: FieldDataType) => { + const form = useFormContext() as unknown as FormType; + + return ( + { + return ( + + {label} + + { + field.handleChange(e.target.value); + }} + /> + +
+ {helptext} +
+ + +
+ ); + }} + /> + ); +}; + +export default FormField; diff --git a/src/app/demo/[name]/ui/forms/tanstack/FormWrapper.tsx b/src/app/demo/[name]/ui/forms/tanstack/FormWrapper.tsx new file mode 100644 index 00000000..6c95c076 --- /dev/null +++ b/src/app/demo/[name]/ui/forms/tanstack/FormWrapper.tsx @@ -0,0 +1,45 @@ +"use client"; + +import * as React from "react"; + +import { useAppForm } from "@/components/ui/tanstack-form"; +import FormField from "./FormField"; +import FormControls from "./FormControls"; +import { data, defaultValues, schema } from "../data"; + +const TanstackFormWrapper = () => { + const form = useAppForm({ + defaultValues: defaultValues, + onSubmit: async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }, + validators: { + onSubmit: schema, + }, + }); + + return ( + +
{ + event.preventDefault(); + void form.handleSubmit(); + }} + > +
+ {data.map((item) => ( + + ))} +
+ + +
+ ); +}; + +export default TanstackFormWrapper; diff --git a/src/app/demo/[name]/ui/hover-card.tsx b/src/app/demo/[name]/ui/hover-card.tsx new file mode 100644 index 00000000..e1bfcd58 --- /dev/null +++ b/src/app/demo/[name]/ui/hover-card.tsx @@ -0,0 +1,46 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from "@/components/ui/hover-card"; +import { mdiCalendar } from "@mdi/js"; +import Icon from "@mdi/react"; + +export const hoverCard = { + name: "hover-card", + components: { + Default: ( + + + + + +
+ + + VC + +
+

@nextjs

+

+ The React Framework – created and maintained by @vercel. +

+
+ + + Joined December 2021 + +
+
+
+
+
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/input.tsx b/src/app/demo/[name]/ui/input.tsx index 929ab9b2..3db93214 100644 --- a/src/app/demo/[name]/ui/input.tsx +++ b/src/app/demo/[name]/ui/input.tsx @@ -1,29 +1,31 @@ -import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; export const input = { name: "input", components: { - Default: , - Email: , - WithLabel: ( -
- - + Email: ( +
+
), - WithButton: ( -
- - + Text: ( +
+ +
+ ), + Password: ( +
+
), - File: ( -
- - +
+ +
+ ), + Disabled: ( +
+
), }, diff --git a/src/app/demo/[name]/ui/inputOtp.tsx b/src/app/demo/[name]/ui/inputOtp.tsx new file mode 100644 index 00000000..66c04366 --- /dev/null +++ b/src/app/demo/[name]/ui/inputOtp.tsx @@ -0,0 +1,57 @@ +import { Label } from "@/components/ui/label"; +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@/components/ui/inputOtp"; + +export const inputOtp = { + name: "inputOtp", + components: { + Default: ( +
+ + + + + + + + + + + + + + +
+ ), + Pattern: ( +
+ + + + + + + + + + + +
+ ), + // With Spacing + WithSpacing: ( +
+ + + + + + + + + +
+ ), + + }, +}; + \ No newline at end of file diff --git a/src/app/demo/[name]/ui/label.tsx b/src/app/demo/[name]/ui/label.tsx new file mode 100644 index 00000000..d6167d24 --- /dev/null +++ b/src/app/demo/[name]/ui/label.tsx @@ -0,0 +1,14 @@ +import { Checkbox } from "@/components/ui/checkbox"; +import { Label } from "@/components/ui/label"; + +export const label = { + name: "label", + components: { + Default: ( +
+ + +
+ ), + }, +}; diff --git a/src/app/demo/[name]/ui/line-chart.tsx b/src/app/demo/[name]/ui/line-chart.tsx new file mode 100644 index 00000000..85217653 --- /dev/null +++ b/src/app/demo/[name]/ui/line-chart.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { TrendingUp } from "lucide-react"; +import { CartesianGrid, Line, LineChart, XAxis } from "recharts"; + +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/components/ui/chart"; + +export const description = "A multiple line chart"; + +const chartData = [ + { 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 chartConfig = { + desktop: { + label: "Desktop", + color: "var(--chart-1)", + }, + mobile: { + label: "Mobile", + color: "var(--chart-2)", + }, +} satisfies ChartConfig; + +export function LineChartComponent() { + return ( + + + Line Chart - Multiple + January - June 2024 + + + + + + value.slice(0, 3)} + /> + } /> + + + + + + +
+
+
+ Trending up by 5.2% this month +
+
+ Showing total visitors for the last 6 months +
+
+
+
+
+ ); +} diff --git a/src/app/demo/[name]/ui/menu-bar.tsx b/src/app/demo/[name]/ui/menu-bar.tsx index 9a37025b..2d1bf409 100644 --- a/src/app/demo/[name]/ui/menu-bar.tsx +++ b/src/app/demo/[name]/ui/menu-bar.tsx @@ -2,6 +2,7 @@ import { Menubar, MenubarCheckboxItem, MenubarContent, + MenubarGroup, MenubarItem, MenubarMenu, MenubarRadioGroup, @@ -13,98 +14,123 @@ import { MenubarSubTrigger, MenubarTrigger, } from "@/components/ui/menubar"; +import { HelpCircleIcon, SettingsIcon, Trash2Icon } from "lucide-react"; export const menuBar = { name: "menu-bar", components: { Default: ( - - - File - - - New Tab ⌘T - - - New Window ⌘N - - New Incognito Window - - - Share - - Email link - Messages - Notes - - - - - Print... ⌘P - - - - - Edit - - - Undo ⌘Z - - - Redo ⇧⌘Z - - - - Find - - Search the web +
+ + + File + + + New Tab ⌘T + + + New Window ⌘N + + New Incognito Window + + + Share + + Email link + Messages + Notes + + + + + Print... ⌘P + + + + + Edit + + + Undo ⌘Z + + + Redo ⇧⌘Z + + + + Find + + Search the web + + Find... + Find Next + Find Previous + + + + Cut + Copy + Paste + + + + View + + + Always Show Bookmarks Bar + + + Always Show Full URLs + + + + Reload ⌘R + + + Force Reload ⇧⌘R + + + Toggle Fullscreen + + Hide Sidebar + + + + Profiles + + + Andy + Benoit + Luis + + + Edit... + + Add Profile... + + + + More + + + + + Settings + + + + Help + - Find... - Find Next - Find Previous - - - - Cut - Copy - Paste - - - - View - - Always Show Bookmarks Bar - - Always Show Full URLs - - - - Reload ⌘R - - - Force Reload ⇧⌘R - - - Toggle Fullscreen - - Hide Sidebar - - - - Profiles - - - Andy - Benoit - Luis - - - Edit... - - Add Profile... - - - + + + Delete + + + + + +
), }, }; diff --git a/src/app/demo/[name]/ui/multi-calendar.tsx b/src/app/demo/[name]/ui/multi-calendar.tsx index 7aeadd76..4ad480b3 100644 --- a/src/app/demo/[name]/ui/multi-calendar.tsx +++ b/src/app/demo/[name]/ui/multi-calendar.tsx @@ -5,7 +5,7 @@ import type { DateRange } from "react-day-picker"; import { Calendar } from "@/components/ui/calendar"; -export function MultiCalendar() { +export function MultiCalendar({numberOfMonths = 1}: {numberOfMonths?: number}) { const [dateRange, setDateRange] = React.useState({ from: new Date(2025, 5, 9), to: new Date(2025, 5, 26), @@ -17,6 +17,7 @@ export function MultiCalendar() { defaultMonth={dateRange?.from} selected={dateRange} onSelect={setDateRange} + numberOfMonths={numberOfMonths} className="rounded-lg border shadow-sm" /> ); diff --git a/src/app/demo/[name]/ui/navigation-menu.tsx b/src/app/demo/[name]/ui/navigation-menu.tsx new file mode 100644 index 00000000..c134eb2a --- /dev/null +++ b/src/app/demo/[name]/ui/navigation-menu.tsx @@ -0,0 +1,239 @@ +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + navigationMenuTriggerStyle, +} from "@/components/ui/navigation-menu"; +import { + mdiCheckCircleOutline, + mdiCircleOutline, + mdiHelpCircleOutline, +} from "@mdi/js"; +import Icon from "@mdi/react"; +import Link from "next/link"; +import type React from "react"; + +const components: { title: string; href: string; description: string }[] = [ + { + title: "Alert Dialog", + href: "/docs/primitives/alert-dialog", + description: + "A modal dialog that interrupts the user with important content and expects a response.", + }, + { + title: "Hover Card", + href: "/docs/primitives/hover-card", + description: + "For sighted users to preview content available behind a link.", + }, + { + title: "Progress", + href: "/docs/primitives/progress", + description: + "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", + }, + { + title: "Scroll-area", + href: "/docs/primitives/scroll-area", + description: "Visually or semantically separates content.", + }, + { + title: "Tabs", + href: "/docs/primitives/tabs", + description: + "A set of layered sections of content—known as tab panels—that are displayed one at a time.", + }, + { + title: "Tooltip", + href: "/docs/primitives/tooltip", + description: + "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", + }, +]; + +export const navigationMenu = { + name: "navigation-menu", + components: { + Default: ( + + + + Getting Started + +
    +
  • + + +
    + shadcn/ui +
    +

    + Beautifully designed components built with Tailwind CSS. +

    + +
    +
  • + + Re-usable components built using Radix UI and Tailwind CSS. + + + How to install dependencies and structure your app. + + + Styles for headings, paragraphs, lists...etc + +
+
+
+ + + Components + +
    + {components.map((component) => ( + + {component.description} + + ))} +
+
+
+ + + + Documentation + + +
+
+ ), + Secondary: ( + + + + + Documentation + + + + + List + +
    +
  • + + +
    Components
    +
    + Browse all components in the library. +
    + +
    + + +
    Documentation
    +
    + Learn how to use the library. +
    + +
    + + +
    Blog
    +
    + Read our latest blog posts. +
    + +
    +
  • +
+
+
+ + + Simple List + +
    +
  • + + Components + + + Documentation + + + Blocks + +
  • +
+
+
+ + + With Icon + +
    +
  • + + + + Backlog + + + + + + To Do + + + + + + Done + + +
  • +
+
+
+
+
+ ), + }, +}; + +function ListItem({ + title, + children, + href, + ...props +}: React.ComponentPropsWithoutRef<"li"> & { href: string }) { + return ( +
  • + + +
    {title}
    +

    + {children} +

    + +
    +
  • + ); +} diff --git a/src/app/demo/[name]/ui/pagination.tsx b/src/app/demo/[name]/ui/pagination.tsx new file mode 100644 index 00000000..d3091d0f --- /dev/null +++ b/src/app/demo/[name]/ui/pagination.tsx @@ -0,0 +1,43 @@ +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from "@/components/ui/pagination"; + +export const pagination = { + name: "pagination", + components: { + Default: ( +
    + + + + + + + 1 + + + + 2 + + + + 3 + + + + + + + + + +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/pie-chart.tsx b/src/app/demo/[name]/ui/pie-chart.tsx index fdcd4e77..7de1e841 100644 --- a/src/app/demo/[name]/ui/pie-chart.tsx +++ b/src/app/demo/[name]/ui/pie-chart.tsx @@ -58,7 +58,7 @@ export function PieChartComponent() { }, []); return ( - + Pie Chart January - June 2024 diff --git a/src/app/demo/[name]/ui/popover.tsx b/src/app/demo/[name]/ui/popover.tsx new file mode 100644 index 00000000..8888160b --- /dev/null +++ b/src/app/demo/[name]/ui/popover.tsx @@ -0,0 +1,67 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Label } from "@radix-ui/react-label"; + +export const popover = { + name: "popover", + components: { + Default: ( +
    + + + + + +
    +
    +

    Dimensions

    +

    + Set the dimensions for the layer. +

    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/progress.tsx b/src/app/demo/[name]/ui/progress.tsx new file mode 100644 index 00000000..1e30cfef --- /dev/null +++ b/src/app/demo/[name]/ui/progress.tsx @@ -0,0 +1,14 @@ +import { Progress } from "@/components/ui/progress"; + +export const progress = { + name: "Progress", + components: { + Default: ( +
    +
    + +
    +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/radio-group.tsx b/src/app/demo/[name]/ui/radio-group.tsx new file mode 100644 index 00000000..9f3c5d7f --- /dev/null +++ b/src/app/demo/[name]/ui/radio-group.tsx @@ -0,0 +1,62 @@ +import { Label } from "@/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; + +const plans = [ + { + id: "starter", + name: "Starter Plan", + description: + "Perfect for small businesses getting started with our platform", + price: "$10", + }, + { + id: "pro", + name: "Pro Plan", + description: "Advanced features for growing businesses with higher demands", + price: "$20", + }, +]; + +export const radioGroup = { + name: "radio-group", + components: { + Default: ( + +
    + + +
    +
    + + +
    +
    + + +
    +
    + ), + Descriptive: ( + + {plans.map((plan) => ( + + ))} + + ), + }, +}; diff --git a/src/app/demo/[name]/ui/resizable.tsx b/src/app/demo/[name]/ui/resizable.tsx new file mode 100644 index 00000000..d5006a5f --- /dev/null +++ b/src/app/demo/[name]/ui/resizable.tsx @@ -0,0 +1,75 @@ +import { + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from "@/components/ui/resizable"; + +export const resizable = { + name: "resizable", + components: { + Default: ( + + +
    + One +
    +
    + + + + +
    + Two +
    +
    + + +
    + Three +
    +
    +
    +
    +
    + ), + Vertical: ( + + +
    + Header +
    +
    + + +
    + Content +
    +
    +
    + ), + Handle: ( + + +
    + Sidebar +
    +
    + + +
    + Content +
    +
    +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/scroll-area.tsx b/src/app/demo/[name]/ui/scroll-area.tsx new file mode 100644 index 00000000..461a29d6 --- /dev/null +++ b/src/app/demo/[name]/ui/scroll-area.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; + +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; +import { Separator } from "@/components/ui/separator"; + +export const works = [ + { + artist: "Ornella Binni", + art: "https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80", + }, + { + artist: "Tom Byrom", + art: "https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80", + }, + { + artist: "Vladimir Malyav", + art: "https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80", + }, +] as const; + +const tags = Array.from({ length: 50 }).map( + (_, i, a) => `v1.2.0-beta.${a.length - i}` +); + +export const scrollArea = { + name: "scrollarea", + components: { + ScrollAreaVertical: ( +
    + +
    +

    Tags

    + {tags.map((tag) => ( + +
    {tag}
    + +
    + ))} +
    +
    +
    + ), + ScrollAreaHorizontal: ( + +
    + {works.map((artwork) => ( +
    +
    + {`Photo +
    +
    + Photo by{" "} + + {artwork.artist} + +
    +
    + ))} +
    + +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/select.tsx b/src/app/demo/[name]/ui/select.tsx index d2539b49..6634e892 100644 --- a/src/app/demo/[name]/ui/select.tsx +++ b/src/app/demo/[name]/ui/select.tsx @@ -7,6 +7,13 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import Icon from "@mdi/react"; +import { + mdiChartBar, + mdiChartLine, + mdiChartPie, + mdiCircleOutline, +} from "@mdi/js"; export const select = { name: "select", @@ -22,11 +29,78 @@ export const select = { Apple Banana Blueberry - Grapes + + Grapes + Pineapple ), + largeList: ( + + ), + withIcon: ( + + ), + disabled: ( + + ), }, }; diff --git a/src/app/demo/[name]/ui/separator.tsx b/src/app/demo/[name]/ui/separator.tsx index 1467026a..68621016 100644 --- a/src/app/demo/[name]/ui/separator.tsx +++ b/src/app/demo/[name]/ui/separator.tsx @@ -5,19 +5,25 @@ export const separator = { components: { Default: (
    -
    -

    Radix Primitives

    -

    - An open-source UI component library. -

    -
    - -
    -
    Blog
    - -
    Docs
    - -
    Source
    +
    +
    +
    +
    + Tailwind CSS +
    +
    + A utility-first CSS framework. +
    +
    + +
    +
    Blog
    + +
    Docs
    + +
    Source
    +
    +
    ), diff --git a/src/app/demo/[name]/ui/sheet.tsx b/src/app/demo/[name]/ui/sheet.tsx new file mode 100644 index 00000000..551a8faf --- /dev/null +++ b/src/app/demo/[name]/ui/sheet.tsx @@ -0,0 +1,109 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; + +const SheetPopupComponent = ({ side = "left" }: { side?: "top" | "right" | "bottom" | "left" }) => ( + + + + + + + Edit profile + + Make changes to your profile here. Click save when you're + done. + + +
    +

    + Lorem Ipsum +

    + {Array.from({ length: 10 }).map((_, index) => ( +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed + do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation + ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia + deserunt mollit anim id est laborum. +

    + ))} +
    + + + + + + +
    +
    +); + +export const sheet = { + name: "sheet", + components: { + Default: ( +
    + + + + + + + Edit profile + + Make changes to your profile here. Click save when you're + done. + + +
    +
    + + +
    +
    + + +
    +
    + + + + + + +
    +
    +
    + ), + Top: ( + + ), + Bottom: ( + + ), + Left: ( + + ), + Right: ( + + ) + } +}; + + diff --git a/src/app/demo/[name]/ui/sidebar.tsx b/src/app/demo/[name]/ui/sidebar.tsx new file mode 100644 index 00000000..3c9d7d91 --- /dev/null +++ b/src/app/demo/[name]/ui/sidebar.tsx @@ -0,0 +1,42 @@ +import { Sidebar, SidebarContent, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarProvider } from "@/components/ui/sidebar"; +import { mdiHome, mdiAccount, mdiCog } from "@mdi/js"; +import Icon from "@mdi/react"; + +export const sidebar = { + name: "sidebar", + components: { + Default: ( +
    + + + +
    Navigation
    +
    + + + + + + Home + + + + + + Profile + + + + + + Settings + + + + +
    +
    +
    + ), + }, +}; diff --git a/src/app/demo/[name]/ui/skeleton.tsx b/src/app/demo/[name]/ui/skeleton.tsx index e8cce6d6..835a3a65 100644 --- a/src/app/demo/[name]/ui/skeleton.tsx +++ b/src/app/demo/[name]/ui/skeleton.tsx @@ -1,24 +1,31 @@ +import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; export const skeleton = { name: "skeleton", components: { Default: ( -
    - -
    - - +
    + +
    + +
    ), - Card: ( -
    - -
    - - -
    + CardList: ( +
    + {Array.from({ length: 2 }).map((_, index) => ( + + + + + + + + + + ))}
    ), }, diff --git a/src/app/demo/[name]/ui/sonner-toasts.tsx b/src/app/demo/[name]/ui/sonner-toasts.tsx index e1109f64..c8e4e9ac 100644 --- a/src/app/demo/[name]/ui/sonner-toasts.tsx +++ b/src/app/demo/[name]/ui/sonner-toasts.tsx @@ -3,9 +3,11 @@ import { toast } from "sonner"; import { Button } from "@/components/ui/button"; +import Icon from "@mdi/react"; +import { mdiInformation } from "@mdi/js"; export function Sonner() { - return ; + return ; } export function SuccessfulSonner() { @@ -29,10 +31,7 @@ export function WarningSonner() { export function ErrorSonner() { return ( - ); @@ -41,10 +40,11 @@ export function ErrorSonner() { export function ActionSonner() { return (