├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── app ├── api │ └── auth │ │ ├── [auth0] │ │ └── route.ts │ │ ├── mfa │ │ ├── [enrollmentId] │ │ │ └── route.ts │ │ └── route.ts │ │ ├── orgs │ │ ├── [id] │ │ │ ├── connections │ │ │ │ ├── [connection_id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ ├── route.ts │ │ └── sso │ │ │ └── route.ts │ │ └── user │ │ ├── metadata │ │ └── route.ts │ │ └── sessions │ │ ├── [id] │ │ └── route.ts │ │ └── route.ts ├── docs │ ├── components │ │ ├── basic-info │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── mfa-enrollment │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-creator │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-info │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-metadata │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-profile │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-sso │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── organization-switcher │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ └── page.tsx │ │ ├── user-button │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ └── page.tsx │ │ ├── user-metadata │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ ├── user-profile │ │ │ ├── data │ │ │ │ ├── dependencies.ts │ │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ │ └── user-sessions │ │ │ ├── data │ │ │ ├── dependencies.ts │ │ │ └── usage.ts │ │ │ ├── example.tsx │ │ │ └── page.tsx │ ├── page.tsx │ └── rate-limit │ │ ├── data │ │ └── readme.md │ │ └── page.tsx ├── example │ ├── components │ │ └── top-bar.tsx │ ├── create-organization │ │ ├── components │ │ │ ├── create-organizations.tsx │ │ │ └── plan-picker.tsx │ │ └── page.tsx │ ├── dashboard │ │ ├── components │ │ │ ├── dashboard-page.tsx │ │ │ ├── main-nav.tsx │ │ │ ├── overview.tsx │ │ │ └── recent-sales.tsx │ │ └── page.tsx │ ├── organization │ │ ├── components │ │ │ └── profile-page.tsx │ │ └── page.tsx │ └── user-profile │ │ ├── components │ │ └── profile-page.tsx │ │ └── page.tsx ├── favicon.ico ├── globals.css └── layout.tsx ├── components.json ├── components ├── ui │ ├── alert.tsx │ ├── aspect-ratio.tsx │ ├── avatar.tsx │ ├── badge.tsx │ ├── button.tsx │ ├── card.tsx │ ├── command.tsx │ ├── dialog.tsx │ ├── dropdown-menu.tsx │ ├── form.tsx │ ├── input.tsx │ ├── label.tsx │ ├── popover.tsx │ ├── radio-group.tsx │ ├── scroll-area.tsx │ ├── select.tsx │ ├── separator.tsx │ ├── sheet.tsx │ ├── switch.tsx │ ├── tabs.tsx │ ├── toast.tsx │ ├── toaster.tsx │ └── use-toast.ts └── www │ ├── code.tsx │ ├── config.ts │ ├── header.tsx │ ├── icons.tsx │ ├── layouts.tsx │ ├── main-nav.tsx │ ├── mobile-nav.tsx │ ├── page-layout.tsx │ ├── sidebar-nav.tsx │ ├── site-footer.tsx │ ├── tabs.tsx │ ├── theme-provider.tsx │ └── theme.ts ├── lib └── utils.ts ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public └── dashboard.png ├── registry ├── components │ ├── basic-info-form.tsx │ ├── mfa-enrollment.tsx │ ├── organization-create.tsx │ ├── organization-info.tsx │ ├── organization-metadata.tsx │ ├── organization-profile.tsx │ ├── organization-sso.tsx │ ├── organization-switcher.tsx │ ├── user-button.tsx │ ├── user-metadata.tsx │ ├── user-profile.tsx │ └── user-sessions.tsx ├── hooks │ ├── use-mfa-enrollment.ts │ ├── use-organizations.ts │ ├── use-user-metadata.ts │ └── use-user-sessions.ts ├── lib.ts └── routers │ ├── helpers │ └── rate-limit.ts │ ├── mfa.ts │ ├── organizations.ts │ ├── user-metadata.ts │ └── user-sessions.ts ├── scripts └── samples.js ├── tailwind.config.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | /app/docs/components/**/data/code.ts 10 | /app/docs/components/**/data/hooks.ts 11 | /app/docs/components/**/data/routers.ts 12 | /app/docs/rate-limit/**/data/helpers.ts 13 | 14 | # testing 15 | /coverage 16 | 17 | # next.js 18 | /.next/ 19 | /out/ 20 | 21 | # production 22 | /build 23 | 24 | # misc 25 | .DS_Store 26 | *.pem 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | 33 | # local env files 34 | .env*.local 35 | 36 | .env 37 | 38 | # vercel 39 | .vercel 40 | 41 | # typescript 42 | *.tsbuildinfo 43 | next-env.d.ts 44 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode.vscode-typescript-tslint-plugin", 4 | "mikerhyssmith.ts-barrelr", 5 | "mike-co.import-sorter", 6 | "editorconfig.editorconfig", 7 | "msjsdiag.debugger-for-chrome", 8 | "esbenp.prettier-vscode", 9 | "Tobermory.es6-string-html" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.tslint": "explicit" 6 | }, 7 | "editor.defaultFormatter": "esbenp.prettier-vscode", 8 | "eslint.format.enable": true, 9 | "importSorter.importStringConfiguration.trailingComma": "multiLine", 10 | "importSorter.generalConfiguration.sortOnBeforeSave": true, 11 | "importSorter.importStringConfiguration.quoteMark": "double", 12 | "importSorter.importStringConfiguration.maximumNumberOfImportExpressionsPerLine.count": 120, 13 | "importSorter.importStringConfiguration.tabSize": 2, 14 | "importSorter.importStringConfiguration.maximumNumberOfImportExpressionsPerLine.type": "newLineEachExpressionAfterCountLimitExceptIfOnlyOne" 15 | } 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Auth0 projects 2 | 3 | A big welcome and thank you for considering contributing to the Auth0 open source projects. It’s people like you that make it a reality for users in our community. 4 | 5 | Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved. It also communicates that you agree to respect the time of the developers managing and developing these open source projects. In return, we will reciprocate that respect by addressing your issue, assessing changes, and helping you finalize your pull requests. 6 | 7 | ### Quicklinks 8 | 9 | - [Code of Conduct](#code-of-conduct) 10 | - [Getting Started](#getting-started) 11 | - [Making Changes](#making-changes) 12 | - [Opening Issues](#opening-issues) 13 | - [Submitting Pull Requests](#submitting-pull-requests) 14 | - [Getting in Touch](#getting-in-touch) 15 | - [Got a question or problem?](#got-a-question-or-problem?) 16 | - [Vulnerability Reporting](#vulnerability-reporting) 17 | 18 | ## Code of Conduct 19 | 20 | By participating and contributing to this project, you are expected to uphold our [Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). 21 | 22 | ## Getting Started 23 | 24 | ### Making Changes 25 | 26 | When contributing to a repository, the first step is to open an issue in that repository to discuss the change you wish to make before making them. 27 | 28 | ### Opening Issues 29 | 30 | Before you submit a new issue please make sure to search all open and closed issues. It is possible your feature request/issue has already been answered. 31 | 32 | This repo includes an issue template that will walk through all the places to check before submitting your issue here. Please follow the instructions there to make sure this is not a duplicate issue and we have everything we need to research and reproduce this problem. 33 | 34 | ### Submitting Pull Requests 35 | 36 | Same goes for PRs, please search all open and closed PRs before submitting a new one. We do not want duplicate effort. 37 | 38 | In general, we follow the "fork-and-pull" Git workflow. 39 | 40 | - Fork the repository to your own Github account 41 | - Clone the project to your machine 42 | - Create a branch locally with a succinct but descriptive name 43 | - Commit changes to the branch 44 | - Push changes to your fork 45 | - Open a Pull Request in the repository (not your own fork) and follow the PR template so that we can efficiently review the changes. 46 | 47 | NOTE: Be sure to merge the latest from "upstream" before making a pull request. 48 | 49 | ## Getting in touch 50 | 51 | ### Have a question or problem? 52 | 53 | Please do not open issues for general support or usage questions. Instead, join us over in the Auth0Lab community at [discord.gg/XbQpZSF2Ys](https://discord.gg/XbQpZSF2Ys) and post your question there in the correct channel. 54 | 55 | ### Vulnerability Reporting 56 | 57 | Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. 58 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Credits 2 | Some of the components included in UI Components project are licensed under free or open source licenses. We wish to thank the contributors to those projects. 3 | 4 | The following components are licensed under MIT License: 5 | 6 | shadcn-ui v0.8.0 7 | https://github.com/shadcn-ui/ 8 | 9 | api-routes-rate-limit v14.2.3 10 | https://github.com/vercel/next.js/tree/main/examples/api-routes-rate-limit 11 | 12 | MIT License 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining 15 | a copy of this software and associated documentation files (the 16 | "Software"), to deal in the Software without restriction, including 17 | without limitation the rights to use, copy, modify, merge, publish, 18 | distribute, sublicense, and/or sell copies of the Software, and to 19 | permit persons to whom the Software is furnished to do so, subject to 20 | the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be 23 | included in all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | -------------------------------------------------------------------------------- /app/api/auth/[auth0]/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest } from "next/server"; 2 | 3 | import { CLAIMS } from "@/lib/utils"; 4 | import { 5 | enhanceClaimsWithOrganizations, 6 | handleOrganizationsParams, 7 | } from "@/registry/lib"; 8 | import { 9 | handleAuth, 10 | handleCallback, 11 | handleLogin, 12 | Session, 13 | } from "@auth0/nextjs-auth0"; 14 | 15 | export const GET = handleAuth({ 16 | login: handleLogin(handleOrganizationsParams), 17 | callback: handleCallback({ 18 | afterCallback: async (_req: NextRequest, session: Session) => { 19 | return await enhanceClaimsWithOrganizations( 20 | session, 21 | CLAIMS.ORGANIZATIONS 22 | ); 23 | }, 24 | }), 25 | }); 26 | -------------------------------------------------------------------------------- /app/api/auth/mfa/[enrollmentId]/route.ts: -------------------------------------------------------------------------------- 1 | import { handleMFADeleteEnrollment } from "@/registry/routers/mfa"; 2 | 3 | export const DELETE = handleMFADeleteEnrollment(); 4 | -------------------------------------------------------------------------------- /app/api/auth/mfa/route.ts: -------------------------------------------------------------------------------- 1 | import { handleMFAFactorEnrollment, handleMFAFactorsList } from "@/registry/routers/mfa"; 2 | 3 | export const GET = handleMFAFactorsList(); 4 | 5 | export const POST = handleMFAFactorEnrollment(); 6 | -------------------------------------------------------------------------------- /app/api/auth/orgs/[id]/connections/[connection_id]/route.ts: -------------------------------------------------------------------------------- 1 | import { handleDeleteConnection } from "@/registry/routers/organizations"; 2 | 3 | export const DELETE = handleDeleteConnection(); 4 | -------------------------------------------------------------------------------- /app/api/auth/orgs/[id]/connections/route.ts: -------------------------------------------------------------------------------- 1 | import { handleFetchEnabledConnections } from "@/registry/routers/organizations"; 2 | 3 | export const GET = handleFetchEnabledConnections(); 4 | -------------------------------------------------------------------------------- /app/api/auth/orgs/[id]/route.ts: -------------------------------------------------------------------------------- 1 | import { handleFetchOrganization, handleOrganizationUpdate } from "@/registry/routers/organizations"; 2 | 3 | export const GET = handleFetchOrganization(); 4 | 5 | export const PUT = handleOrganizationUpdate(); 6 | -------------------------------------------------------------------------------- /app/api/auth/orgs/route.ts: -------------------------------------------------------------------------------- 1 | import { handleOrganizationCreation } from "@/registry/routers/organizations"; 2 | 3 | export const POST = handleOrganizationCreation({ 4 | enabled_connections: [ 5 | { 6 | connection_id: process.env.ORGANIZATIONS_ENABLED_CONNECTION!, 7 | assign_membership_on_login: false, 8 | }, 9 | ], 10 | }); 11 | -------------------------------------------------------------------------------- /app/api/auth/orgs/sso/route.ts: -------------------------------------------------------------------------------- 1 | import { handleConnectionUpdate, handleSelfService } from "@/registry/routers/organizations"; 2 | 3 | export const POST = handleSelfService({ 4 | clients_to_enable: [process.env.ORGANIZATIONS_CLIENT_TO_ENABLE!], 5 | }); 6 | 7 | export const PUT = handleConnectionUpdate({ 8 | clients_to_enable: [process.env.ORGANIZATIONS_CLIENT_TO_ENABLE!], 9 | }); 10 | -------------------------------------------------------------------------------- /app/api/auth/user/metadata/route.ts: -------------------------------------------------------------------------------- 1 | import { 2 | handleUserMetadataFetch, 3 | handleUserMetadataUpdate, 4 | } from "@/registry/routers/user-metadata"; 5 | 6 | export const GET = handleUserMetadataFetch(); 7 | 8 | export const PUT = handleUserMetadataUpdate(); 9 | -------------------------------------------------------------------------------- /app/api/auth/user/sessions/[id]/route.ts: -------------------------------------------------------------------------------- 1 | import { handleDeleteUserSession } from "@/registry/routers/user-sessions"; 2 | 3 | export const DELETE = handleDeleteUserSession(); 4 | -------------------------------------------------------------------------------- /app/api/auth/user/sessions/route.ts: -------------------------------------------------------------------------------- 1 | import { handleUserSessionsFetch } from "@/registry/routers/user-sessions"; 2 | 3 | export const GET = handleUserSessionsFetch(); 4 | -------------------------------------------------------------------------------- /app/docs/components/basic-info/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add card input label", 3 | ]; 4 | -------------------------------------------------------------------------------- /app/docs/components/basic-info/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ``; 2 | -------------------------------------------------------------------------------- /app/docs/components/basic-info/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import BasicInfoForm from "@/registry/components/basic-info-form"; 4 | 5 | export function Example() { 6 | return ( 7 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /app/docs/components/basic-info/page.tsx: -------------------------------------------------------------------------------- 1 | import Code from "@/components/www/code"; 2 | import { DocsLayout } from "@/components/www/layouts"; 3 | import PageLayout from "@/components/www/page-layout"; 4 | import { DocTabs } from "@/components/www/tabs"; 5 | 6 | import { componentCode } from "./data/code"; 7 | import { componentDependencies } from "./data/dependencies"; 8 | import { componentUsage } from "./data/usage"; 9 | import { Example } from "./example"; 10 | 11 | export default function UserProfile() { 12 | return ( 13 | 14 | 18 | 19 | 20 | 21 | 22 |

26 | 31 | 32 | 33 | Installation 34 |

35 | 36 |
37 |

38 | Install the following dependencies: 39 |

40 | 41 |
42 | {componentDependencies.map((dependency, index) => ( 43 | 44 | ))} 45 |
46 | 47 |

48 | Copy and paste the following code into your project. 49 |

50 | 51 |
52 | 53 |
54 | 55 |

56 | Update the import paths to match your project setup. 57 |

58 |
59 |
60 |
61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /app/docs/components/mfa-enrollment/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add badge button card label separator toast", 3 | ]; 4 | -------------------------------------------------------------------------------- /app/docs/components/mfa-enrollment/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 4 | return { factors, status: 200 }; 5 | }} 6 | onCreate={async (factor: string) => { 7 | return { enrollment: { ticket_url: "https://auth0.com" }, status: 200 }; 8 | }} 9 | onDelete={async (enrollmentId: string) => { 10 | return { status: 200 }; 11 | }} 12 | />`; 13 | -------------------------------------------------------------------------------- /app/docs/components/mfa-enrollment/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import MFAEnrollment from "@/registry/components/mfa-enrollment"; 4 | 5 | export function Example() { 6 | const factors = [ 7 | { 8 | name: "sms", 9 | enabled: true, 10 | enrollmentId: "phone|xxxxxxxxxx", 11 | }, 12 | { name: "push-notification", enabled: true }, 13 | { 14 | name: "otp", 15 | enabled: true, 16 | enrollmentId: "totp|xxxxxxxxxx", 17 | }, 18 | { name: "webauthn-roaming", enabled: true }, 19 | { name: "webauthn-platform", enabled: true }, 20 | ]; 21 | 22 | return ( 23 | { 26 | return { factors, status: 200 }; 27 | }} 28 | onCreate={async (factor: string) => { 29 | alert(`Create ${factor}`); 30 | return { enrollment: { ticket_url: "https://auth0.com" }, status: 200 }; 31 | }} 32 | onDelete={async (enrollmentId: string) => { 33 | alert(`Delete ${enrollmentId}`); 34 | return { status: 200 }; 35 | }} 36 | /> 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /app/docs/components/organization-creator/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add card button form input toast", 3 | "pnpm install zod react-hook-form @hookform/resolvers", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/organization-creator/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 3 | alert("Created!"); 4 | return { status: 200 }; 5 | }} 6 | schema={z.object({ 7 | plan: z.enum(["basic", "starter", "business"], { 8 | required_error: "You need to select a plan.", 9 | }), 10 | })} 11 | defaultValues={{ 12 | plan: "basic", 13 | }} 14 | customFields={[ 15 | ({ form }: any) => { 16 | return ( 17 | ( 21 | 22 | Price Plan 23 | 24 | 36 | 37 | 38 | )} 39 | /> 40 | ); 41 | }, 42 | ]} 43 | />`; 44 | -------------------------------------------------------------------------------- /app/docs/components/organization-creator/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import { 6 | FormControl, 7 | FormField, 8 | FormItem, 9 | FormLabel, 10 | } from "@/components/ui/form"; 11 | import { 12 | Select, 13 | SelectContent, 14 | SelectItem, 15 | SelectTrigger, 16 | SelectValue, 17 | } from "@/components/ui/select"; 18 | import OrganizationCreate from "@/registry/components/organization-create"; 19 | 20 | export default function Example() { 21 | return ( 22 | { 24 | alert("Created!"); 25 | return { status: 200 }; 26 | }} 27 | schema={z.object({ 28 | plan: z.enum(["basic", "starter", "business"], { 29 | required_error: "You need to select a plan.", 30 | }), 31 | })} 32 | defaultValues={{ 33 | plan: "basic", 34 | }} 35 | customFields={[ 36 | ({ form }: any) => { 37 | return ( 38 | ( 42 | 43 | Price Plan 44 | 45 | 57 | 58 | 59 | )} 60 | /> 61 | ); 62 | }, 63 | ]} 64 | /> 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /app/docs/components/organization-info/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add avatar card button form input toast label separator", 3 | "pnpm install zod react-hook-form @hookform/resolvers", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/organization-info/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 3 | return {}; 4 | }} 5 | orgId="xxx" 6 | organization={{ 7 | name: "acme", 8 | display_name: "Acme", 9 | branding: { 10 | logo_url: "https://cdn.auth0.com/avatars/c.png", 11 | }, 12 | }} 13 | />`; 14 | -------------------------------------------------------------------------------- /app/docs/components/organization-info/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import OrganizationInfo from "@/registry/components/organization-info"; 4 | 5 | export function Example() { 6 | return ( 7 | { 9 | return {}; 10 | }} 11 | orgId="xxx" 12 | organization={{ 13 | name: "acme", 14 | display_name: "Acme", 15 | branding: { 16 | logo_url: "https://cdn.auth0.com/avatars/c.png", 17 | }, 18 | }} 19 | /> 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /app/docs/components/organization-info/page.tsx: -------------------------------------------------------------------------------- 1 | import Code from "@/components/www/code"; 2 | import { DocsLayout } from "@/components/www/layouts"; 3 | import PageLayout from "@/components/www/page-layout"; 4 | import { DocTabs } from "@/components/www/tabs"; 5 | 6 | import { componentCode } from "./data/code"; 7 | import { componentDependencies } from "./data/dependencies"; 8 | import { componentHooks } from "./data/hooks"; 9 | import { componentRoutes } from "./data/routers"; 10 | import { componentUsage } from "./data/usage"; 11 | import { Example } from "./example"; 12 | 13 | export default function OrganizationInfo() { 14 | return ( 15 | 16 | 20 | 21 | 22 | 23 | 24 |

28 | 33 | 34 | 35 | Installation 36 |

37 | 38 |
39 |

40 | Install the following dependencies: 41 |

42 | 43 |
44 | {componentDependencies.map((dependency, index) => ( 45 | 46 | ))} 47 |
48 | 49 |

50 | Copy and paste the following code into your project. 51 |

52 | 53 |
54 | 55 |
56 | 57 |

58 | Update the import paths to match your project setup. 59 |

60 |
61 | 62 |

66 | 71 | 72 | 73 | React Hooks 74 |

75 | 76 |
77 | {componentHooks.map((hook, index) => ( 78 |
79 |

80 | {hook.name} 81 |

82 |

{hook.description}

83 |
84 | 85 |
86 |
87 | ))} 88 |
89 | 90 |

94 | 99 | 100 | 101 | NextJS routers 102 |

103 | 104 |
105 | {componentRoutes.map((hook, index) => ( 106 |
107 |

108 | {hook.name} 109 |

110 |

{hook.description}

111 |
112 | 113 |
114 |
115 | ))} 116 |
117 |
118 |
119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /app/docs/components/organization-metadata/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add card button form input select toast label separator", 3 | "pnpm install zod react-hook-form @hookform/resolvers", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/organization-metadata/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 4 | return {}; 5 | }} 6 | onSave={async () => { 7 | alert("Saved!"); 8 | return { status: 200 }; 9 | }} 10 | schema={z.object({ 11 | admin_email: z.string().email(), 12 | billing_email: z.string().email(), 13 | })} 14 | metadata={{ 15 | admin_email: "admin@acme.com", 16 | billing_email: "billing@acme.com", 17 | }} 18 | />`; 19 | -------------------------------------------------------------------------------- /app/docs/components/organization-metadata/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import OrganizationMetadata from "@/registry/components/organization-metadata"; 6 | 7 | export function Example() { 8 | return ( 9 | { 12 | return {}; 13 | }} 14 | onSave={async () => { 15 | alert("Saved!"); 16 | return { status: 200 }; 17 | }} 18 | schema={z.object({ 19 | admin_email: z.string().email(), 20 | billing_email: z.string().email(), 21 | })} 22 | metadata={{ 23 | admin_email: "admin@acme.com", 24 | billing_email: "billing@acme.com", 25 | }} 26 | /> 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /app/docs/components/organization-profile/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add card button dialog form input", 3 | "pnpm install zod react-hook-form @hookform/resolvers", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/organization-profile/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ``; 19 | -------------------------------------------------------------------------------- /app/docs/components/organization-profile/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import OrganizationProfile from "@/registry/components/organization-profile"; 6 | 7 | export function Example() { 8 | return ( 9 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /app/docs/components/organization-profile/page.tsx: -------------------------------------------------------------------------------- 1 | import Code from "@/components/www/code"; 2 | import { DocsLayout } from "@/components/www/layouts"; 3 | import PageLayout from "@/components/www/page-layout"; 4 | import { DocTabs } from "@/components/www/tabs"; 5 | 6 | import { componentCode } from "./data/code"; 7 | import { componentDependencies } from "./data/dependencies"; 8 | import { componentHooks } from "./data/hooks"; 9 | import { componentRoutes } from "./data/routers"; 10 | import { componentUsage } from "./data/usage"; 11 | import { Example } from "./example"; 12 | 13 | export default function OrganizationInfo() { 14 | return ( 15 | 16 | 20 | 21 | 22 | 23 | 24 |

28 | 33 | 34 | 35 | Installation 36 |

37 | 38 |
39 |

40 | Install the following dependencies: 41 |

42 | 43 |
44 | {componentDependencies.map((dependency, index) => ( 45 | 46 | ))} 47 |
48 | 49 |

50 | Copy and paste the following code into your project. 51 |

52 | 53 |
54 | 55 |
56 | 57 |

58 | Update the import paths to match your project setup. 59 |

60 |
61 | 62 |

66 | 71 | 72 | 73 | React Hooks 74 |

75 | 76 |
77 | {componentHooks.map((hook, index) => ( 78 |
79 |

80 | {hook.name} 81 |

82 |

{hook.description}

83 |
84 | 85 |
86 |
87 | ))} 88 |
89 | 90 |

94 | 99 | 100 | 101 | NextJS routers 102 |

103 | 104 |
105 | {componentRoutes.map((hook, index) => ( 106 |
107 |

108 | {hook.name} 109 |

110 |

{hook.description}

111 |
112 | 113 |
114 |
115 | ))} 116 |
117 |
118 |
119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /app/docs/components/organization-sso/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add badge button card form input label separator toaster", 3 | "pnpm install zod react-hook-form @hookform/resolvers lucide-react", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/organization-sso/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 5 | return Promise.resolve({}); 6 | }} 7 | onDelete={() => { 8 | return Promise.resolve({}); 9 | }} 10 | onConfigure={() => { 11 | return Promise.resolve({ selfService: undefined, status: 200 }); 12 | }} 13 | onUpdateConfiguration={() => { 14 | return Promise.resolve({ selfService: undefined, status: 200 }); 15 | }} 16 | />`; 17 | -------------------------------------------------------------------------------- /app/docs/components/organization-sso/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import OrganizationSSO from "@/registry/components/organization-sso"; 4 | 5 | export function Example() { 6 | return ( 7 | { 11 | return Promise.resolve({}); 12 | }} 13 | onDelete={() => { 14 | return Promise.resolve({}); 15 | }} 16 | onConfigure={() => { 17 | return Promise.resolve({ selfService: undefined, status: 200 }); 18 | }} 19 | onUpdateConfiguration={() => { 20 | return Promise.resolve({ selfService: undefined, status: 200 }); 21 | }} 22 | /> 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /app/docs/components/organization-switcher/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add avatar button command popover", 3 | ]; 4 | -------------------------------------------------------------------------------- /app/docs/components/organization-switcher/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ``; 20 | -------------------------------------------------------------------------------- /app/docs/components/organization-switcher/page.tsx: -------------------------------------------------------------------------------- 1 | import Code from "@/components/www/code"; 2 | import { DocsLayout } from "@/components/www/layouts"; 3 | import PageLayout from "@/components/www/page-layout"; 4 | import { DocTabs } from "@/components/www/tabs"; 5 | import OrganizationSwitcher from "@/registry/components/organization-switcher"; 6 | 7 | import { componentCode } from "./data/code"; 8 | import { componentDependencies } from "./data/dependencies"; 9 | import { componentUsage } from "./data/usage"; 10 | 11 | export default function OrganizationSwitcherPage() { 12 | return ( 13 | 14 | 18 | 19 |
20 | 39 |
40 |
41 | 42 |

46 | 51 | 52 | 53 | Installation 54 |

55 | 56 |
57 |

58 | Install the following dependencies: 59 |

60 | 61 |
62 | {componentDependencies.map((dependency, index) => ( 63 | 64 | ))} 65 |
66 | 67 |

68 | Copy and paste the following code into your project. 69 |

70 | 71 |
72 | 73 |
74 | 75 |

76 | Update the import paths to match your project setup. 77 |

78 |
79 |
80 |
81 | ); 82 | } 83 | -------------------------------------------------------------------------------- /app/docs/components/user-button/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add avatar button dropdown-menu", 3 | ]; 4 | -------------------------------------------------------------------------------- /app/docs/components/user-button/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` 2 | 3 | 4 | Theme 5 | 6 | Billing 7 | ⌘B 8 | 9 | 10 | Settings 11 | ⌘S 12 | 13 | 14 | 15 | `; 16 | -------------------------------------------------------------------------------- /app/docs/components/user-button/page.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DropdownMenu, 3 | DropdownMenuGroup, 4 | DropdownMenuItem, 5 | DropdownMenuShortcut, 6 | } from "@/components/ui/dropdown-menu"; 7 | import Code from "@/components/www/code"; 8 | import { DocsLayout } from "@/components/www/layouts"; 9 | import PageLayout from "@/components/www/page-layout"; 10 | import { DocTabs } from "@/components/www/tabs"; 11 | import UserButton from "@/registry/components/user-button"; 12 | 13 | import { componentCode } from "./data/code"; 14 | import { componentDependencies } from "./data/dependencies"; 15 | import { componentUsage } from "./data/usage"; 16 | 17 | export default function UserButtonPage() { 18 | return ( 19 | 20 | 24 | 25 | 34 | 35 | 36 | Theme 37 | 38 | Billing 39 | ⌘B 40 | 41 | 42 | Settings 43 | ⌘S 44 | 45 | 46 | 47 | 48 | 49 | 50 |

54 | 59 | 60 | 61 | Installation 62 |

63 | 64 |
65 |

66 | Install the following dependencies: 67 |

68 | 69 |
70 | {componentDependencies.map((dependency, index) => ( 71 | 72 | ))} 73 |
74 | 75 |

76 | Copy and paste the following code into your project. 77 |

78 | 79 |
80 | 81 |
82 | 83 |

84 | Update the import paths to match your project setup. 85 |

86 |
87 |
88 |
89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /app/docs/components/user-metadata/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add card button form input select toast label separator", 3 | "pnpm install zod react-hook-form @hookform/resolvers", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/user-metadata/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 3 | alert("Saved!"); 4 | }} 5 | schema={z.object({ 6 | address: z.string(), 7 | job_title: z.string(), 8 | language: z.enum(languages), 9 | })} 10 | defaultValues={{ 11 | address: "123 Fake st", 12 | job_title: "Designer", 13 | language: "es-AR", 14 | }} 15 | />`; 16 | -------------------------------------------------------------------------------- /app/docs/components/user-metadata/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import UserMetadata from "@/registry/components/user-metadata"; 6 | 7 | const languages = ["en-US", "es-AR"] as const; 8 | 9 | export function Example() { 10 | return ( 11 | { 13 | return {}; 14 | }} 15 | onSave={async () => { 16 | alert("Saved!"); 17 | return { status: 200 }; 18 | }} 19 | schema={z.object({ 20 | address: z.string(), 21 | job_title: z.string(), 22 | language: z.enum(languages), 23 | })} 24 | metadata={{ 25 | address: "123 Fake st", 26 | job_title: "Designer", 27 | language: "es-AR", 28 | }} 29 | /> 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /app/docs/components/user-profile/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add badge button card dialog form input label separator toast", 3 | "pnpm install zod react-hook-form @hookform/resolvers moment ua-parser-js", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/user-profile/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ``; 30 | -------------------------------------------------------------------------------- /app/docs/components/user-profile/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import UserProfile from "@/registry/components/user-profile"; 6 | 7 | const languages = ["en-US", "es-AR"] as const; 8 | 9 | export function Example() { 10 | return ( 11 | 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /app/docs/components/user-sessions/data/dependencies.ts: -------------------------------------------------------------------------------- 1 | export const componentDependencies = [ 2 | "npx shadcn-ui@latest add badge button card label separator toast", 3 | "pnpm install moment ua-parser-js", 4 | ]; 5 | -------------------------------------------------------------------------------- /app/docs/components/user-sessions/data/usage.ts: -------------------------------------------------------------------------------- 1 | export const componentUsage = ` { 5 | return { sessions, status: 200 }; 6 | }} 7 | onDelete={async (sessionId: string) => { 8 | return { id: sessionId, status: 200 }; 9 | }} 10 | />`; 11 | -------------------------------------------------------------------------------- /app/docs/components/user-sessions/example.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import UserSessions from "@/registry/components/user-sessions"; 6 | 7 | const languages = ["en-US", "es-AR"] as const; 8 | 9 | const user = { 10 | given_name: "John", 11 | family_name: "Doe", 12 | nickname: "john.doe", 13 | name: "John Doe", 14 | email: "john.doe@acme.com", 15 | sub: "auth0|123456789101112", 16 | sid: "123123-123123-123123-123123", 17 | }; 18 | 19 | const sessions = [ 20 | { 21 | id: "123123-123123-123123-123123", 22 | created_at: "2024-08-07T19:06:28.561Z", 23 | updated_at: "2024-08-07T19:06:28.971Z", 24 | authenticated_at: "2024-08-07T19:06:28.561Z", 25 | device: { 26 | initial_user_agent: 27 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", 28 | initial_asn: "394089", 29 | initial_ip: "130.41.100.250", 30 | last_user_agent: 31 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", 32 | last_ip: "130.41.100.250", 33 | last_asn: "394089", 34 | }, 35 | }, 36 | { 37 | id: "321321-321321-321321-321321", 38 | created_at: "2024-08-09T17:41:55.199Z", 39 | updated_at: "2024-08-09T17:41:55.585Z", 40 | authenticated_at: "2024-08-09T17:41:55.199Z", 41 | device: { 42 | initial_user_agent: 43 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:129.0) Gecko/20100101 Firefox/129.0", 44 | initial_ip: "130.41.100.250", 45 | last_user_agent: 46 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:129.0) Gecko/20100101 Firefox/129.0", 47 | last_ip: "130.41.100.250", 48 | }, 49 | }, 50 | ]; 51 | 52 | export function Example() { 53 | return ( 54 | { 58 | return { sessions, status: 200 }; 59 | }} 60 | onDelete={async (sessionId: string) => { 61 | alert(`Delete ${sessionId}`); 62 | return { id: sessionId, status: 200 }; 63 | }} 64 | /> 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /app/docs/page.tsx: -------------------------------------------------------------------------------- 1 | import { AlertCircle } from "lucide-react"; 2 | 3 | import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; 4 | import { DocsLayout } from "@/components/www/layouts"; 5 | import PageLayout from "@/components/www/page-layout"; 6 | 7 | export default function Docs() { 8 | return ( 9 | 10 | 15 | 16 | 17 | Important 18 | 19 | The UI components provided from the experimental{" "} 20 | 26 | Auth0Lab 27 | {" "} 28 | library may not remain available or be incorporated into the Auth0 29 | platform. The Auth0Lab UI components are community supported and are 30 | not directly supported by Auth0 by Okta. All questions should be 31 | directed to the open source{" "} 32 | 38 | repository 39 | {" "} 40 | or the{" "} 41 | 47 | Auth0Lab discord 48 | 49 | . 50 | 51 | 52 |
53 |

54 | The goal of this project is to deliver reusable UI components that 55 | help customers build high-quality interfaces efficiently. These 56 | self-contained pieces of code can be easily integrated into existing 57 | projects, allowing for customization and extension as needed. 58 |

59 |
60 |
    61 |
  • 62 | Code ownership: Take ownership of the UI 63 | components code, just like you would with any other code in 64 | their project. 65 |
  • 66 |
  • 67 | Customization: Modify the pre-built components 68 | to fit your specific needs and branding. This might involve 69 | changing colors, fonts, or layouts, or adding custom 70 | functionality. 71 |
  • 72 |
  • 73 | Integration: Integrate the UI components into 74 | your existing codebase. 75 |
  • 76 |
  • 77 | Version control: Manage the UI components code 78 | alongside your codebase. 79 |
  • 80 |
81 |
82 | 83 |

87 | 92 | 93 | 94 | Notes 95 |

96 |
97 | The UI components were designed specifically for use with{" "} 98 | 104 | React 105 | {" "} 106 | applications. They are built on top of{" "} 107 | 113 | Shadcn 114 | 115 | , a powerful collection that provides reusable components you can 116 | easily integrate into your apps. Our UI components follow the same 117 | philosophy: simply copy and paste them to customize them for your 118 | specific app. 119 |
120 |
121 |
122 |
123 | ); 124 | } 125 | -------------------------------------------------------------------------------- /app/docs/rate-limit/data/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-lab/a0-components/1f303e5d4fdcb3e9a61c299c2d4cea7dc142e603/app/docs/rate-limit/data/readme.md -------------------------------------------------------------------------------- /app/docs/rate-limit/page.tsx: -------------------------------------------------------------------------------- 1 | import Code from "@/components/www/code"; 2 | import { DocsLayout } from "@/components/www/layouts"; 3 | import PageLayout from "@/components/www/page-layout"; 4 | 5 | import { helpers } from "./data/helpers"; 6 | 7 | export default function Docs() { 8 | return ( 9 | 10 | 15 |

16 | UI Components functionality are built on top of{" "} 17 | 23 | Auth0 Management API 24 | 25 | , which has rate limits based on subscription plans. Please refer to{" "} 26 | 32 | Auth0 Rate Limits 33 | {" "} 34 | for details and learn how to utilize them in your application. 35 |

36 |

37 | The Reack Hooks and the NextJS Routers we provide have a basic 38 | built-in rate limit handling mechanism. You can use the helpers we 39 | provide to implement more advanced rate limit handling. 40 |

41 |

45 | 50 | 51 | 52 | Helpers 53 |

54 |
55 | {helpers.map((helper, index) => ( 56 |
57 |

58 | {helper.name} 59 |

60 |

{helper.description}

61 |
62 | 63 |
64 |
65 | ))} 66 |
67 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /app/example/components/top-bar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState } from "react"; 4 | 5 | import { 6 | DropdownMenu, 7 | DropdownMenuGroup, 8 | DropdownMenuItem, 9 | DropdownMenuShortcut, 10 | } from "@/components/ui/dropdown-menu"; 11 | import { CLAIMS } from "@/lib/utils"; 12 | import OrganizationSwitcher from "@/registry/components/organization-switcher"; 13 | import UserButton from "@/registry/components/user-button"; 14 | import { Claims } from "@auth0/nextjs-auth0"; 15 | 16 | import { MainNav } from "../dashboard/components/main-nav"; 17 | 18 | export default function TopBar({ user }: { user: Claims }) { 19 | const [orgsDot, setOrgsDot] = useState(true); 20 | const [userDot, setUserDot] = useState(true); 21 | 22 | function handleOrgsDot() { 23 | setOrgsDot(false); 24 | } 25 | 26 | function handleUserDot() { 27 | setUserDot(false); 28 | } 29 | 30 | return ( 31 |
32 |
33 |
34 | {orgsDot && ( 35 | 36 | 37 | 38 | 39 | )} 40 | 41 | 51 |
52 | 53 | 54 | 55 |
59 | {userDot && ( 60 | 61 | 62 | 63 | 64 | )} 65 | 66 | 67 | 68 | 69 | {user.org_id && ( 70 | 71 | 72 | Organization 73 | ⌘O 74 | 75 | 76 | )} 77 | 78 | 79 | Profile 80 | ⌘P 81 | 82 | 83 | 84 | 85 | 86 |
87 |
88 |
89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /app/example/create-organization/components/create-organizations.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { usePathname, useRouter } from "next/navigation"; 4 | import { z } from "zod"; 5 | 6 | import OrganizationCreate, { 7 | OrganizationCreationResponse, 8 | } from "@/registry/components/organization-create"; 9 | import useOrganizations from "@/registry/hooks/use-organizations"; 10 | 11 | import { PlanPicker } from "./plan-picker"; 12 | 13 | export function CreateOrganizationPage() { 14 | const router = useRouter(); 15 | const pathname = usePathname(); 16 | const { createOrganization } = useOrganizations(); 17 | 18 | async function handleOnCreate(organization: OrganizationCreationResponse) { 19 | const response = await createOrganization(organization); 20 | 21 | if (response.organization) { 22 | router.push( 23 | `/api/auth/login?organization=${response.organization.id}&returnTo=${pathname}` 24 | ); 25 | } 26 | 27 | return response; 28 | } 29 | 30 | return ( 31 | { 43 | return ; 44 | }, 45 | ]} 46 | > 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /app/example/create-organization/components/plan-picker.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { CheckSquare2 } from "lucide-react"; 4 | 5 | import { 6 | FormControl, 7 | FormDescription, 8 | FormField, 9 | FormItem, 10 | FormLabel, 11 | FormMessage, 12 | } from "@/components/ui/form"; 13 | import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; 14 | 15 | type PlanCardProps = { 16 | name: string; 17 | price: string; 18 | features: string[]; 19 | selected: boolean; 20 | }; 21 | 22 | type PlanItemProps = PlanCardProps & { 23 | value: string; 24 | field: any; 25 | }; 26 | 27 | const PlanCard = ({ name, price, features, selected }: PlanCardProps) => { 28 | return ( 29 |
34 |

{name}

35 | 36 |
37 |
38 | ${price} 39 | 40 | per Month / User 41 | 42 |
43 |
44 | 45 |
46 | This includes: 47 |
    48 | {features.map((feature: string) => ( 49 |
  • 53 |
    54 | 55 |
    56 | {feature} 57 |
  • 58 | ))} 59 |
60 |
61 |
62 | ); 63 | }; 64 | 65 | const PlanItem = ({ value, field, name, price, features }: PlanItemProps) => { 66 | return ( 67 | <> 68 | 72 | 78 | 79 | ); 80 | }; 81 | 82 | export function PlanPicker({ form }: { form: any }) { 83 | return ( 84 | ( 88 | 89 | Price Plan 90 | 91 | 99 | 100 | 101 | 109 | 110 | 111 | 112 | 113 | 125 | 126 | 127 | 128 | 129 | 141 | 142 | 143 | 144 | 145 | 146 | Choose a price plan for your organization. 147 | 148 | 149 | 150 | )} 151 | /> 152 | ); 153 | } 154 | -------------------------------------------------------------------------------- /app/example/create-organization/page.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronLeftIcon } from "lucide-react"; 2 | 3 | import { ExamplesLayout } from "@/components/www/layouts"; 4 | import { getSession } from "@auth0/nextjs-auth0"; 5 | 6 | import TopBar from "../components/top-bar"; 7 | import { CreateOrganizationPage } from "./components/create-organizations"; 8 | 9 | export default async function CreateOrganization() { 10 | const session = await getSession(); 11 | 12 | return ( 13 | 14 |
15 | {session && } 16 |
17 |
18 | 27 |
28 | 29 |
30 |
31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /app/example/dashboard/components/main-nav.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export function MainNav({ 6 | className, 7 | ...props 8 | }: React.HTMLAttributes) { 9 | return ( 10 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /app/example/dashboard/components/overview.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis } from "recharts"; 4 | 5 | const data = [ 6 | { 7 | name: "Jan", 8 | total: Math.floor(Math.random() * 5000) + 1000, 9 | }, 10 | { 11 | name: "Feb", 12 | total: Math.floor(Math.random() * 5000) + 1000, 13 | }, 14 | { 15 | name: "Mar", 16 | total: Math.floor(Math.random() * 5000) + 1000, 17 | }, 18 | { 19 | name: "Apr", 20 | total: Math.floor(Math.random() * 5000) + 1000, 21 | }, 22 | { 23 | name: "May", 24 | total: Math.floor(Math.random() * 5000) + 1000, 25 | }, 26 | { 27 | name: "Jun", 28 | total: Math.floor(Math.random() * 5000) + 1000, 29 | }, 30 | { 31 | name: "Jul", 32 | total: Math.floor(Math.random() * 5000) + 1000, 33 | }, 34 | { 35 | name: "Aug", 36 | total: Math.floor(Math.random() * 5000) + 1000, 37 | }, 38 | { 39 | name: "Sep", 40 | total: Math.floor(Math.random() * 5000) + 1000, 41 | }, 42 | { 43 | name: "Oct", 44 | total: Math.floor(Math.random() * 5000) + 1000, 45 | }, 46 | { 47 | name: "Nov", 48 | total: Math.floor(Math.random() * 5000) + 1000, 49 | }, 50 | { 51 | name: "Dec", 52 | total: Math.floor(Math.random() * 5000) + 1000, 53 | }, 54 | ]; 55 | 56 | export function Overview() { 57 | return ( 58 | 59 | 60 | 67 | `$${value}`} 73 | /> 74 | 80 | 81 | 82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /app/example/dashboard/components/recent-sales.tsx: -------------------------------------------------------------------------------- 1 | import { Avatar, AvatarFallback } from "@/components/ui/avatar"; 2 | 3 | export function RecentSales() { 4 | return ( 5 |
6 |
7 | 8 | OM 9 | 10 |
11 |

Olivia Martin

12 |

13 | olivia.martin@email.com 14 |

15 |
16 |
+$1,999.00
17 |
18 |
19 | 20 | JL 21 | 22 |
23 |

Jackson Lee

24 |

jackson.lee@email.com

25 |
26 |
+$39.00
27 |
28 |
29 | 30 | IN 31 | 32 |
33 |

Isabella Nguyen

34 |

35 | isabella.nguyen@email.com 36 |

37 |
38 |
+$299.00
39 |
40 |
41 | 42 | WK 43 | 44 |
45 |

William Kim

46 |

will@email.com

47 |
48 |
+$99.00
49 |
50 |
51 | 52 | SD 53 | 54 |
55 |

Sofia Davis

56 |

sofia.davis@email.com

57 |
58 |
+$39.00
59 |
60 |
61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /app/example/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | import { ExamplesLayout } from "@/components/www/layouts"; 2 | import { getSession } from "@auth0/nextjs-auth0"; 3 | 4 | import DashboardPage from "./components/dashboard-page"; 5 | 6 | export default async function Dashboard() { 7 | const session = await getSession(); 8 | 9 | return ( 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /app/example/organization/components/profile-page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import OrganizationProfile from "@/registry/components/organization-profile"; 6 | import { Claims } from "@auth0/nextjs-auth0"; 7 | 8 | export function ProfilePage({ user }: { user: Claims }) { 9 | return ( 10 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /app/example/organization/page.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronLeftIcon } from "lucide-react"; 2 | 3 | import { ExamplesLayout } from "@/components/www/layouts"; 4 | import { getSession } from "@auth0/nextjs-auth0"; 5 | 6 | import TopBar from "../components/top-bar"; 7 | import { ProfilePage } from "./components/profile-page"; 8 | 9 | export default async function Profile() { 10 | const session = await getSession(); 11 | const user = session!.user; 12 | 13 | return ( 14 | 15 |
16 | {session && } 17 |
18 |
19 | 28 |
29 | 30 |
31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /app/example/user-profile/components/profile-page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { z } from "zod"; 4 | 5 | import UserProfile from "@/registry/components/user-profile"; 6 | import { Claims } from "@auth0/nextjs-auth0"; 7 | 8 | const languages = ["en-US", "es-AR"] as const; 9 | 10 | export function ProfilePage({ user }: { user: Claims }) { 11 | return ( 12 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /app/example/user-profile/page.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronLeftIcon } from "lucide-react"; 2 | 3 | import { ExamplesLayout } from "@/components/www/layouts"; 4 | import { getSession } from "@auth0/nextjs-auth0"; 5 | 6 | import TopBar from "../components/top-bar"; 7 | import { ProfilePage } from "./components/profile-page"; 8 | 9 | export default async function Profile() { 10 | const session = await getSession(); 11 | const user = session!.user; 12 | 13 | return ( 14 | 15 |
16 | {session && } 17 |
18 |
19 | 28 |
29 | 30 |
31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0-lab/a0-components/1f303e5d4fdcb3e9a61c299c2d4cea7dc142e603/app/favicon.ico -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 20 14.3% 4.1%; 9 | --card: 0 0% 100%; 10 | --card-foreground: 20 14.3% 4.1%; 11 | --popover: 0 0% 100%; 12 | --popover-foreground: 20 14.3% 4.1%; 13 | --primary: 215 100% 42%; 14 | --primary-foreground: 60 9.1% 97.8%; 15 | --secondary: 60 4.8% 95.9%; 16 | --secondary-foreground: 24 9.8% 10%; 17 | --muted: 60 4.8% 95.9%; 18 | --muted-foreground: 25 5.3% 44.7%; 19 | --accent: 60 4.8% 95.9%; 20 | --accent-foreground: 24 9.8% 10%; 21 | --destructive: 0 84.2% 60.2%; 22 | --destructive-foreground: 60 9.1% 97.8%; 23 | --border: 20 5.9% 90%; 24 | --input: 20 5.9% 90%; 25 | --ring: 24.6 95% 53.1%; 26 | --radius: 0.3125rem; 27 | } 28 | 29 | .dark { 30 | --background: 20 14.3% 4.1%; 31 | --foreground: 60 9.1% 97.8%; 32 | --card: 20 14.3% 4.1%; 33 | --card-foreground: 60 9.1% 97.8%; 34 | --popover: 20 14.3% 4.1%; 35 | --popover-foreground: 60 9.1% 97.8%; 36 | --primary: 20.5 90.2% 48.2%; 37 | --primary-foreground: 60 9.1% 97.8%; 38 | --secondary: 12 6.5% 15.1%; 39 | --secondary-foreground: 60 9.1% 97.8%; 40 | --muted: 12 6.5% 15.1%; 41 | --muted-foreground: 24 5.4% 63.9%; 42 | --accent: 12 6.5% 15.1%; 43 | --accent-foreground: 60 9.1% 97.8%; 44 | --destructive: 0 72.2% 50.6%; 45 | --destructive-foreground: 60 9.1% 97.8%; 46 | --border: 12 6.5% 15.1%; 47 | --input: 12 6.5% 15.1%; 48 | --ring: 20.5 90.2% 48.2%; 49 | } 50 | } 51 | 52 | @layer base { 53 | :root { 54 | --background: 0 0% 100%; 55 | --foreground: 222.2 84% 4.9%; 56 | 57 | --card: 0 0% 100%; 58 | --card-foreground: 222.2 84% 4.9%; 59 | 60 | --popover: 0 0% 100%; 61 | --popover-foreground: 222.2 84% 4.9%; 62 | 63 | --primary: 222.2 47.4% 11.2%; 64 | --primary-foreground: 210 40% 98%; 65 | 66 | --secondary: 210 40% 96.1%; 67 | --secondary-foreground: 222.2 47.4% 11.2%; 68 | 69 | --muted: 210 40% 96.1%; 70 | --muted-foreground: 215.4 16.3% 46.9%; 71 | 72 | --accent: 210 40% 96.1%; 73 | --accent-foreground: 222.2 47.4% 11.2%; 74 | 75 | --destructive: 0 84.2% 60.2%; 76 | --destructive-foreground: 210 40% 98%; 77 | 78 | --border: 214.3 31.8% 91.4%; 79 | --input: 214.3 31.8% 91.4%; 80 | --ring: 222.2 84% 4.9%; 81 | 82 | --radius: 0.5rem; 83 | } 84 | 85 | .dark { 86 | --background: 222.2 84% 4.9%; 87 | --foreground: 210 40% 98%; 88 | 89 | --card: 222.2 84% 4.9%; 90 | --card-foreground: 210 40% 98%; 91 | 92 | --popover: 222.2 84% 4.9%; 93 | --popover-foreground: 210 40% 98%; 94 | 95 | --primary: 210 40% 98%; 96 | --primary-foreground: 222.2 47.4% 11.2%; 97 | 98 | --secondary: 217.2 32.6% 17.5%; 99 | --secondary-foreground: 210 40% 98%; 100 | 101 | --muted: 217.2 32.6% 17.5%; 102 | --muted-foreground: 215 20.2% 65.1%; 103 | 104 | --accent: 217.2 32.6% 17.5%; 105 | --accent-foreground: 210 40% 98%; 106 | 107 | --destructive: 0 62.8% 30.6%; 108 | --destructive-foreground: 210 40% 98%; 109 | 110 | --border: 217.2 32.6% 17.5%; 111 | --input: 217.2 32.6% 17.5%; 112 | --ring: 212.7 26.8% 83.9%; 113 | } 114 | } 115 | 116 | @layer base { 117 | * { 118 | @apply border-border; 119 | } 120 | body { 121 | @apply bg-background text-foreground; 122 | } 123 | } 124 | 125 | body { 126 | counter-reset: step; 127 | } 128 | 129 | .steps > h3 { 130 | counter-increment: step; 131 | } 132 | 133 | .steps > h3:before { 134 | position: absolute; 135 | display: inline-flex; 136 | height: 2.25rem; 137 | width: 2.25rem; 138 | align-items: center; 139 | justify-content: center; 140 | border-radius: 9999px; 141 | border-width: 4px; 142 | border-color: hsl(var(--background)); 143 | background-color: hsl(var(--muted)); 144 | text-align: center; 145 | text-indent: -1px; 146 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 147 | Liberation Mono, Courier New, monospace; 148 | font-size: 1rem; 149 | line-height: 1.5rem; 150 | font-weight: 500; 151 | margin-left: -50px; 152 | margin-top: -4px; 153 | content: counter(step); 154 | } 155 | 156 | .code-container button { 157 | display: inline !important; 158 | } 159 | 160 | .code-container span { 161 | padding: 0 !important; 162 | } 163 | 164 | @media (max-width: 640px) { 165 | .container { 166 | @apply px-4; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | import { Metadata } from "next"; 4 | import { Inter } from "next/font/google"; 5 | 6 | import { SiteHeader } from "@/components/www/header"; 7 | import { SiteFooter } from "@/components/www/site-footer"; 8 | import { ThemeProvider } from "@/components/www/theme-provider"; 9 | import { cn } from "@/lib/utils"; 10 | import { UserProvider } from "@auth0/nextjs-auth0/client"; 11 | 12 | const inter = Inter({ subsets: ["latin"] }); 13 | 14 | export const metadata: Metadata = { 15 | title: "Auth0 Lab - UI Components", 16 | description: 17 | "UI components provide a solid foundation for developing robust and user-friendly identity-related features in applications.", 18 | }; 19 | 20 | export default async function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 28 | 34 | 40 | 41 | {children} 42 | 43 | 44 | 45 | 46 | 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /components/ui/alert.tsx: -------------------------------------------------------------------------------- 1 | import { cva, VariantProps } from "class-variance-authority"; 2 | import * as React from "react"; 3 | 4 | import { cn } from "@/lib/utils"; 5 | 6 | const alertVariants = cva( 7 | "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", 8 | { 9 | variants: { 10 | variant: { 11 | default: "bg-background text-foreground", 12 | destructive: 13 | "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", 14 | warning: 15 | "border-yellow-400/50 text-warning dark:border-yellow-400 [&>svg]:text-warning bg-yellow-50 ", 16 | }, 17 | }, 18 | defaultVariants: { 19 | variant: "default", 20 | }, 21 | } 22 | ); 23 | 24 | const Alert = React.forwardRef< 25 | HTMLDivElement, 26 | React.HTMLAttributes & VariantProps 27 | >(({ className, variant, ...props }, ref) => ( 28 |
34 | )); 35 | Alert.displayName = "Alert"; 36 | 37 | const AlertTitle = React.forwardRef< 38 | HTMLParagraphElement, 39 | React.HTMLAttributes 40 | >(({ className, ...props }, ref) => ( 41 |
46 | )); 47 | AlertTitle.displayName = "AlertTitle"; 48 | 49 | const AlertDescription = React.forwardRef< 50 | HTMLParagraphElement, 51 | React.HTMLAttributes 52 | >(({ className, ...props }, ref) => ( 53 |
58 | )); 59 | AlertDescription.displayName = "AlertDescription"; 60 | 61 | export { Alert, AlertTitle, AlertDescription }; 62 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root 6 | 7 | export { AspectRatio } 8 | -------------------------------------------------------------------------------- /components/ui/avatar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AvatarPrimitive from "@radix-ui/react-avatar" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Avatar = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 20 | )) 21 | Avatar.displayName = AvatarPrimitive.Root.displayName 22 | 23 | const AvatarImage = React.forwardRef< 24 | React.ElementRef, 25 | React.ComponentPropsWithoutRef 26 | >(({ className, ...props }, ref) => ( 27 | 32 | )) 33 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 34 | 35 | const AvatarFallback = React.forwardRef< 36 | React.ElementRef, 37 | React.ComponentPropsWithoutRef 38 | >(({ className, ...props }, ref) => ( 39 | 47 | )) 48 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 49 | 50 | export { Avatar, AvatarImage, AvatarFallback } 51 | -------------------------------------------------------------------------------- /components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | } 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 |
17 | )) 18 | Card.displayName = "Card" 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 |
29 | )) 30 | CardHeader.displayName = "CardHeader" 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 |

44 | )) 45 | CardTitle.displayName = "CardTitle" 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |

56 | )) 57 | CardDescription.displayName = "CardDescription" 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 |

64 | )) 65 | CardContent.displayName = "CardContent" 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 |
76 | )) 77 | CardFooter.displayName = "CardFooter" 78 | 79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 80 | -------------------------------------------------------------------------------- /components/ui/command.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Command as CommandPrimitive } from "cmdk"; 4 | import { Search } from "lucide-react"; 5 | import * as React from "react"; 6 | 7 | import { Dialog, DialogContent } from "@/components/ui/dialog"; 8 | import { cn } from "@/lib/utils"; 9 | import { DialogProps } from "@radix-ui/react-dialog"; 10 | 11 | const Command = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef 14 | >(({ className, ...props }, ref) => ( 15 | 23 | )); 24 | Command.displayName = CommandPrimitive.displayName; 25 | 26 | interface CommandDialogProps extends DialogProps {} 27 | 28 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => { 29 | return ( 30 | 31 | 32 | 33 | {children} 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | const CommandInput = React.forwardRef< 41 | React.ElementRef, 42 | React.ComponentPropsWithoutRef 43 | >(({ className, ...props }, ref) => ( 44 |
45 | 46 | 54 |
55 | )); 56 | 57 | CommandInput.displayName = CommandPrimitive.Input.displayName; 58 | 59 | const CommandList = React.forwardRef< 60 | React.ElementRef, 61 | React.ComponentPropsWithoutRef 62 | >(({ className, ...props }, ref) => ( 63 | 68 | )); 69 | 70 | CommandList.displayName = CommandPrimitive.List.displayName; 71 | 72 | const CommandEmpty = React.forwardRef< 73 | React.ElementRef, 74 | React.ComponentPropsWithoutRef 75 | >((props, ref) => ( 76 | 81 | )); 82 | 83 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName; 84 | 85 | const CommandGroup = React.forwardRef< 86 | React.ElementRef, 87 | React.ComponentPropsWithoutRef 88 | >(({ className, ...props }, ref) => ( 89 | 97 | )); 98 | 99 | CommandGroup.displayName = CommandPrimitive.Group.displayName; 100 | 101 | const CommandSeparator = React.forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 110 | )); 111 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName; 112 | 113 | const CommandItem = React.forwardRef< 114 | React.ElementRef, 115 | React.ComponentPropsWithoutRef 116 | >(({ className, ...props }, ref) => ( 117 | 125 | )); 126 | 127 | CommandItem.displayName = CommandPrimitive.Item.displayName; 128 | 129 | const CommandShortcut = ({ 130 | className, 131 | ...props 132 | }: React.HTMLAttributes) => { 133 | return ( 134 | 141 | ); 142 | }; 143 | CommandShortcut.displayName = "CommandShortcut"; 144 | 145 | export { 146 | Command, 147 | CommandDialog, 148 | CommandInput, 149 | CommandList, 150 | CommandEmpty, 151 | CommandGroup, 152 | CommandItem, 153 | CommandShortcut, 154 | CommandSeparator, 155 | }; 156 | -------------------------------------------------------------------------------- /components/ui/dialog.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as DialogPrimitive from "@radix-ui/react-dialog" 5 | import { X } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Dialog = DialogPrimitive.Root 10 | 11 | const DialogTrigger = DialogPrimitive.Trigger 12 | 13 | const DialogPortal = DialogPrimitive.Portal 14 | 15 | const DialogClose = DialogPrimitive.Close 16 | 17 | const DialogOverlay = React.forwardRef< 18 | React.ElementRef, 19 | React.ComponentPropsWithoutRef 20 | >(({ className, ...props }, ref) => ( 21 | 29 | )) 30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName 31 | 32 | const DialogContent = React.forwardRef< 33 | React.ElementRef, 34 | React.ComponentPropsWithoutRef 35 | >(({ className, children, ...props }, ref) => ( 36 | 37 | 38 | 46 | {children} 47 | 48 | 49 | Close 50 | 51 | 52 | 53 | )) 54 | DialogContent.displayName = DialogPrimitive.Content.displayName 55 | 56 | const DialogHeader = ({ 57 | className, 58 | ...props 59 | }: React.HTMLAttributes) => ( 60 |
67 | ) 68 | DialogHeader.displayName = "DialogHeader" 69 | 70 | const DialogFooter = ({ 71 | className, 72 | ...props 73 | }: React.HTMLAttributes) => ( 74 |
81 | ) 82 | DialogFooter.displayName = "DialogFooter" 83 | 84 | const DialogTitle = React.forwardRef< 85 | React.ElementRef, 86 | React.ComponentPropsWithoutRef 87 | >(({ className, ...props }, ref) => ( 88 | 96 | )) 97 | DialogTitle.displayName = DialogPrimitive.Title.displayName 98 | 99 | const DialogDescription = React.forwardRef< 100 | React.ElementRef, 101 | React.ComponentPropsWithoutRef 102 | >(({ className, ...props }, ref) => ( 103 | 108 | )) 109 | DialogDescription.displayName = DialogPrimitive.Description.displayName 110 | 111 | export { 112 | Dialog, 113 | DialogPortal, 114 | DialogOverlay, 115 | DialogClose, 116 | DialogTrigger, 117 | DialogContent, 118 | DialogHeader, 119 | DialogFooter, 120 | DialogTitle, 121 | DialogDescription, 122 | } 123 | -------------------------------------------------------------------------------- /components/ui/form.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as LabelPrimitive from "@radix-ui/react-label" 3 | import { Slot } from "@radix-ui/react-slot" 4 | import { 5 | Controller, 6 | ControllerProps, 7 | FieldPath, 8 | FieldValues, 9 | FormProvider, 10 | useFormContext, 11 | } from "react-hook-form" 12 | 13 | import { cn } from "@/lib/utils" 14 | import { Label } from "@/components/ui/label" 15 | 16 | const Form = FormProvider 17 | 18 | type FormFieldContextValue< 19 | TFieldValues extends FieldValues = FieldValues, 20 | TName extends FieldPath = FieldPath 21 | > = { 22 | name: TName 23 | } 24 | 25 | const FormFieldContext = React.createContext( 26 | {} as FormFieldContextValue 27 | ) 28 | 29 | const FormField = < 30 | TFieldValues extends FieldValues = FieldValues, 31 | TName extends FieldPath = FieldPath 32 | >({ 33 | ...props 34 | }: ControllerProps) => { 35 | return ( 36 | 37 | 38 | 39 | ) 40 | } 41 | 42 | const useFormField = () => { 43 | const fieldContext = React.useContext(FormFieldContext) 44 | const itemContext = React.useContext(FormItemContext) 45 | const { getFieldState, formState } = useFormContext() 46 | 47 | const fieldState = getFieldState(fieldContext.name, formState) 48 | 49 | if (!fieldContext) { 50 | throw new Error("useFormField should be used within ") 51 | } 52 | 53 | const { id } = itemContext 54 | 55 | return { 56 | id, 57 | name: fieldContext.name, 58 | formItemId: `${id}-form-item`, 59 | formDescriptionId: `${id}-form-item-description`, 60 | formMessageId: `${id}-form-item-message`, 61 | ...fieldState, 62 | } 63 | } 64 | 65 | type FormItemContextValue = { 66 | id: string 67 | } 68 | 69 | const FormItemContext = React.createContext( 70 | {} as FormItemContextValue 71 | ) 72 | 73 | const FormItem = React.forwardRef< 74 | HTMLDivElement, 75 | React.HTMLAttributes 76 | >(({ className, ...props }, ref) => { 77 | const id = React.useId() 78 | 79 | return ( 80 | 81 |
82 | 83 | ) 84 | }) 85 | FormItem.displayName = "FormItem" 86 | 87 | const FormLabel = React.forwardRef< 88 | React.ElementRef, 89 | React.ComponentPropsWithoutRef 90 | >(({ className, ...props }, ref) => { 91 | const { error, formItemId } = useFormField() 92 | 93 | return ( 94 |