diff --git a/.dockerignore b/.dockerignore
index ff561a782b4..15e4fbec010 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -3,18 +3,17 @@
.git
.github
about
-apps
docker
examples
i18n
**/node_modules
-spec
+apps/docs/spec
supabase
tests
**/.next
.vercel
-.env.*
+**/.env.*
.dockerignore
-studio/Dockerfile
+apps/studio/Dockerfile
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e117764a36f..3eed078f08f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,6 +1,7 @@
/packages/shared-data/pricing.ts @roryw10 @kevcodez
/packages/shared-data/plans.ts @roryw10 @kevcodez
-/studio/ @supabase/Dashboard
+/apps/studio/ @supabase/Dashboard
/apps/www/ @supabase/Website
+/apps/www/_blog
/docker/ @supabase/cli
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 00000000000..c0d20008ea8
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,19 @@
+## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file.
+
+YES/NO
+
+## What kind of change does this PR introduce?
+
+Bug fix, feature, docs update, ...
+
+## What is the current behavior?
+
+Please link any relevant issues here.
+
+## What is the new behavior?
+
+Feel free to include screenshots if it includes visual changes.
+
+## Additional context
+
+Add any other context or screenshots.
diff --git a/.github/workflows/ai-tests.yml b/.github/workflows/ai-tests.yml
new file mode 100644
index 00000000000..357b2600c32
--- /dev/null
+++ b/.github/workflows/ai-tests.yml
@@ -0,0 +1,46 @@
+name: AI Unit Tests & Type Check
+
+on:
+ push:
+ branches: [master]
+ paths:
+ - 'packages/ai-commands/**'
+ pull_request:
+ branches: [master]
+ paths:
+ - 'packages/ai-commands/**'
+ schedule:
+ - cron: '15 0 * * 1' # Every Monday @ 12:15am UTC (off the hour to avoid heavy load times)
+
+# Cancel old builds on new commit for same workflow + branch/PR
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ env:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+
+ defaults:
+ run:
+ working-directory: ./packages/ai-commands
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: |
+ packages
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'npm'
+ - name: Install deps
+ run: npm ci
+ - name: Type check
+ run: npm run typecheck
+ - name: Run tests
+ run: npm run test
diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/auto-label-issues.yml
new file mode 100644
index 00000000000..eb248c823e0
--- /dev/null
+++ b/.github/workflows/auto-label-issues.yml
@@ -0,0 +1,65 @@
+name: Auto Label Issues
+on:
+ issues:
+ types: [opened, reopened]
+jobs:
+ check-external:
+ runs-on: ubuntu-latest
+ outputs:
+ result: ${{ steps.is-member.outputs.result }}
+ steps:
+ - name: Get deps
+ run: |
+ sudo apt-get update && sudo apt-get install -y jq
+ - name: Get org members
+ id: is-member
+ env:
+ GH_ORG: supabase
+ GH_USER: ${{ github.event.issue.user.login }}
+ GH_TOKEN: ${{ secrets.SB_ORG_MEMBERSHIP_PAT }}
+ run: |
+ gh api /orgs/supabase/members/$GH_USER
+ - if: failure()
+ name: is-member
+ run: |
+ echo "User is not a member of Supabase org"
+ echo "result=false" >> "$GITHUB_OUTPUT"
+ - if: success()
+ run: |
+ echo "User is a member of Supabase org"
+ echo "result=true" >> "$GITHUB_OUTPUT"
+ - name: Label contributor
+ id: label-contributor
+ if: ${{ steps.is-member.outputs.result == 'false' }}
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ USERNAME: ${{ github.event.issue.user.login }}
+ GH_REPO: ${{ github.repository }}
+ NUMBER: ${{ github.event.issue.number }}
+ LABELS: external-issue
+ run: |
+ echo "applying external label"
+ gh issue edit $NUMBER --add-label $LABELS
+ - name: Label internal
+ id: label-internal
+ if: ${{ steps.is-member.outputs.result == 'true' }}
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ USERNAME: ${{ github.event.issue.user.login }}
+ GH_REPO: ${{ github.repository }}
+ NUMBER: ${{ github.event.issue.number }}
+ LABELS: internal-issue
+ run: |
+ echo "applying internal label"
+ gh issue edit $NUMBER --add-label $LABELS
+ triage-new:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Label triage
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NUMBER: ${{ github.event.issue.number }}
+ LABELS: to-triage
+ run: |
+ echo "applying triage label"
+ gh issue edit $NUMBER --add-label $LABELS
diff --git a/.github/workflows/autofix_linters.yml b/.github/workflows/autofix_linters.yml
new file mode 100644
index 00000000000..ca8882d7e04
--- /dev/null
+++ b/.github/workflows/autofix_linters.yml
@@ -0,0 +1,58 @@
+name: Autofix Linting Checks
+
+on:
+ pull_request:
+ types:
+ - labeled
+
+# Cancel old builds on new commit for same workflow + branch/PR
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ autofix:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ if: ${{ github.event_name == 'pull_request' && (github.event.label.name == 'autofix') }}
+ steps:
+ - name: Calculate number of commits
+ run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}"
+
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.head_ref }}
+ sparse-checkout: apps
+ fetch-depth: ${{ env.PR_FETCH_DEPTH }}
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+
+ # Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps
+ - name: Install required dependencies
+ run: |
+ rm package.json
+ rm package-lock.json
+ npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst
+
+ - name: Run Prettier in fix mode
+ run: |
+ npx prettier --write 'apps/**/*.{js,jsx,ts,tsx,css,md,mdx,json}'
+
+ - name: Commit changes and push to existing branch
+ run: |
+ git checkout -- package.json
+ git checkout -- package-lock.json
+ git config --global user.name 'github-tidy-bot'
+ git config --global user.email 'github-tidy-bot@supabase.com'
+ if [[ `git status --porcelain` ]]; then
+ echo "[bot] Changes detected, committing."
+
+ echo "[bot] Running in non-squash mode."
+ git commit -am "ci: Autofix updates from GitHub workflow"
+ git push
+ else
+ echo "[bot] No changes detected, nothing to commit."
+ fi
diff --git a/.github/workflows/config-preview.yaml b/.github/workflows/config-preview.yaml
new file mode 100644
index 00000000000..cca3c2d7de3
--- /dev/null
+++ b/.github/workflows/config-preview.yaml
@@ -0,0 +1,63 @@
+name: Config (Preview)
+
+on:
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ branches:
+ - master
+ paths:
+ - "supabase/**"
+ workflow_dispatch:
+
+jobs:
+ wait:
+ runs-on: ubuntu-latest
+ outputs:
+ status: ${{ steps.check.outputs.conclusion }}
+ steps:
+ - uses: fountainhead/action-wait-for-check@v1.2.0
+ id: check
+ with:
+ checkName: Supabase
+ ref: ${{ github.event.pull_request.head.sha }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ apply:
+ needs:
+ - wait
+ if: ${{ needs.wait.outputs.status == 'success' }}
+ runs-on: ubuntu-latest
+ env:
+ SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
+ TF_VAR_linked_project: xguihxuzqibwxjnimxev
+ TF_VAR_git_branch: ${{ github.head_ref }}
+ TF_CLI_ARGS_apply: -target=supabase_settings.preview
+ defaults:
+ run:
+ working-directory: supabase/remotes
+ outputs:
+ db_user: ${{ steps.branch.outputs.user }}
+ db_pass: ${{ steps.branch.outputs.password }}
+ db_host: ${{ steps.branch.outputs.host }}
+ db_port: ${{ steps.branch.outputs.port }}
+ jwt_secret: ${{ steps.branch.outputs.jwt_secret }}
+ ref: ${{ steps.branch.outputs.id }}
+ status: ${{ steps.branch.outputs.status }}
+ version: ${{ steps.branch.outputs.version }}
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: hashicorp/setup-terraform@v3
+ with:
+ terraform_wrapper: false
+
+ - run: terraform init
+ - run: terraform apply -auto-approve -no-color
+ - id: branch
+ run: |
+ terraform output -json branch_database \
+ | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" \
+ >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/config-production.yaml b/.github/workflows/config-production.yaml
new file mode 100644
index 00000000000..b7f3dd3d63c
--- /dev/null
+++ b/.github/workflows/config-production.yaml
@@ -0,0 +1,28 @@
+name: Config (Production)
+
+on:
+ push:
+ branches:
+ - master
+ paths:
+ - "supabase/remotes/**"
+ workflow_dispatch:
+
+jobs:
+ apply:
+ runs-on: ubuntu-latest
+ env:
+ SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
+ TF_VAR_linked_project: xguihxuzqibwxjnimxev
+ defaults:
+ run:
+ working-directory: supabase/remotes
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: hashicorp/setup-terraform@v3
+ with:
+ terraform_wrapper: false
+
+ - run: terraform init
+ - run: terraform apply -auto-approve -no-color
diff --git a/.github/workflows/docs-last-changed.yml b/.github/workflows/docs-last-changed.yml
new file mode 100644
index 00000000000..71764de9626
--- /dev/null
+++ b/.github/workflows/docs-last-changed.yml
@@ -0,0 +1,45 @@
+name: '[Docs] Update last-changed dates'
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+ workflow_dispatch:
+ inputs:
+ reset:
+ description: 'Reset last-updated dates using Git commit dates'
+ required: false
+ type: boolean
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ env:
+ NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.SEARCH_SUPABASE_URL }}
+ SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SEARCH_SUPABASE_SERVICE_ROLE_KEY }}
+
+ steps:
+ - name: Check out repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ sparse-checkout: |
+ apps/docs
+
+ - name: Setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+
+ - name: Download dependencies
+ run: npm ci
+
+ - name: Update last-changed dates
+ working-directory: ./apps/docs
+ if: ${{ !inputs.reset }}
+ run: npm run last-changed
+
+ - name: Reset last-changed dates
+ working-directory: ./apps/docs
+ if: ${{ inputs.reset }}
+ run: npm run last-changed:reset
diff --git a/.github/workflows/docs-mgmt-api-update.yml b/.github/workflows/docs-mgmt-api-update.yml
new file mode 100644
index 00000000000..bfb12b7214b
--- /dev/null
+++ b/.github/workflows/docs-mgmt-api-update.yml
@@ -0,0 +1,41 @@
+name: Update Mgmt Api Docs
+
+on:
+ schedule:
+ # Run at 00:00 UTC every Monday
+ - cron: '0 0 * * 1'
+ workflow_dispatch:
+
+jobs:
+ update-docs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: master
+ sparse-checkout: |
+ apps/docs
+
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'npm'
+
+ - name: Install deps
+ run: npm ci
+
+ - name: Change to apps/docs/spec directory and run make command
+ working-directory: apps/docs/spec
+ run: make download.api.v1 dereference.api.v1 generate.sections.api.v1 format
+
+ - name: Create pull request
+ uses: peter-evans/create-pull-request@v6
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ commit-message: 'feat: update mgmt api docs'
+ title: 'feat: update mgmt api docs'
+ body: 'This PR updates mgmt api docs automatically.'
+ branch: 'gha/auto-update-mgmt-api-docs'
+ base: 'master'
diff --git a/.github/workflows/docs-tests.yml b/.github/workflows/docs-tests.yml
index d1b6ab48b00..7d402e444b4 100644
--- a/.github/workflows/docs-tests.yml
+++ b/.github/workflows/docs-tests.yml
@@ -15,10 +15,6 @@ jobs:
build:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
steps:
- uses: actions/checkout@v4
with:
@@ -26,10 +22,10 @@ jobs:
apps/docs
packages
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - name: Use Node.js
+ uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.nvmrc'
cache: 'npm'
- name: Install deps
diff --git a/.github/workflows/lint-prose.yml b/.github/workflows/lint-prose.yml
new file mode 100644
index 00000000000..c2a402697a7
--- /dev/null
+++ b/.github/workflows/lint-prose.yml
@@ -0,0 +1,25 @@
+name: reviewdog
+on:
+ pull_request:
+ paths:
+ - '.vale.ini'
+ - 'vale/**'
+ - 'apps/docs/content/**'
+
+jobs:
+ vale:
+ name: runner / vale
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ sparse-checkout: |
+ .vale.ini
+ vale
+ apps/docs/content
+ - uses: errata-ai/vale-action@reviewdog
+ with:
+ files: apps/docs/content
+ # [Charis] Temporary because we still have to go through giant backlog of existing errors
+ # Don't want people to worry about this (just want them looking at the specific PR comments)
+ # fail_on_error: true
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
new file mode 100644
index 00000000000..2508ef13315
--- /dev/null
+++ b/.github/workflows/playwright.yml
@@ -0,0 +1,45 @@
+name: Playwright Tests
+on:
+ push:
+ branches: [master]
+ paths:
+ - 'apps/studio/**'
+ - 'package-lock.json'
+ pull_request:
+ branches: [master]
+ paths:
+ - 'apps/studio/**'
+ - 'package-lock.json'
+
+# Cancel old builds on new commit for same workflow + branch/PR
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ test:
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'npm'
+ - uses: supabase/setup-cli@v1
+ - name: Install dependencies
+ run: npm ci
+ - name: Install Playwright Browsers
+ run: npx playwright install --with-deps
+ - name: Run Playwright tests
+ run: npm run test:playwright
+ # mark the action as succeeded even if the tests failed. This is temporarily until we make the tests more stable.
+ # continue-on-error: true
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-report
+ path: playwright-tests/playwright-report/
+ retention-days: 7
diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml
index 3d4bc47ad7d..9d7053db16b 100644
--- a/.github/workflows/prettier.yml
+++ b/.github/workflows/prettier.yml
@@ -17,23 +17,18 @@ jobs:
- name: Check out repo
uses: actions/checkout@v4
with:
- sparse-checkout: |
- apps
- studio
+ sparse-checkout: apps
- name: Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version-file: '.nvmrc'
# Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps
- name: Download dependencies
run: |
- rm package.json
- rm package-lock.json
- npm i prettier@2 prettier-plugin-sql-cst
+ npm ci
- name: Run prettier
run: |-
- npx prettier -c '{apps,studio}/**/*.{js,jsx,ts,tsx,css,md,mdx,json}'
-
+ npm run test:prettier
# i18n is not a node package, so we handle that one separately
format-i18n:
@@ -45,15 +40,15 @@ jobs:
sparse-checkout: |
i18n
- name: Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version-file: '.nvmrc'
# Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps
- name: Download dependencies
run: |
rm package.json
rm package-lock.json
- npm i prettier@2 prettier-plugin-sql-cst
+ npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst
- name: Run prettier
run: |-
npx prettier -c 'i18n/**/*.{js,jsx,ts,tsx,css,md,mdx,json}'
@@ -66,13 +61,14 @@ jobs:
with:
sparse-checkout: |
apps/docs/pages
+ apps/docs/content
# Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps
- name: Download dependencies
run: |
rm package.json
rm package-lock.json
- npm i prettier@2 prettier-plugin-sql-cst
+ npm i prettier@4.0.0-alpha.8 prettier-plugin-sql-cst
- name: Run prettier
run: |-
# Check mdx files which contain sql code blocks
- grep -lr '```sql' apps/docs/pages/**/*.mdx | xargs npx prettier -c
+ grep -lr '```sql' apps/docs/{pages,content}/**/*.mdx | xargs npx prettier -c
diff --git a/.github/workflows/publish_image.yml b/.github/workflows/publish_image.yml
index f57fd2515d3..7f14f125ed9 100644
--- a/.github/workflows/publish_image.yml
+++ b/.github/workflows/publish_image.yml
@@ -1,17 +1,10 @@
name: Publish to Image Registry
on:
- push:
- branches:
- - 'studio'
- tags:
- - '*'
+ # run this action every Monday at 04:00 UTC (Singapore noon)
+ schedule:
+ - cron: '0 4 * * 1'
workflow_dispatch:
- inputs:
- version:
- description: 'Image tag'
- required: true
- type: string
jobs:
settings:
@@ -25,11 +18,10 @@ jobs:
images: |
supabase/studio
flavor: |
- latest=false
+ latest=true
tags: |
- type=ref,event=tag
- type=sha,prefix={{date 'YYYYMMDD'}}-,enable=${{ github.event_name == 'push' && github.ref_type == 'branch' }}
- type=raw,value=${{ inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
+ type=sha,prefix={{date 'YYYYMMDD'}}-,enable=${{ github.event_name == 'schedule' }}
+ type=sha,prefix={{date 'YYYYMMDD'}}-,enable=${{ github.event_name == 'workflow_dispatch' }}
release_x86:
needs: settings
@@ -61,7 +53,7 @@ jobs:
with:
push: true
context: '{{defaultContext}}'
- file: studio/Dockerfile
+ file: apps/studio/Dockerfile
target: production
platforms: linux/${{ env.arch }}
tags: ${{ steps.meta.outputs.tags }}
@@ -104,7 +96,7 @@ jobs:
with:
push: true
context: .
- file: studio/Dockerfile
+ file: apps/studio/Dockerfile
target: production
platforms: linux/${{ env.arch }}
tags: ${{ steps.meta.outputs.tags }}
diff --git a/.github/workflows/search.yml b/.github/workflows/search.yml
index 31e83a0f065..b2587177495 100644
--- a/.github/workflows/search.yml
+++ b/.github/workflows/search.yml
@@ -8,7 +8,6 @@ on:
- '.github/workflows/search.yml'
- 'supabase/migrations/**'
- 'apps/docs/**'
- - 'spec/**'
workflow_dispatch:
inputs:
refresh:
@@ -23,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
env:
- OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
PROJECT_ID: ${{ secrets.SEARCH_SUPABASE_PROJECT_ID }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.SEARCH_SUPABASE_URL }}
@@ -39,12 +38,13 @@ jobs:
with:
sparse-checkout: |
apps/docs
+ apps/www/.env.local.example
supabase
- name: Setup node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version-file: '.nvmrc'
- name: Download dependencies
run: npm ci
@@ -55,6 +55,10 @@ jobs:
- name: Run migrations
run: npx supabase db push
+ # Need the miscellaneous use API, which is available publicly (by design) in www
+ - name: Copy environment variables
+ run: cp apps/www/.env.local.example apps/docs/.env
+
- name: Update embeddings
working-directory: ./apps/docs
if: ${{ !inputs.refresh }}
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 00000000000..8281d285e2a
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,18 @@
+name: Automatically label stale issues
+on:
+ schedule:
+ - cron: '30 1 * * *'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Label Stale Issues
+ uses: actions/stale@v9.0.0
+ with:
+ days-before-issue-stale: 30
+ stale-issue-message: 'After 30 days of inactivity, this issue has been marked as stale. Commenting (or other activity) will remove the stale label.'
+ stale-issue-label: stale
+ any-of-labels: contributor
+ exempt-issue-labels: dnc, needs-analysis
+ exempt-all-assignees: true
diff --git a/.github/workflows/studio-tests.yml b/.github/workflows/studio-tests.yml
index 611ac60fafd..1dbc0bd8dd6 100644
--- a/.github/workflows/studio-tests.yml
+++ b/.github/workflows/studio-tests.yml
@@ -7,12 +7,12 @@ on:
push:
branches: [master, studio]
paths:
- - 'studio/**'
+ - 'apps/studio/**'
- 'package-lock.json'
pull_request:
branches: [master, studio]
paths:
- - 'studio/**'
+ - 'apps/studio/**'
- 'package-lock.json'
# Cancel old builds on new commit for same workflow + branch/PR
@@ -25,30 +25,23 @@ jobs:
# Uses larger hosted runner as it significantly decreases build times
runs-on: [larger-runner-4cpu]
- strategy:
- matrix:
- node-version: [18.x]
- cmd:
- - npm run test:studio
- - npm run build:studio
-
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
- studio
+ apps/studio
packages
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - name: Use Node.js
+ uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.nvmrc'
cache: 'npm'
- name: Install deps
run: npm ci
working-directory: ./
- - name: Run ${{ matrix.cmd }}
+ - name: Run Tests
env:
# Default is 2 GB, increase to have less frequent OOM errors
NODE_OPTIONS: '--max_old_space_size=3072'
- run: ${{ matrix.cmd }}
+ run: npm run test:studio
working-directory: ./
diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml
index 15fb3d390c6..eb4e5885a55 100644
--- a/.github/workflows/typecheck.yml
+++ b/.github/workflows/typecheck.yml
@@ -12,20 +12,17 @@ concurrency:
jobs:
typecheck:
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- node-version: [18.x]
+ # Uses larger hosted runner as it significantly decreases build times
+ runs-on: [larger-runner-4cpu]
steps:
- name: Checkout
uses: actions/checkout@v4
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - name: Use Node.js
+ uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.nvmrc'
cache: 'npm'
- name: Install deps
diff --git a/.github/workflows/ui-patterns-tests.yml b/.github/workflows/ui-patterns-tests.yml
new file mode 100644
index 00000000000..a2fe4dc775f
--- /dev/null
+++ b/.github/workflows/ui-patterns-tests.yml
@@ -0,0 +1,34 @@
+name: UI Patterns Tests
+
+on:
+ pull_request:
+ branches: [master]
+ paths:
+ - 'packages/ui-patterns/**'
+
+# Cancel old builds on new commit for same workflow + branch/PR
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: |
+ packages
+
+ - name: Use Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+ cache: 'npm'
+
+ - name: Install deps
+ run: npm ci
+
+ - name: Run tests
+ run: npm run test:ui-patterns
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index f312f2130d4..126edd5b9a5 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -15,20 +15,16 @@ jobs:
build:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
packages
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - name: Use Node.js
+ uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.nvmrc'
cache: 'npm'
- name: Install deps
diff --git a/.gitignore b/.gitignore
index de5d7122e93..b6ce235b350 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@ node_modules
out
.docz
tmp
-.swp
+*.swp
coverage
allure-results
@@ -82,8 +82,10 @@ typings/
.env
# excempt the apps/www .env
!apps/www/.env
+.env.tmp
.env.test
.env.local
+.env.staging
.env.production
# parcel-bundler cache (https://parceljs.org/)
@@ -125,9 +127,6 @@ apps/new-docs/*
# UI tokens
packages/ui/tokens/**/*.json
-# UI Storybook build
-packages/ui/storybook-static
-
# For self-hosted logs: https://github.com/supabase/supabase/blob/86e3ab20abfdb9c3e666334d3d2f8efeef9ccf2c/docker/docker-compose-logging.yml#L101
gcloud.json
diff --git a/.misspell-fixer.ignore b/.misspell-fixer.ignore
index 105b2fccda8..2bfab3e9e99 100644
--- a/.misspell-fixer.ignore
+++ b/.misspell-fixer.ignore
@@ -1 +1,2 @@
-^./i18n
\ No newline at end of file
+^./i18n
+^./packages/api-types
\ No newline at end of file
diff --git a/.nvmrc b/.nvmrc
index 25bf17fc5aa..2edeafb09db 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-18
\ No newline at end of file
+20
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
index 9de82e2c6c5..10d155ba310 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,6 +4,7 @@ node_modules
package-lock.json
docker*
apps/**/out
+apps/docs/spec/**
# prettier-plugin-sql-cst only supports sqlite syntax
**/supabase/migrations/*.sql
apps/www/schema.sql
@@ -12,11 +13,7 @@ examples/slack-clone/nextjs-slack-clone/full-schema.sql
# ignore files with custom js formatting
apps/docs/pages/guides/auth/*.mdx
apps/docs/pages/guides/integrations/*.mdx
-studio/public
-studio/__mocks__
-studio/.next
-studio/.storybook
-studio/.swc
-studio/.turbo
-studio/node
-studio/data
\ No newline at end of file
+apps/studio/public
+apps/**/.turbo
+apps/docs/CONTRIBUTING.md
+apps/design-system/__registry__
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
index c60d3ab91ef..5609026b6f4 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -7,5 +7,11 @@
"endOfLine": "lf",
"sqlKeywordCase": "lower",
"pluginSearchDirs": false,
- "plugins": ["prettier-plugin-sql-cst"]
+ "plugins": ["prettier-plugin-sql-cst"],
+ "overrides": [
+ {
+ "files": "**/*.json",
+ "options": { "parser": "json" }
+ }
+ ]
}
diff --git a/.vale.ini b/.vale.ini
new file mode 100644
index 00000000000..1ff9438668a
--- /dev/null
+++ b/.vale.ini
@@ -0,0 +1,14 @@
+StylesPath = './vale/styles'
+MinAlertLevel = 'suggestion'
+
+Vocab = Supabase
+
+[formats]
+mdx = md
+
+[*]
+BasedOnStyles = Vale, Custom
+BlockIgnores = (?s) *(.*?), \
+(?s) *(export\s+const\s+\S+\s*=\s*\[.*?\]), \
+(?s) *()
+TokenIgnores = (href\s*([=:])\s*['"].*?\1), \
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000000..b5d3188a5b3
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# CONTRIBUTING.md
+
+Thank you for contributing to Supabase! We’re a big, exciting open source project and we’d love to have you contribute! Here’s some resources and guidance to help you get started:
+
+[1. Getting Started](#getting-started)
+[2. Issues](#issues)
+[3. Pull Requests](#pull-requests)
+
+## Getting Started
+
+To ensure a positive and inclusive environment, please read our [code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) before contributing. For help setting up the code in this repo, please follow our [DEVELOPERS.md](https://github.com/supabase/supabase/blob/master/DEVELOPERS.md) file. For the [docs](https://supabase.com/docs) site, follow this [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md) guide.
+
+## Issues
+
+If you find a bug, please create an Issue and we’ll triage it.
+
+- Please search [existing Issues](https://github.com/supabase/supabase/issues) before creating a new one.
+- Please include a clear description of the problem along with steps to reproduce it. Exact steps with screenshots and urls really help here.
+
+## Pull Requests
+
+We actively welcome your Pull Requests! A couple of things to keep in mind before you submit:
+
+- If you’re fixing an Issue, make sure someone else hasn’t already created a PR fixing the same issue. Likewise, make sure to link your PR to the related Issue(s).
+- We will always try to accept the first viable PR that resolves the Issue.
+- If you're new, we encourage you to take a look at issues tagged with [good first issue](https://github.com/supabase/supabase/labels/good%20first%20issue).
+- If you’re submitting a new feature, make sure you have opened a [Discussion](https://github.com/orgs/supabase/discussions/new/choose) to discuss the new feature before opening a PR. We’d love to accept your hard work, but unfortunately if a feature hasn’t gone through a proper design process, your PR will be closed.
+- Please use the PR message template and provide detailed context for quicker review. PRs without clear problem statements will be closed.
+
+Prior to submitting your PR, please conduct the following pre-flight checks:
+
+- Run `npm run build` locally to ensure that your code builds successfully without having to wait on us to approve Vercel Preview deploys.
+- Ensure that the Prettier tests run successfully on your PR.
+
+Running these before you create the PR will help reduce back and forth with the team.
diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index 78cfcda3598..a42c0a057b1 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -1,15 +1,26 @@
# Developing Supabase
-1. [Getting started](#getting-started)
- - [Install dependencies](#install-dependencies)
-2. [Local development](#local-development)
- - [Fork the repository](#fork-the-repository)
- - [Clone the repo](#clone-the-repo)
- - [Running turborepo](#running-turborepo)
- - [Shared components](#shared-components)
- - [Installing packages](#installing-packages)
- - [New Supabase docs](#new-supabase-docs)
-3. [Create a pull request](#create-a-pull-request)
+- [Developing Supabase](#developing-supabase)
+
+ - [Getting started](#getting-started)
+ - [Install dependencies](#install-dependencies)
+ - [Local development](#local-development)
+ - [Fork the repo](#fork-the-repo)
+ - [Clone the repo](#clone-the-repo)
+ - [Install dependencies](#install-dependencies-1)
+ - [Running sites individually](#running-sites-individually)
+ - [Shared components](#shared-components)
+ - [Installing packages](#installing-packages)
+ - [Running Docker for Supabase Studio](#running-docker-for-supabase-studio)
+ - [Prerequsites](#prerequsites)
+ - [Get Started](#get-started)
+ - [Create a pull request](#create-a-pull-request)
+ - [Issue assignment](#issue-assignment)
+ - [Common tasks](#common-tasks)
+ - [Add a redirect](#add-a-redirect)
+ - [Federated docs](#federated-docs)
+ - [Community channels](#community-channels)
+ - [Contributors](#contributors)
- [Common tasks](#common-tasks)
- [Add a redirect](#add-a-redirect)
@@ -17,31 +28,32 @@
## Getting started
-Thank you for expressing your interest in [Supabase](https://supabase.com) and your willingness to contribute!
+Thank you for your interest in [Supabase](https://supabase.com) and your willingness to contribute!
-To ensure a positive and inclusive environment, we kindly request you to read our [code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md). Additionally, we encourage you to explore the existing [issues](https://github.com/supabase/supabase/issues) to see how you can make a meaningful impact. This document will guide you through the process of setting up your development environment, enabling you to successfully build and test [Supabase](https://supabase.com).
+To ensure a positive and inclusive environment, please read our [code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md). We encourage you to explore the existing [issues](https://github.com/supabase/supabase/issues) to see how you can make a meaningful impact. This document will help you setup your development environment.
### Install dependencies
You will need to install and configure the following dependencies on your machine to build [Supabase](https://supabase.com):
- [Git](http://git-scm.com/)
-- [Node.js v18.x (LTS)](http://nodejs.org)
-- [npm](https://www.npmjs.com/) version 9.x.x
+- [Node.js v20.x (LTS)](http://nodejs.org)
+- [npm](https://www.npmjs.com/) version 9.x.x or higher
+- [Docker](https://docs.docker.com/get-docker/) (to run studio locally)
## Local development
-We are in the process of migrating this repository to monorepo, using [Turborepo](https://turborepo.org/docs).
+This repo uses [Turborepo](https://turborepo.org/docs).
-Eventually, all the apps will be run using [Turborepo](https://turborepo.org/docs), which will significantly improve the developer workflow.
+All of our apps are in this [Turborepo](https://turborepo.org/docs), which make it easy to share packages and config between projects.
-### Fork the repository
+### Fork the repo
-To contribute code to [Supabase](https://supabase.com), you must fork the [Supabase Repository](https://github.com/supabase/supabase).
+To contribute code to [Supabase](https://supabase.com), you must fork the [Supabase repo](https://github.com/supabase/supabase).
### Clone the repo
-1. Clone your GitHub forked repository:
+1. Clone your GitHub forked repo:
```sh
git clone https://github.com//supabase.git
@@ -52,9 +64,7 @@ To contribute code to [Supabase](https://supabase.com), you must fork the [Supab
cd supabase
```
-### Running turborepo
-
-[Supabase](https://supabase.com) uses [Turborepo](https://turborepo.org/docs) to manage and run this monorepo.
+### Install dependencies
1. Install the dependencies in the root of the repo.
@@ -62,18 +72,24 @@ To contribute code to [Supabase](https://supabase.com), you must fork the [Supab
npm install # install dependencies
```
-2. After that you can run the apps simultaneously with the following.
+2. Copy the example `.env.local.example` to `.env.local`
+
+ ```sh
+ cp apps/www/.env.local.example apps/www/.env.local
+ ```
+
+3. After that you can run the apps simultaneously with the following.
```sh
npm run dev # start all the applications
```
Then visit, and edit, any of the following sites:
-| Site | Directory | Scope name | Description | Local development server |
-| -------------------------------------------------------- | ------------ | ---------- | ------------------------------------ | -------------------------- |
-| [supabase.com](https://supabase.com) | `/apps/www` | www | The main website | http://localhost:3000 |
-| [supabase.com/dashboard](https://supabase.com/dashboard) | `/studio` | studio | Studio dashboard | http://localhost:8082 |
-| [supabase.com/docs](https://supabase.com/docs) | `/apps/docs` | docs | Guides and Reference (Next.js based) | http://localhost:3001/docs |
+| Site | Directory | Scope name | Description | Local development server |
+| -------------------------------------------------------- | -------------- | ---------- | --------------------------------------------- | -------------------------- |
+| [supabase.com](https://supabase.com) | `/apps/www` | www | The main website | http://localhost:3000 |
+| [supabase.com/dashboard](https://supabase.com/dashboard) | `/apps/studio` | studio | Studio dashboard (requires Docker, see below) | http://localhost:8082 |
+| [supabase.com/docs](https://supabase.com/docs) | `/apps/docs` | docs | Guides and Reference (Next.js based) | http://localhost:3001/docs |
#### Running sites individually
@@ -83,14 +99,18 @@ You can run any of the sites individually by using the scope name. For example:
npm run dev:www
```
+Note: Particularly for `www` make sure you have copied `apps/www/.env.local.example` to `apps/www/.env.local`
+
#### Shared components
The monorepo has a set of shared components under `/packages`:
-- `/packages/common`: Common React code, shared between all sites.
+- `/packages/ai-commands`: Helpers/Commands for AI related functions
+- `/packages/common`: Common React components, shared between all sites
- `/packages/config`: All shared config
-- `/packages/spec`: Generates documentation using spec files.
+- `/packages/shared-data`: Shared data that can be used across all apps
- `/packages/tsconfig`: Shared Typescript settings
+- `/packages/ui`: Common UI components
#### Installing packages
@@ -102,29 +122,21 @@ For example:
- `npm install react -w common`: installs into `./packages/common`
- `npm install react -w www`: installs into `./apps/www`
-- `npm install react -w studio`: installs into `./studio`
+- `npm install react -w studio`: installs into `./apps/studio`
You do not need to install `devDependencies` in each workspace. These can all be installed in the root package.
-#### New Supabase docs
-
-Following the changes to the [Supabase docs](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) the following is needed to run the new docs locally:
-
-- Inside of `apps/docs` create a `.env.local` file with the following: `NEXT_PUBLIC_NEW_DOCS=true`
-
-Now when you run a local development docs server you will see the new docs site.
-
---
-## Running Docker
+## Running Docker for Supabase Studio
-To test your changes, you need to run Supabase using Docker. Docker lets you use features of your locally modified Supabase version.
+To run Studio locally, you'll need to setup Docker in addition to your NextJS frontend.
#### Prerequsites
-First, make sure you have the Docker application installed on your device. You can download and install it from [here](https://docs.docker.com/get-docker/).
+First, make sure you have the Docker installed on your device. You can download and install it from [here](https://docs.docker.com/get-docker/).
-#### Getting Started
+#### Get Started
1. Navigate to the `docker` directory in your forked repo
@@ -141,20 +153,28 @@ First, make sure you have the Docker application installed on your device. You c
3. Run docker
```sh
- docker-compose up
+ docker compose up
```
-This command initializes the containers specified in the docker-compose.yml file. It might take a few moments to complete, depending on your computer and internet connection.
+This command initializes the containers specified in the `docker-compose.yml` file. It might take a few moments to complete, depending on your computer and internet connection.
-Once the `docker-compose up` process completes, you should have your local version of Supabase up and running within Docker containers. You can access and test the features you've modified or added.
+Once the `docker compose up` process completes, you should have your local version of Supabase up and running within Docker containers. You can access it at `http://localhost:8082`.
Remember to keep the Docker application open as long as you're working with your local Supabase instance.
## Create a pull request
-After making your changes, open a pull request. Once you submit your pull request, the Supabase team will review it with you.
+After making any changes, open a pull request. Once you submit your pull request, the Supabase team will review it with you.
-Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors).
+Once your PR has been merged, you will be proudly listed as a contributor in the [contributor chart](https://github.com/supabase/supabase/graphs/contributors)!
+
+## Issue assignment
+
+We don't have a process for assigning issues to contributors. Please feel free to jump into any issues in this repo that you are able to help with. Our intention is to encourage anyone to help without feeling burdened by an assigned task. Life can sometimes get in the way, and we don't want to leave contributors feeling obligated to complete issues when they may have limited time or unexpected commitments.
+
+We also recognize that not having a process can sometimes lead to competing or duplicate PRs. There's no perfect solution here. We encourage you to communicate early and often on an Issue to indicate that you're actively working on it. If you see that an Issue already has a PR, try working with that author instead of drafting your own.
+
+We review PRs in the order of their submission. We try to accept the earliest one that is closest to being ready to merge.
---
@@ -188,7 +208,7 @@ Some things to consider:
## Community channels
-If you are stuck somewhere or have any questions, join our [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
+If you get stuck somewhere or have any questions, join our [Discord Community Server](https://discord.supabase.com/) or the [Github Discussions](https://github.com/supabase/supabase/discussions). We are here to help!
## Contributors
diff --git a/LICENSE b/LICENSE
index e029233d99c..49ea1240252 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2023 Supabase
+ Copyright 2024 Supabase
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 88e63413c05..d63f425b65d 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,6 @@
----
-
# Supabase
[Supabase](https://supabase.com) is an open source Firebase alternative. We're building the features of Firebase using enterprise-grade open source tools.
@@ -12,9 +10,9 @@
- [x] Hosted Postgres Database. [Docs](https://supabase.com/docs/guides/database)
- [x] Authentication and Authorization. [Docs](https://supabase.com/docs/guides/auth)
- [x] Auto-generated APIs.
- - [x] REST. [Docs](https://supabase.com/docs/guides/api#rest-api-overview)
- - [x] GraphQL. [Docs](https://supabase.com/docs/guides/api#graphql-api-overview)
- - [x] Realtime subscriptions. [Docs](https://supabase.com/docs/guides/api#realtime-api-overview)
+ - [x] REST. [Docs](https://supabase.com/docs/guides/api)
+ - [x] GraphQL. [Docs](https://supabase.com/docs/guides/graphql)
+ - [x] Realtime subscriptions. [Docs](https://supabase.com/docs/guides/realtime)
- [x] Functions.
- [x] Database Functions. [Docs](https://supabase.com/docs/guides/database/functions)
- [x] Edge Functions [Docs](https://supabase.com/docs/guides/functions)
@@ -24,6 +22,10 @@

+Watch "releases" of this repo to get notified of major updates.
+
+
+
## Documentation
For full documentation, visit [supabase.com/docs](https://supabase.com/docs)
@@ -37,19 +39,6 @@ To see how to Contribute, visit [Getting Started](./DEVELOPERS.md)
- [Email Support](https://supabase.com/docs/support#business-support). Best for: problems with your database or infrastructure.
- [Discord](https://discord.supabase.com). Best for: sharing your applications and hanging out with the community.
-## Status
-
-- [x] Alpha: We are testing Supabase with a closed set of customers
-- [x] Public Alpha: Anyone can sign up over at [supabase.com/dashboard](https://supabase.com/dashboard). But go easy on us, there are a few kinks
-- [x] Public Beta: Stable enough for most non-enterprise use-cases
-- [ ] Public: General Availability [[status](https://supabase.com/docs/guides/getting-started/features#feature-status)]
-
-We are currently in Public Beta. Watch "releases" of this repo to get notified of major updates.
-
-
-
----
-
## How it works
Supabase is a combination of open source tools. We’re building the features of Firebase using enterprise-grade, open source products. If the tools and communities exist, with an MIT, Apache 2, or equivalent open license, we will use and support that tool. If the tool doesn't exist, we build and open source it ourselves. Supabase is not a 1-to-1 mapping of Firebase. Our aim is to give developers a Firebase-like developer experience using open source tools.
@@ -59,15 +48,15 @@ Supabase is a combination of open source tools. We’re building the features of
Supabase is a [hosted platform](https://supabase.com/dashboard). You can sign up and start using Supabase without installing anything.
You can also [self-host](https://supabase.com/docs/guides/hosting/overview) and [develop locally](https://supabase.com/docs/guides/local-development).
-
+
-- [PostgreSQL](https://www.postgresql.org/) is an object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.
+- [Postgres](https://www.postgresql.org/) is an object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.
- [Realtime](https://github.com/supabase/realtime) is an Elixir server that allows you to listen to PostgreSQL inserts, updates, and deletes using websockets. Realtime polls Postgres' built-in replication functionality for database changes, converts changes to JSON, then broadcasts the JSON over websockets to authorized clients.
- [PostgREST](http://postgrest.org/) is a web server that turns your PostgreSQL database directly into a RESTful API
-- [pg_graphql](http://github.com/supabase/pg_graphql/) a PostgreSQL extension that exposes a GraphQL API
-- [Storage](https://github.com/supabase/storage-api) provides a RESTful interface for managing Files stored in S3, using Postgres to manage permissions.
-- [postgres-meta](https://github.com/supabase/postgres-meta) is a RESTful API for managing your Postgres, allowing you to fetch tables, add roles, and run queries, etc.
- [GoTrue](https://github.com/supabase/gotrue) is a JWT based API for managing users and issuing JWT tokens.
+- [Storage](https://github.com/supabase/storage-api) provides a RESTful interface for managing Files stored in S3, using Postgres to manage permissions.
+- [pg_graphql](http://github.com/supabase/pg_graphql/) a PostgreSQL extension that exposes a GraphQL API
+- [postgres-meta](https://github.com/supabase/postgres-meta) is a RESTful API for managing your Postgres, allowing you to fetch tables, add roles, and run queries, etc.
- [Kong](https://github.com/Kong/kong) is a cloud-native API gateway.
#### Client libraries
@@ -122,6 +111,15 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
+
+
+ )
+}
diff --git a/apps/database-new/app/[thread_id]/[message_id]/SchemaFlow.tsx b/apps/database-new/app/[thread_id]/[message_id]/SchemaFlow.tsx
new file mode 100644
index 00000000000..e53a476920a
--- /dev/null
+++ b/apps/database-new/app/[thread_id]/[message_id]/SchemaFlow.tsx
@@ -0,0 +1,8 @@
+import SchemaFlowHandler from '@/components/SchemaFlowHandler'
+
+export async function SchemaFlow({ promisedMessage }: { promisedMessage: Promise }) {
+ const code = await promisedMessage
+ const strippedCode = code.replace('```sql\n', '').replace('\n```', '')
+
+ return
+}
diff --git a/apps/database-new/app/[thread_id]/[message_id]/getAssistantMessage.ts b/apps/database-new/app/[thread_id]/[message_id]/getAssistantMessage.ts
new file mode 100644
index 00000000000..5d5de4d165a
--- /dev/null
+++ b/apps/database-new/app/[thread_id]/[message_id]/getAssistantMessage.ts
@@ -0,0 +1,134 @@
+import { stripIndent } from 'common-tags'
+import { cookies } from 'next/headers'
+import OpenAI from 'openai'
+
+// import is weird, what's up with this?
+import { createClient } from '@/lib/supabase/server'
+import { ContextLengthError } from '../../../../../packages/ai-commands/src/errors'
+import { getMessages } from './getMessages'
+
+// Create an OpenAI API client (that's edge friendly!)
+const openai = new OpenAI({
+ apiKey: process.env.OPENAI_API_KEY,
+})
+
+// Set the runtime to edge for best performance
+export const runtime = 'edge'
+
+export type AiAssistantMessage = {
+ content: string
+ role: 'user' | 'assistant'
+}
+
+/**
+ * Get the latest AI generated message. In the DB, there's a pair of user prompt and AI response, so if the
+ * user sent a message but that message lacks the corresponding AI response, a call will be made to OpenAI to generate
+ * it.
+ */
+export const getAssistantResponse = async (threadId: string, messageId: string) => {
+ const supabase = createClient()
+
+ const { data: message, error } = await supabase
+ .from('messages')
+ .select()
+ .eq('message_id', messageId)
+ .single()
+
+ if (!message || error) {
+ throw new Error('A message with that id does not exist.')
+ }
+
+ // if the message lacks the AI response, fetch it from OpenAI
+ if (!message.message_content) {
+ const { data: messages, error } = await getMessages(threadId)
+
+ if (error) {
+ throw new Error('Error while trying to fetch the existing messages.')
+ }
+
+ // transform the DB messages into a format that OpenAI understands
+ const existingMessages = messages.flatMap((m) => [
+ {
+ content: m.message_input,
+ role: 'user' as const,
+ },
+ {
+ content: m.message_content,
+ role: 'assistant' as const,
+ },
+ ])
+
+ const initMessages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
+ {
+ role: 'system',
+ content: stripIndent`
+ Your purpose is to generate a SQL schema where the user will give commands to you via a chat.
+ The output should use the following instructions:
+ - The generated SQL must be valid SQL.
+ - For primary keys, always use "id bigint primary key generated always as identity" (not serial)
+ - Always create foreign key references in the create statement
+ - Prefer 'text' over 'varchar'
+ - Prefer 'timestamp with time zone' over 'date'
+ - Use vector(384) data type for any embedding/vector related query
+ - Always use double apostrophe in SQL strings (eg. 'Night''s watch')
+ - Always omit \`\`\`sql from your reply
+ - You can use only CREATE TABLE queries, no other queries are allowed under no circumstances (ALTER TABLE etc).
+ - On each subsequent message from the user, rewrite the original response to include the new requirement.
+ - Don't add any SQL comments in the code
+ - Never put a comma before a round bracket
+
+ The output should look like this: "CREATE TABLE users (id bigint primary key generated always as identity)"
+
+ DO NOT RESPOND WITH ANYTHING ELSE.
+ YOU MUST NOT ANSWER WITH ANY PLAIN TEXT
+ ONLY RESPOND WITH 1 CODE BLOCK
+ YOU MUST NOT FOLLOW UP ANY CODE BLOCKS WITH ANY EXPLANATION
+ `,
+ },
+ ]
+
+ initMessages.push(...existingMessages)
+
+ try {
+ const response = await openai.chat.completions.create({
+ model: 'gpt-3.5-turbo-16k-0613',
+ messages: initMessages,
+ max_tokens: 1024,
+ temperature: 0,
+ stream: false,
+ })
+
+ const newMessage = response.choices[0].message.content || ''
+
+ const {
+ data: { user },
+ error: userError,
+ } = await supabase.auth.getUser()
+
+ if (userError || !user) {
+ throw new Error('Failed to get user')
+ }
+
+ // Insert the message from the completion
+ const { data, error } = await supabase
+ .from('messages')
+ .update({ message_content: newMessage })
+ .eq('id', message.id)
+ .select()
+ .single()
+
+ if (error || !data) {
+ throw new Error('Error while updating the existing message with the completion data.')
+ }
+
+ return data.message_content
+ } catch (error) {
+ if (error instanceof Error && 'code' in error && error.code === 'context_length_exceeded') {
+ throw new ContextLengthError()
+ }
+ throw error
+ }
+ }
+
+ return message.message_content
+}
diff --git a/apps/database-new/app/[thread_id]/[message_id]/getMessages.ts b/apps/database-new/app/[thread_id]/[message_id]/getMessages.ts
new file mode 100644
index 00000000000..3909a2551c5
--- /dev/null
+++ b/apps/database-new/app/[thread_id]/[message_id]/getMessages.ts
@@ -0,0 +1,9 @@
+import { createClient } from '@/lib/supabase/server'
+import { cookies } from 'next/headers'
+import { cache } from 'react'
+
+export const getMessages = cache(async (thread_id: string) => {
+ const supabase = createClient()
+
+ return await supabase.from('messages').select().eq('thread_id', thread_id).order('created_at')
+})
diff --git a/apps/database-new/app/[thread_id]/[message_id]/page.tsx b/apps/database-new/app/[thread_id]/[message_id]/page.tsx
new file mode 100644
index 00000000000..4ff81c18eb7
--- /dev/null
+++ b/apps/database-new/app/[thread_id]/[message_id]/page.tsx
@@ -0,0 +1,56 @@
+import { AssistantChatForm } from '@/components/AssistantChatForm'
+import SaveSchemaDropdown from '@/components/Header/SaveSchemaDropdown'
+import ToggleCodeEditorButton from '@/components/Header/ToggleCodeEditorButton'
+import GraphLoader from '@/components/Loaders/GraphLoader'
+import SchemaLoader from '@/components/Loaders/SchemaLoader'
+import { cn } from '@ui/lib/utils/cn'
+import { Suspense } from 'react'
+import { CodeEditor } from './CodeEditor'
+import { Messages } from './Messages'
+import { SchemaFlow } from './SchemaFlow'
+import { getAssistantResponse } from './getAssistantMessage'
+
+export interface ThreadPageProps {
+ params: {
+ thread_id: string
+ message_id: string
+ }
+}
+
+export default async function ThreadPage({ params }: ThreadPageProps) {
+ const promise = getAssistantResponse(params.thread_id, params.message_id)
+
+ return (
+
+ )
+}
+
+export default Threads
diff --git a/apps/database-new/app/profile/layout.tsx b/apps/database-new/app/profile/layout.tsx
new file mode 100644
index 00000000000..89d3d8e6058
--- /dev/null
+++ b/apps/database-new/app/profile/layout.tsx
@@ -0,0 +1,3 @@
+export default function Layout({ children }: { children: React.ReactNode }) {
+ return
{children}
+}
diff --git a/apps/database-new/app/profile/page.tsx b/apps/database-new/app/profile/page.tsx
new file mode 100644
index 00000000000..96046ff681e
--- /dev/null
+++ b/apps/database-new/app/profile/page.tsx
@@ -0,0 +1,81 @@
+import { createClient } from '@/lib/supabase/server'
+import { default as dayjs, default as relativeTime } from 'dayjs'
+import { cookies } from 'next/headers'
+import { redirect } from 'next/navigation'
+import Threads from './Threads'
+import { Suspense } from 'react'
+import ShimmeringLoader from '@/components/Shimmer'
+import type { Metadata } from 'next'
+
+dayjs.extend(relativeTime)
+export const metadata: Metadata = {
+ title: 'database.design | Profile',
+}
+
+// revalidatePath not working in the create route handler
+// force-dynamic to refetch every time if needed
+// just a hack for now
+// export const dynamic = 'force-dynamic'
+
+const Profile = async () => {
+ return (
+
+
+
+ Loading user...}>
+
+
+
+
+
+
+
Past conversations
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+ )
+}
+
+async function ProfileDetails() {
+ const supabase = createClient()
+
+ const {
+ data: { user },
+ } = await supabase.auth.getUser()
+
+ if (!user) redirect('/')
+
+ return !user ? (
+ // make this better!
+
+ ) : null
+}
diff --git a/apps/design-system/components/top-navigation-search.tsx b/apps/design-system/components/top-navigation-search.tsx
new file mode 100644
index 00000000000..3de4610238d
--- /dev/null
+++ b/apps/design-system/components/top-navigation-search.tsx
@@ -0,0 +1,17 @@
+'use client'
+
+import { Search } from 'lucide-react'
+import { Input } from 'ui-patterns/DataInputs/Input'
+
+function TopNavigationSearch() {
+ return (
+ }
+ placeholder="Search Design System..."
+ />
+ )
+}
+
+export { TopNavigationSearch }
diff --git a/apps/design-system/components/top-navigation.tsx b/apps/design-system/components/top-navigation.tsx
new file mode 100644
index 00000000000..7301be52fc7
--- /dev/null
+++ b/apps/design-system/components/top-navigation.tsx
@@ -0,0 +1,38 @@
+// import { docsConfig } from '@/config/docs'
+import Link from 'next/link'
+import { DesignSystemMarks } from './design-system-marks'
+import { ThemeSwitcherDropdown } from './theme-switcher-dropdown'
+import { TopNavigationSearch } from './top-navigation-search'
+import { CommandMenu } from './command-menu'
+
+function TopNavigation() {
+ return (
+
+
+
+
+ )
+}
+
+export default TopNavigation
diff --git a/apps/design-system/config/docs.ts b/apps/design-system/config/docs.ts
new file mode 100644
index 00000000000..4e1a7be559d
--- /dev/null
+++ b/apps/design-system/config/docs.ts
@@ -0,0 +1,380 @@
+import { MainNavItem, SidebarNavItem } from 'types/nav'
+
+interface DocsConfig {
+ mainNav?: MainNavItem[]
+ sidebarNav: SidebarNavItem[]
+}
+
+export const docsConfig: DocsConfig = {
+ // mainNav: [
+ // {
+ // title: 'Documentation',
+ // href: '/docs',
+ // },
+ // {
+ // title: 'Components',
+ // href: '/docs/components/accordion',
+ // },
+ // {
+ // title: 'Themes',
+ // href: '/themes',
+ // },
+ // {
+ // title: 'Examples',
+ // href: '/examples',
+ // },
+ // {
+ // title: 'Blocks',
+ // href: '/blocks',
+ // },
+ // ],
+ sidebarNav: [
+ {
+ title: 'Getting Started',
+ items: [
+ {
+ title: 'Introduction',
+ href: '/docs',
+ items: [],
+ },
+ {
+ title: 'Color usage',
+ href: '/docs/color-usage',
+ items: [],
+ },
+ {
+ title: 'Tailwind classes',
+ href: '/docs/tailwind-classes',
+ items: [],
+ },
+ {
+ title: 'Theming',
+ href: '/docs/theming',
+ items: [],
+ },
+ {
+ title: 'Icons',
+ href: '/docs/icons',
+ items: [],
+ },
+ {
+ title: 'Figma',
+ href: '/docs/figma',
+ items: [],
+ },
+ {
+ title: 'Changelog',
+ href: '/docs/changelog',
+ items: [],
+ },
+ ],
+ },
+ {
+ title: 'Fragment Components',
+ items: [
+ {
+ title: 'Introduction',
+ href: '/docs/components/fragment-components',
+ items: [],
+ },
+ {
+ title: 'Admonition',
+ href: '/docs/fragments/admonition',
+ items: [],
+ },
+ {
+ title: 'Modal',
+ href: '/docs/fragments/modal',
+ items: [],
+ },
+ {
+ title: 'Text Confirm Dialog',
+ href: '/docs/fragments/text-confirm-dialog',
+ items: [],
+ },
+ {
+ title: 'Info Tooltip',
+ href: '/docs/fragments/info-tooltip',
+ items: [],
+ },
+ {
+ title: 'Form Item Layout',
+ href: '/docs/fragments/form-item-layout',
+ items: [],
+ },
+ {
+ title: 'Multi Select',
+ href: '/docs/fragments/multi-select',
+ items: [],
+ },
+ ],
+ },
+ {
+ title: 'Atom Components',
+ items: [
+ {
+ title: 'Introduction',
+ href: '/docs/components/atom-components',
+ items: [],
+ },
+ {
+ title: 'Accordion',
+ href: '/docs/components/accordion',
+ items: [],
+ },
+ {
+ title: 'Alert',
+ href: '/docs/components/alert',
+ items: [],
+ },
+ {
+ title: 'Alert Dialog',
+ href: '/docs/components/alert-dialog',
+ items: [],
+ },
+ {
+ title: 'Aspect Ratio',
+ href: '/docs/components/aspect-ratio',
+ items: [],
+ },
+ {
+ title: 'Avatar',
+ href: '/docs/components/avatar',
+ items: [],
+ },
+ {
+ title: 'Badge',
+ href: '/docs/components/badge',
+ items: [],
+ },
+ {
+ title: 'Breadcrumb',
+ href: '/docs/components/breadcrumb',
+ items: [],
+ label: 'New',
+ },
+ {
+ title: 'Button',
+ href: '/docs/components/button',
+ items: [],
+ },
+ {
+ title: 'Calendar',
+ href: '/docs/components/calendar',
+ items: [],
+ },
+ {
+ title: 'Card',
+ href: '/docs/components/card',
+ items: [],
+ },
+ {
+ title: 'Carousel',
+ href: '/docs/components/carousel',
+ items: [],
+ },
+ {
+ title: 'Checkbox',
+ href: '/docs/components/checkbox',
+ items: [],
+ },
+ {
+ title: 'Collapsible',
+ href: '/docs/components/collapsible',
+ items: [],
+ },
+ {
+ title: 'Combobox',
+ href: '/docs/components/combobox',
+ items: [],
+ },
+ {
+ title: 'Command',
+ href: '/docs/components/command',
+ items: [],
+ },
+ {
+ title: 'Context Menu',
+ href: '/docs/components/context-menu',
+ items: [],
+ },
+ {
+ title: 'Data Table',
+ href: '/docs/components/data-table',
+ items: [],
+ },
+ {
+ title: 'Date Picker',
+ href: '/docs/components/date-picker',
+ items: [],
+ },
+ {
+ title: 'Dialog',
+ href: '/docs/components/dialog',
+ items: [],
+ },
+ {
+ title: 'Drawer',
+ href: '/docs/components/drawer',
+ items: [],
+ },
+ {
+ title: 'Dropdown Menu',
+ href: '/docs/components/dropdown-menu',
+ items: [],
+ },
+ {
+ title: 'Form',
+ href: '/docs/components/form',
+ items: [],
+ },
+ {
+ title: 'Hover Card',
+ href: '/docs/components/hover-card',
+ items: [],
+ },
+ {
+ title: 'Input',
+ href: '/docs/components/input',
+ items: [],
+ },
+ {
+ title: 'Input OTP',
+ href: '/docs/components/input-otp',
+ items: [],
+ label: 'New',
+ },
+ {
+ title: 'Label',
+ href: '/docs/components/label',
+ items: [],
+ },
+ {
+ title: 'Menubar',
+ href: '/docs/components/menubar',
+ items: [],
+ },
+ {
+ title: 'Navigation Menu',
+ href: '/docs/components/navigation-menu',
+ items: [],
+ },
+ {
+ title: 'Pagination',
+ href: '/docs/components/pagination',
+ items: [],
+ },
+ {
+ title: 'Popover',
+ href: '/docs/components/popover',
+ items: [],
+ },
+ {
+ title: 'Progress',
+ href: '/docs/components/progress',
+ items: [],
+ },
+ {
+ title: 'Radio Group',
+ href: '/docs/components/radio-group',
+ items: [],
+ },
+ {
+ title: 'Radio Group Stacked',
+ href: '/docs/components/radio-group-stacked',
+ items: [],
+ },
+ {
+ title: 'Radio Group Card',
+ href: '/docs/components/radio-group-card',
+ items: [],
+ },
+ {
+ title: 'Resizable',
+ href: '/docs/components/resizable',
+ items: [],
+ },
+ {
+ title: 'Scroll Area',
+ href: '/docs/components/scroll-area',
+ items: [],
+ },
+ {
+ title: 'Select',
+ href: '/docs/components/select',
+ items: [],
+ },
+ {
+ title: 'Separator',
+ href: '/docs/components/separator',
+ items: [],
+ },
+ {
+ title: 'Sheet',
+ href: '/docs/components/sheet',
+ items: [],
+ },
+ {
+ title: 'Skeleton',
+ href: '/docs/components/skeleton',
+ items: [],
+ },
+ {
+ title: 'Slider',
+ href: '/docs/components/slider',
+ items: [],
+ },
+ {
+ title: 'Sonner',
+ href: '/docs/components/sonner',
+ items: [],
+ },
+ {
+ title: 'Switch',
+ href: '/docs/components/switch',
+ items: [],
+ },
+ {
+ title: 'Table',
+ href: '/docs/components/table',
+ items: [],
+ },
+ {
+ title: 'Tabs',
+ href: '/docs/components/tabs',
+ items: [],
+ },
+ {
+ title: 'Textarea',
+ href: '/docs/components/textarea',
+ items: [],
+ },
+ {
+ title: 'Toast',
+ href: '/docs/components/toast',
+ items: [],
+ },
+ {
+ title: 'Toggle',
+ href: '/docs/components/toggle',
+ items: [],
+ },
+ {
+ title: 'Toggle Group',
+ href: '/docs/components/toggle-group',
+ items: [],
+ },
+ {
+ title: 'Tooltip',
+ href: '/docs/components/tooltip',
+ items: [],
+ },
+ {
+ title: 'Tree View',
+ href: '/docs/components/tree-view',
+ items: [],
+ },
+ ],
+ },
+ ],
+}
diff --git a/apps/design-system/config/site.ts b/apps/design-system/config/site.ts
new file mode 100644
index 00000000000..b858b897e73
--- /dev/null
+++ b/apps/design-system/config/site.ts
@@ -0,0 +1,17 @@
+export const siteConfig = {
+ name: 'Supabase Design System',
+ url: 'https://supabase.com/design-system',
+ ogImage: 'https://supabase.com/design-system/og.jpg',
+ description: 'Design System of Supabase',
+ links: {
+ twitter: 'https://twitter.com/supabase',
+ github: 'https://github.com/supabase/supabase/tree/master/apps/design-system',
+ credits: {
+ radix: 'https://www.radix-ui.com/themes/docs/overview/getting-started',
+ shadcn: 'https://ui.shadcn.com/',
+ geist: 'https://vercel.com/geist/introduction',
+ },
+ },
+}
+
+export type SiteConfig = typeof siteConfig
diff --git a/apps/design-system/content/docs/changelog.mdx b/apps/design-system/content/docs/changelog.mdx
new file mode 100644
index 00000000000..c84c07d16da
--- /dev/null
+++ b/apps/design-system/content/docs/changelog.mdx
@@ -0,0 +1,26 @@
+---
+title: Changelog
+description: Latest updates and announcements.
+toc: false
+---
+
+## 24th May 2024 - New components and docs
+
+### New components added
+
+- [Multi Select](/design-system/components/multi-select)
+
+### New components documented
+
+- [Radio Group Card](/design-system/docs/components/radio-group-card)
+- [Radio Group Stacked](/design-system/docs/components/radio-group-stacked)
+- [Info Tooltip](/design-system/docs/components/info-tooltip)
+- [Admonition](/design-system/docs/components/admonition)
+
+### New colors
+
+`bg-surface-75` tailwind color fixed for Dark theme
+
+## 22nd May 2024 - Introducing Design System
+
+We're introducing [Supabase Design System](/design-system), a home for Design related resources for Supabase
diff --git a/apps/design-system/content/docs/color-usage.mdx b/apps/design-system/content/docs/color-usage.mdx
new file mode 100644
index 00000000000..aed6907d2b0
--- /dev/null
+++ b/apps/design-system/content/docs/color-usage.mdx
@@ -0,0 +1,74 @@
+---
+title: Color usage
+description: Colors system breakdown with best practise
+---
+
+Colors available in the Supabase Design System
+
+These are examples of using colors with shorthands.
+
+## Background
+
+
+
+### App backgrounds
+
+We use backgrounds in 2 different ways. In the ./www and ./docs sites, we use a darker background, so we have an extra background color we can use
+
+```jsx
+/**
+ * ./www background color
+ * ./docs background color
+ */
+{children}
+
+/**
+ * ./studio background color
+ */
+{children}
+```
+
+### Backgrounds and Surfaces
+
+#### `./apps/www` + `./apps/docs`
+
+We use surfaces in 2 different ways. In the ./www and ./docs sites, we use a darker background, so we have an extra surface color we can use
+
+
+
+#### `./apps/studio`
+
+For the studio (dashbaord) we can use `bg-surface-100`, `bg-surface-200`, `bg-surface-300`
+
+
+
+#### Data grid and frame space
+
+Data grids use an alternative background color for empty space to add depth to the layout.
+The background of the empty space is the same background as used in `./apps/docs` and `./apps/www` - although; the color has been mapped to `bg-alternative` so it works well across different themes.
+
+
+
+Dealing with large areas of emmpty space in data display should also be catered for. You can use the `bg-200` or `bg` class to fill the space.
+
+### Overlays
+
+We use the `./bg-overlay` background color for overlays.
+This is not to be confused with `Dialogs`, they require to use the same app background color as the site.
+
+## Border
+
+
+
+## Text
+
+These can also be accessed with `foreground`. Like `text-foreground-light`.
+
+
+
+## Other Colors
+
+These can also be accessed with `foreground`. Like `text-foreground-light`.
+
+
+```
diff --git a/apps/design-system/content/docs/components/accordion.mdx b/apps/design-system/content/docs/components/accordion.mdx
new file mode 100644
index 00000000000..9190c8c8248
--- /dev/null
+++ b/apps/design-system/content/docs/components/accordion.mdx
@@ -0,0 +1,139 @@
+---
+title: Accordion
+description: A vertically stacked set of interactive headings that each reveal a section of content.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/accordion
+ api: https://www.radix-ui.com/docs/primitives/components/accordion#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+
+
+Run the following command:
+
+```bash
+npx shadcn-ui@latest add accordion
+```
+
+Update `tailwind.config.js`
+
+Add the following animations to your `tailwind.config.js` file:
+
+```js title="tailwind.config.js" {5-18}
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ theme: {
+ extend: {
+ keyframes: {
+ 'accordion-down': {
+ from: { height: '0' },
+ to: { height: 'var(--radix-accordion-content-height)' },
+ },
+ 'accordion-up': {
+ from: { height: 'var(--radix-accordion-content-height)' },
+ to: { height: '0' },
+ },
+ },
+ animation: {
+ 'accordion-down': 'accordion-down 0.2s ease-out',
+ 'accordion-up': 'accordion-up 0.2s ease-out',
+ },
+ },
+ },
+}
+```
+
+
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-accordion
+```
+
+Copy and paste the following code into your project.
+
+{/* */}
+
+Update the import paths to match your project setup.
+
+Update `tailwind.config.js`
+
+Add the following animations to your `tailwind.config.js` file:
+
+```js title="tailwind.config.js" {5-18}
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ theme: {
+ extend: {
+ keyframes: {
+ 'accordion-down': {
+ from: { height: '0' },
+ to: { height: 'var(--radix-accordion-content-height)' },
+ },
+ 'accordion-up': {
+ from: { height: 'var(--radix-accordion-content-height)' },
+ to: { height: '0' },
+ },
+ },
+ animation: {
+ 'accordion-down': 'accordion-down 0.2s ease-out',
+ 'accordion-up': 'accordion-up 0.2s ease-out',
+ },
+ },
+ },
+}
+```
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from '@/components/ui/accordion'
+```
+
+```tsx
+
+
+ Is it accessible?
+ Yes. It adheres to the WAI-ARIA design pattern.
+
+
+```
diff --git a/apps/design-system/content/docs/components/alert copy.mdx b/apps/design-system/content/docs/components/alert copy.mdx
new file mode 100644
index 00000000000..1ada949fd9c
--- /dev/null
+++ b/apps/design-system/content/docs/components/alert copy.mdx
@@ -0,0 +1,65 @@
+---
+title: Alert
+description: Displays a callout for user attention.
+component: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add alert
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+```
+
+```tsx
+
+
+ Heads up!
+
+ You can add components and dependencies to your app using the cli.
+
+
+```
+
+## Examples
+
+### Default
+
+
+
+### Destructive
+
+
diff --git a/apps/design-system/content/docs/components/alert-dialog.mdx b/apps/design-system/content/docs/components/alert-dialog.mdx
new file mode 100644
index 00000000000..10c28d1f137
--- /dev/null
+++ b/apps/design-system/content/docs/components/alert-dialog.mdx
@@ -0,0 +1,87 @@
+---
+title: Alert Dialog
+description: A modal dialog that interrupts the user with important content and expects a response.
+featured: true
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/alert-dialog
+ api: https://www.radix-ui.com/docs/primitives/components/alert-dialog#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add alert-dialog
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-alert-dialog
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@/components/ui/alert-dialog'
+```
+
+```tsx
+
+ Open
+
+
+ Are you absolutely sure?
+
+ This action cannot be undone. This will permanently delete your account and remove your data
+ from our servers.
+
+
+
+ Cancel
+ Continue
+
+
+
+```
diff --git a/apps/design-system/content/docs/components/alert.mdx b/apps/design-system/content/docs/components/alert.mdx
new file mode 100644
index 00000000000..0f0a031a2a1
--- /dev/null
+++ b/apps/design-system/content/docs/components/alert.mdx
@@ -0,0 +1,79 @@
+---
+title: Alert
+description: Displays a callout for user attention.
+component: true
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add alert
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
+```
+
+```tsx
+
+
+ Heads up!
+
+ You can add components and dependencies to your app using the cli.
+
+
+```
+
+## Examples
+
+### Default
+
+
+
+### Destructive
+
+
diff --git a/apps/design-system/content/docs/components/aspect-ratio.mdx b/apps/design-system/content/docs/components/aspect-ratio.mdx
new file mode 100644
index 00000000000..4ddf98dfddb
--- /dev/null
+++ b/apps/design-system/content/docs/components/aspect-ratio.mdx
@@ -0,0 +1,67 @@
+---
+title: Aspect Ratio
+description: Displays content within a desired ratio.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/aspect-ratio
+ api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add aspect-ratio
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-aspect-ratio
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import Image from 'next/image'
+
+import { AspectRatio } from '@/components/ui/aspect-ratio'
+```
+
+```tsx
+
+
+
+
+
+```
diff --git a/apps/design-system/content/docs/components/atom-components.mdx b/apps/design-system/content/docs/components/atom-components.mdx
new file mode 100644
index 00000000000..8952b428085
--- /dev/null
+++ b/apps/design-system/content/docs/components/atom-components.mdx
@@ -0,0 +1,4 @@
+---
+title: Atom components
+description:
+---
diff --git a/apps/design-system/content/docs/components/avatar.mdx b/apps/design-system/content/docs/components/avatar.mdx
new file mode 100644
index 00000000000..f6fda6a3d8b
--- /dev/null
+++ b/apps/design-system/content/docs/components/avatar.mdx
@@ -0,0 +1,64 @@
+---
+title: Avatar
+description: An image element with a fallback for representing the user.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/avatar
+ api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add avatar
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-avatar
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
+```
+
+```tsx
+
+
+ CN
+
+```
diff --git a/apps/design-system/content/docs/components/badge.mdx b/apps/design-system/content/docs/components/badge.mdx
new file mode 100644
index 00000000000..d5b22c47a79
--- /dev/null
+++ b/apps/design-system/content/docs/components/badge.mdx
@@ -0,0 +1,87 @@
+---
+title: Badge
+description: Displays a badge or a component that looks like a badge.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add badge
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Badge } from '@/components/ui/badge'
+```
+
+```tsx
+Badge
+```
+
+### Link
+
+You can use the `badgeVariants` helper to create a link that looks like a badge.
+
+```tsx
+import { badgeVariants } from '@/components/ui/badge'
+```
+
+```tsx
+Badge
+```
+
+## Examples
+
+### Default
+
+
+
+---
+
+### Secondary
+
+
+
+---
+
+### Outline
+
+
+
+---
+
+### Destructive
+
+
diff --git a/apps/design-system/content/docs/components/breadcrumb.mdx b/apps/design-system/content/docs/components/breadcrumb.mdx
new file mode 100644
index 00000000000..4665d2938bf
--- /dev/null
+++ b/apps/design-system/content/docs/components/breadcrumb.mdx
@@ -0,0 +1,190 @@
+---
+title: Breadcrumb
+description: Displays the path to the current resource using a hierarchy of links.
+component: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add breadcrumb
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from '@/components/ui/breadcrumb'
+```
+
+```tsx
+
+
+
+ Home
+
+
+
+ Components
+
+
+
+ Breadcrumb
+
+
+
+```
+
+## Examples
+
+### Custom separator
+
+Use a custom component as `children` for `` to create a custom separator.
+
+
+
+```tsx showLineNumbers {1,10-12}
+import { Slash } from "lucide-react"
+
+...
+
+
+
+
+ Home
+
+
+
+
+
+ Components
+
+
+
+```
+
+---
+
+### Dropdown
+
+You can compose `` with a `` to create a dropdown in the breadcrumb.
+
+
+
+```tsx showLineNumbers {1-6,11-21}
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+
+...
+
+
+
+
+ Components
+
+
+
+ Documentation
+ Themes
+ GitHub
+
+
+
+```
+
+---
+
+### Collapsed
+
+We provide a `` component to show a collapsed state when the breadcrumb is too long.
+
+
+
+```tsx showLineNumbers {1,9}
+import { BreadcrumbEllipsis } from "@/components/ui/breadcrumb"
+
+...
+
+
+
+ {/* ... */}
+
+
+
+ {/* ... */}
+
+
+```
+
+---
+
+### Link component
+
+To use a custom link component from your routing library, you can use the `asChild` prop on ``.
+
+
+
+```tsx showLineNumbers {1,8-10}
+import { Link } from "next/link"
+
+...
+
+
+
+
+
+ Home
+
+
+ {/* ... */}
+
+
+```
+
+---
+
+### Responsive
+
+Here's an example of a responsive breadcrumb that composes `` with ``, ``, and ``.
+
+It displays a dropdown on desktop and a drawer on mobile.
+
+
diff --git a/apps/design-system/content/docs/components/button.mdx b/apps/design-system/content/docs/components/button.mdx
new file mode 100644
index 00000000000..8a180d45636
--- /dev/null
+++ b/apps/design-system/content/docs/components/button.mdx
@@ -0,0 +1,124 @@
+---
+title: Button
+description: Displays a button or a component that looks like a button.
+featured: true
+component: true
+---
+
+
+
+## Usage
+
+```tsx
+import { Button } from '@/components/ui/button'
+```
+
+```tsx
+
+```
+
+_It is likely that the `type` prop will be changed to `variant` in the future._
+
+## Link
+
+You can use the `buttonVariants` helper to create a link that looks like a button.
+
+```tsx
+import { buttonVariants } from '@/components/ui/button'
+```
+
+```tsx
+Click here
+```
+
+Alternatively, you can set the `asChild` parameter and nest the link component.
+
+```tsx
+
+```
+
+## Examples
+
+### Sizes
+
+Use the `size` prop to determine the size of the button.
+
+
+
+### Types
+
+These are all the different `type` variations.
+
+#### Primary
+
+Used for data insertion actions, confirming purchases, strong positive actions.
+
+
+
+#### Default
+
+Used for opening dialogs, navigating to pages, and other non CRUD actions.
+
+This `type` will probably be the most used button type.
+It will probably be changed to be the default type in future.
+
+
+
+#### Secondary
+
+Can be used for signaling a data or config change, but not as serious as a primary button.
+For destructuve or side effect actions, use the `destructive` or `warning` type.
+
+
+
+#### Warning
+
+Used for actions that might have a side effect, but not as serious as a destructive action.
+
+
+
+#### Destructive (currently `danger`)
+
+Used for actions that will have a serios destructive side effect, like deleting data.
+
+prop `type` will probably be changed to `destructive` in the future.
+
+
+
+#### Outline
+
+Used for secondary actions, or actions that are not as important as the primary action.
+
+
+
+#### Ghost (currently `text`)
+
+Used for actions that are not as important as the primary action, or for actions that are not as important as the primary action.
+
+prop `type` will probably be changed to `ghost` in the future.
+
+
+
+#### Link
+
+Used for actions that are not as important as the primary action, or for actions that are not as important as the primary action.
+
+
+
+### Only an Icon
+
+Dispaying only an Icon in a button.
+
+
+ We should update the button component to support this use case better.
+
+
+
+
+### As Child
+
+Supports slot behavior with `asChild` prop.
+
+
diff --git a/apps/design-system/content/docs/components/calendar.mdx b/apps/design-system/content/docs/components/calendar.mdx
new file mode 100644
index 00000000000..9b1d4187cbb
--- /dev/null
+++ b/apps/design-system/content/docs/components/calendar.mdx
@@ -0,0 +1,81 @@
+---
+title: Calendar
+description: A date field component that allows users to enter and edit date.
+component: true
+links:
+ doc: https://react-day-picker.js.org
+source:
+ shadcn: true
+---
+
+
+
+## About
+
+The `Calendar` component is built on top of [React DayPicker](https://react-day-picker.js.org).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add calendar
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install react-day-picker date-fns
+```
+
+Add the `Button` component to your project.
+
+The `Calendar` component uses the `Button` component. Make sure you have it installed in your project.
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Calendar } from '@/components/ui/calendar'
+```
+
+```tsx
+const [date, setDate] = React.useState(new Date())
+
+return
+```
+
+See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
+
+## Date Picker
+
+You can use the `` component to build a date picker. See the [Date Picker](/docs/components/date-picker) page for more information.
+
+## Examples
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/card.mdx b/apps/design-system/content/docs/components/card.mdx
new file mode 100644
index 00000000000..32bfdc8ec07
--- /dev/null
+++ b/apps/design-system/content/docs/components/card.mdx
@@ -0,0 +1,71 @@
+---
+title: Card
+description: Displays a card with header, content, and footer.
+component: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add card
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card'
+```
+
+```tsx
+
+
+ Card Title
+ Card Description
+
+
+
Card Content
+
+
+
Card Footer
+
+
+```
+
+## Examples
+
+
diff --git a/apps/design-system/content/docs/components/carousel.mdx b/apps/design-system/content/docs/components/carousel.mdx
new file mode 100644
index 00000000000..71f3806892e
--- /dev/null
+++ b/apps/design-system/content/docs/components/carousel.mdx
@@ -0,0 +1,277 @@
+---
+title: Carousel
+description: A carousel with motion and swipe built using Embla.
+component: true
+links:
+ doc: https://www.embla-carousel.com/get-started/react
+ api: https://www.embla-carousel.com/api
+---
+
+
+
+## About
+
+The carousel component is built using the [Embla Carousel](https://www.embla-carousel.com/) library.
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+```bash
+npx shadcn-ui@latest add carousel
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install embla-carousel-react
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Carousel,
+ CarouselContent,
+ CarouselItem,
+ CarouselNext,
+ CarouselPrevious,
+} from '@/components/ui/carousel'
+```
+
+```tsx
+
+
+ ...
+ ...
+ ...
+
+
+
+
+```
+
+## Examples
+
+### Sizes
+
+To set the size of the items, you can use the `basis` utility class on the ``.
+
+
+
+```tsx title="Example" showLineNumbers {4-6}
+// 33% of the carousel width.
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+```tsx title="Responsive" showLineNumbers {4-6}
+// 50% on small screens and 33% on larger screens.
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+### Spacing
+
+To set the spacing between the items, we use a `pl-[VALUE]` utility on the `` and a negative `-ml-[VALUE]` on the ``.
+
+
+ **Why:** I tried to use the `gap` property or a `grid` layout on the `
+ ` but it required a lot of math and mental effort to get the
+ spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to
+ use.
+
+You can always adjust this in your own project if you need to.
+
+
+
+
+
+```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+```tsx title="Responsive" showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+### Orientation
+
+Use the `orientation` prop to set the orientation of the carousel.
+
+
+
+```tsx showLineNumbers /vertical | horizontal/
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+## Options
+
+You can pass options to the carousel using the `opts` prop. See the [Embla Carousel docs](https://www.embla-carousel.com/api/options/) for more information.
+
+```tsx showLineNumbers {2-5}
+
+
+ ...
+ ...
+ ...
+
+
+```
+
+## API
+
+Use a state and the `setApi` props to get an instance of the carousel API.
+
+
+
+```tsx showLineNumbers {1,4,22}
+import { type CarouselApi } from '@/components/ui/carousel'
+
+export function Example() {
+ const [api, setApi] = React.useState()
+ const [current, setCurrent] = React.useState(0)
+ const [count, setCount] = React.useState(0)
+
+ React.useEffect(() => {
+ if (!api) {
+ return
+ }
+
+ setCount(api.scrollSnapList().length)
+ setCurrent(api.selectedScrollSnap() + 1)
+
+ api.on('select', () => {
+ setCurrent(api.selectedScrollSnap() + 1)
+ })
+ }, [api])
+
+ return (
+
+
+ ...
+ ...
+ ...
+
+
+ )
+}
+```
+
+## Events
+
+You can listen to events using the api instance from `setApi`.
+
+```tsx showLineNumbers {1,4-14,16}
+import { type CarouselApi } from '@/components/ui/carousel'
+
+export function Example() {
+ const [api, setApi] = React.useState()
+
+ React.useEffect(() => {
+ if (!api) {
+ return
+ }
+
+ api.on('select', () => {
+ // Do something on select.
+ })
+ }, [api])
+
+ return (
+
+
+ ...
+ ...
+ ...
+
+
+ )
+}
+```
+
+See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for more information on using events.
+
+## Plugins
+
+You can use the `plugins` prop to add plugins to the carousel.
+
+```ts showLineNumbers {1,6-10}
+import Autoplay from "embla-carousel-autoplay"
+
+export function Example() {
+ return (
+
+ // ...
+
+ )
+}
+```
+
+
+
+See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on using plugins.
diff --git a/apps/design-system/content/docs/components/checkbox.mdx b/apps/design-system/content/docs/components/checkbox.mdx
new file mode 100644
index 00000000000..fc7b7180d41
--- /dev/null
+++ b/apps/design-system/content/docs/components/checkbox.mdx
@@ -0,0 +1,77 @@
+---
+title: Checkbox
+description: A control that allows the user to toggle between checked and not checked.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/checkbox
+ api: https://www.radix-ui.com/docs/primitives/components/checkbox#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add checkbox
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-checkbox
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Checkbox } from '@/components/ui/checkbox'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### With text
+
+
+
+### Disabled
+
+
+
+### Form
+
+
+
+
diff --git a/apps/design-system/content/docs/components/collapsible.mdx b/apps/design-system/content/docs/components/collapsible.mdx
new file mode 100644
index 00000000000..3f5be4bb44b
--- /dev/null
+++ b/apps/design-system/content/docs/components/collapsible.mdx
@@ -0,0 +1,67 @@
+---
+title: Collapsible
+description: An interactive component which expands/collapses a panel.
+component: true
+featured: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/collapsible
+ api: https://www.radix-ui.com/docs/primitives/components/collapsible#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add collapsible
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-collapsible
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
+```
+
+```tsx
+
+ Can I use this in my project?
+
+ Yes. Free to use for personal and commercial projects. No attribution required.
+
+
+```
diff --git a/apps/design-system/content/docs/components/combobox.mdx b/apps/design-system/content/docs/components/combobox.mdx
new file mode 100644
index 00000000000..209f3a54789
--- /dev/null
+++ b/apps/design-system/content/docs/components/combobox.mdx
@@ -0,0 +1,131 @@
+---
+title: Combobox
+description: Autocomplete input and command palette with a list of suggestions.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+The Combobox is built using a composition of the `` and the `` components.
+
+See installation instructions for the [Popover](/docs/components/popover#installation) and the [Command](/docs/components/command#installation) components.
+
+## Usage
+
+```tsx
+'use client'
+
+import * as React from 'react'
+import { Check, ChevronsUpDown } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+import { Button } from '@/components/ui/button'
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+} from '@/components/ui/command'
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
+
+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',
+ },
+]
+
+export function ComboboxDemo() {
+ const [open, setOpen] = React.useState(false)
+ const [value, setValue] = React.useState('')
+
+ return (
+
+
+
+
+
+
+
+ No framework found.
+
+ {frameworks.map((framework) => (
+ {
+ setValue(currentValue === value ? '' : currentValue)
+ setOpen(false)
+ }}
+ >
+
+ {framework.label}
+
+ ))}
+
+
+
+
+ )
+}
+```
+
+## Examples
+
+### Combobox
+
+
+
+### Popover
+
+
+
+### Dropdown menu
+
+
+
+### Responsive
+
+You can create a responsive combobox by using the `` on desktop and the `` components on mobile.
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/command.mdx b/apps/design-system/content/docs/components/command.mdx
new file mode 100644
index 00000000000..cae6977b6e9
--- /dev/null
+++ b/apps/design-system/content/docs/components/command.mdx
@@ -0,0 +1,138 @@
+---
+title: Command
+description: Fast, composable, unstyled command menu for React.
+component: true
+links:
+ doc: https://cmdk.paco.me
+source:
+ shadcn: true
+---
+
+
+
+## About
+
+The `` component uses the [`cmdk`](https://cmdk.paco.me) component by [pacocoursey](https://twitter.com/pacocoursey).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add command
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install cmdk
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Command,
+ CommandDialog,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
+ CommandShortcut,
+} from '@/components/ui/command'
+```
+
+```tsx
+
+
+
+ No results found.
+
+ Calendar
+ Search Emoji
+ Calculator
+
+
+
+ Profile
+ Billing
+ Settings
+
+
+
+```
+
+## Examples
+
+### Dialog
+
+
+
+To show the command menu in a dialog, use the `` component.
+
+```tsx
+export function CommandMenu() {
+ const [open, setOpen] = React.useState(false)
+
+ React.useEffect(() => {
+ const down = (e: KeyboardEvent) => {
+ if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
+ e.preventDefault()
+ setOpen((open) => !open)
+ }
+ }
+ document.addEventListener('keydown', down)
+ return () => document.removeEventListener('keydown', down)
+ }, [])
+
+ return (
+
+
+
+ No results found.
+
+ Calendar
+ Search Emoji
+ Calculator
+
+
+
+ )
+}
+```
+
+### Combobox
+
+You can use the `` component as a combobox. See the [Combobox](/docs/components/combobox) page for more information.
diff --git a/apps/design-system/content/docs/components/context-menu.mdx b/apps/design-system/content/docs/components/context-menu.mdx
new file mode 100644
index 00000000000..4bd06b6baa1
--- /dev/null
+++ b/apps/design-system/content/docs/components/context-menu.mdx
@@ -0,0 +1,74 @@
+---
+title: Context Menu
+description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/context-menu
+ api: https://www.radix-ui.com/docs/primitives/components/context-menu#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add context-menu
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-context-menu
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuTrigger,
+} from '@/components/ui/context-menu'
+```
+
+```tsx
+
+ Right click
+
+ Profile
+ Billing
+ Team
+ Subscription
+
+
+```
diff --git a/apps/design-system/content/docs/components/data-table.mdx b/apps/design-system/content/docs/components/data-table.mdx
new file mode 100644
index 00000000000..d2e6620145e
--- /dev/null
+++ b/apps/design-system/content/docs/components/data-table.mdx
@@ -0,0 +1,842 @@
+---
+title: Data Table
+description: Powerful table and datagrids built using TanStack Table.
+component: true
+links:
+ doc: https://tanstack.com/table/v8/docs/guide/introduction
+---
+
+
+
+## Introduction
+
+Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources.
+
+It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/guide/introduction#what-is-headless-ui) provides.
+
+So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own.
+
+We'll start with the basic `
` component and build a complex data table from scratch.
+
+
+
+**Tip:** If you find yourself using the same table in multiple places in your app, you can always extract it into a reusable component.
+
+
+
+## Table of Contents
+
+This guide will show you how to use [TanStack Table](https://tanstack.com/table) and the `
` component to build your own custom data table. We'll cover the following topics:
+
+- [Basic Table](#basic-table)
+- [Row Actions](#row-actions)
+- [Pagination](#pagination)
+- [Sorting](#sorting)
+- [Filtering](#filtering)
+- [Visibility](#visibility)
+- [Row Selection](#row-selection)
+- [Reusable Components](#reusable-components)
+
+## Installation
+
+1. Add the `
` component to your project:
+
+```bash
+npx shadcn-ui@latest add table
+```
+
+2. Add `tanstack/react-table` dependency:
+
+```bash
+npm install @tanstack/react-table
+```
+
+## Prerequisites
+
+We are going to build a table to show recent payments. Here's what our data looks like:
+
+```tsx showLineNumbers
+type Payment = {
+ id: string
+ amount: number
+ status: 'pending' | 'processing' | 'success' | 'failed'
+ email: string
+}
+
+export const payments: Payment[] = [
+ {
+ id: '728ed52f',
+ amount: 100,
+ status: 'pending',
+ email: 'm@example.com',
+ },
+ {
+ id: '489e1d42',
+ amount: 125,
+ status: 'processing',
+ email: 'example@gmail.com',
+ },
+ // ...
+]
+```
+
+## Project Structure
+
+Start by creating the following file structure:
+
+```txt
+app
+└── payments
+ ├── columns.tsx
+ ├── data-table.tsx
+ └── page.tsx
+```
+
+I'm using a Next.js example here but this works for any other React framework.
+
+- `columns.tsx` (client component) will contain our column definitions.
+- `data-table.tsx` (client component) will contain our `` component.
+- `page.tsx` (server component) is where we'll fetch data and render our table.
+
+## Basic Table
+
+Let's start by building a basic table.
+
+
+
+### Column Definitions
+
+First, we'll define our columns.
+
+```tsx showLineNumbers title="app/payments/columns.tsx" {3,14-27}
+'use client'
+
+import { ColumnDef } from '@tanstack/react-table'
+
+// This type is used to define the shape of our data.
+// You can use a Zod schema here if you want.
+export type Payment = {
+ id: string
+ amount: number
+ status: 'pending' | 'processing' | 'success' | 'failed'
+ email: string
+}
+
+export const columns: ColumnDef[] = [
+ {
+ accessorKey: 'status',
+ header: 'Status',
+ },
+ {
+ accessorKey: 'email',
+ header: 'Email',
+ },
+ {
+ accessorKey: 'amount',
+ header: 'Amount',
+ },
+]
+```
+
+
+
+**Note:** Columns are where you define the core of what your table
+will look like. They define the data that will be displayed, how it will be
+formatted, sorted and filtered.
+
+
+
+### `` component
+
+Next, we'll create a `` component to render our table.
+
+```tsx showLineNumbers title="app/payments/data-table.tsx"
+'use client'
+
+import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'
+
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from '@/components/ui/table'
+
+interface DataTableProps {
+ columns: ColumnDef[]
+ data: TData[]
+}
+
+export function DataTable({ columns, data }: DataTableProps) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ })
+
+ return (
+
+ )
+}
+```
+
+This adds a checkbox to each row and a checkbox in the header to select all rows.
+
+### Show selected rows
+
+You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API.
+
+```tsx
+
+ {table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length}{' '}
+ row(s) selected.
+
+```
+
+
+
+## Reusable Components
+
+Here are some components you can use to build your data tables. This is from the [Tasks](/examples/tasks) demo.
+
+### Column header
+
+Make any column header sortable and hideable.
+
+
+
+```tsx {5}
+export const columns = [
+ {
+ accessorKey: 'email',
+ header: ({ column }) => ,
+ },
+]
+```
+
+### Pagination
+
+Add pagination controls to your table including page size and selection count.
+
+
+
+```tsx
+
+```
+
+### Column toggle
+
+A component to toggle column visibility.
+
+
+
+```tsx
+
+```
diff --git a/apps/design-system/content/docs/components/date-picker.mdx b/apps/design-system/content/docs/components/date-picker.mdx
new file mode 100644
index 00000000000..0848ee3bdbd
--- /dev/null
+++ b/apps/design-system/content/docs/components/date-picker.mdx
@@ -0,0 +1,74 @@
+---
+title: Date Picker
+description: A date picker component with range and presets.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+The Date Picker is built using a composition of the `` and the `` components.
+
+See installation instructions for the [Popover](/docs/components/popover#installation) and the [Calendar](/docs/components/calendar#installation) components.
+
+## Usage
+
+```tsx
+'use client'
+
+import * as React from 'react'
+import { format } from 'date-fns'
+import { Calendar as CalendarIcon } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+import { Button } from '@/components/ui/button'
+import { Calendar } from '@/components/ui/calendar'
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
+
+export function DatePickerDemo() {
+ const [date, setDate] = React.useState()
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
+```
+
+See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
+
+## Examples
+
+### Date Picker
+
+
+
+### Date Range Picker
+
+
+
+### With Presets
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/dialog.mdx b/apps/design-system/content/docs/components/dialog.mdx
new file mode 100644
index 00000000000..47d29e96eb6
--- /dev/null
+++ b/apps/design-system/content/docs/components/dialog.mdx
@@ -0,0 +1,120 @@
+---
+title: Dialog
+description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
+featured: true
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/dialog
+ api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add dialog
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-dialog
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from '@/components/ui/dialog'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Custom close button
+
+
+
+## Notes
+
+To activate the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or
+`Dropdown Menu` component in the `Dialog` component. For more information, refer to the linked issue [here](https://github.com/radix-ui/primitives/issues/1836).
+
+```tsx {14-25}
+
+```
diff --git a/apps/design-system/content/docs/components/drawer.mdx b/apps/design-system/content/docs/components/drawer.mdx
new file mode 100644
index 00000000000..1767e432663
--- /dev/null
+++ b/apps/design-system/content/docs/components/drawer.mdx
@@ -0,0 +1,95 @@
+---
+title: Drawer
+description: A drawer component for React.
+component: true
+links:
+ doc: https://github.com/emilkowalski/vaul
+source:
+ vaul: true
+ shadcn: true
+---
+
+
+
+## About
+
+Drawer is built on top of [Vaul](https://github.com/emilkowalski/vaul) by [emilkowalski\_](https://twitter.com/emilkowalski_).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add drawer
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install vaul
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx showLineNumbers
+import {
+ Drawer,
+ DrawerClose,
+ DrawerContent,
+ DrawerDescription,
+ DrawerFooter,
+ DrawerHeader,
+ DrawerTitle,
+ DrawerTrigger,
+} from '@/components/ui/drawer'
+```
+
+```tsx showLineNumbers
+
+ Open
+
+
+ Are you absolutely sure?
+ This action cannot be undone.
+
+
+
+
+
+
+
+
+
+```
+
+## Examples
+
+### Responsive Dialog
+
+You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile.
+
+
diff --git a/apps/design-system/content/docs/components/dropdown-menu.mdx b/apps/design-system/content/docs/components/dropdown-menu.mdx
new file mode 100644
index 00000000000..daccc38aa88
--- /dev/null
+++ b/apps/design-system/content/docs/components/dropdown-menu.mdx
@@ -0,0 +1,95 @@
+---
+title: Dropdown Menu
+description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
+featured: true
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/dropdown-menu
+ api: https://www.radix-ui.com/docs/primitives/components/dropdown-menu#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+So I guess I can write anything i want in here.
+
+## Props
+
+{/* */}
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add dropdown-menu
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-dropdown-menu
+```
+
+Copy and paste the following code into your project.
+
+{/* */}
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu'
+```
+
+```tsx
+
+ Open
+
+ My Account
+
+ Profile
+ Billing
+ Team
+ Subscription
+
+
+```
+
+## Examples
+
+### Checkboxes
+
+
+
+### Radio Group
+
+
diff --git a/apps/design-system/content/docs/components/form.mdx b/apps/design-system/content/docs/components/form.mdx
new file mode 100644
index 00000000000..a70a79c0974
--- /dev/null
+++ b/apps/design-system/content/docs/components/form.mdx
@@ -0,0 +1,260 @@
+---
+title: React Hook Form
+description: Building forms with React Hook Form and Zod.
+links:
+ doc: https://react-hook-form.com
+source:
+ shadcn: true
+---
+
+Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex.
+
+Well-designed HTML forms are:
+
+- Well-structured and semantically correct.
+- Easy to use and navigate (keyboard).
+- Accessible with ARIA attributes and proper labels.
+- Has support for client and server side validation.
+- Well-styled and consistent with the rest of the application.
+
+In this guide, we will take a look at building forms with [`react-hook-form`](https://react-hook-form.com/) and [`zod`](https://zod.dev). We're going to use a `` component to compose accessible forms using Radix UI components.
+
+## Features
+
+The `` component is a wrapper around the `react-hook-form` library. It provides a few things:
+
+- Composable components for building forms.
+- A `` component for building controlled form fields.
+- Form validation using `zod`.
+- Handles accessibility and error messages.
+- Uses `React.useId()` for generating unique IDs.
+- Applies the correct `aria` attributes to form fields based on states.
+- Built to work with all Radix UI components.
+- Bring your own schema library. We use `zod` but you can use anything you want.
+- **You have full control over the markup and styling.**
+
+## Anatomy
+
+```tsx
+
+```
+
+
+ **Do not** use the standard [Label](/design-system/docs/components/label) component inside Form
+ components.
+
+
+## Example
+
+```tsx
+const form = useForm()
+
+ (
+
+ Username
+
+
+
+ This is your public display name.
+
+
+ )}
+/>
+```
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+
+### Command
+
+```bash
+npx shadcn-ui@latest add form
+```
+
+
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-label @radix-ui/react-slot react-hook-form @hookform/resolvers zod
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+
+
+### Create a form schema
+
+Define the shape of your form using a Zod schema. You can read more about using Zod in the [Zod documentation](https://zod.dev).
+
+```tsx showLineNumbers {3,5-7}
+'use client'
+
+import { z } from 'zod'
+
+const formSchema = z.object({
+ username: z.string().min(2).max(50),
+})
+```
+
+### Define a form
+
+Use the `useForm` hook from `react-hook-form` to create a form.
+
+```tsx showLineNumbers {3-4,14-20,22-27}
+'use client'
+
+import { zodResolver } from '@hookform/resolvers/zod'
+import { useForm } from 'react-hook-form'
+import { z } from 'zod'
+
+const formSchema = z.object({
+ username: z.string().min(2, {
+ message: 'Username must be at least 2 characters.',
+ }),
+})
+
+export function ProfileForm() {
+ // 1. Define your form.
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ username: '',
+ },
+ })
+
+ // 2. Define a submit handler.
+ function onSubmit(values: z.infer) {
+ // Do something with the form values.
+ // ✅ This will be type-safe and validated.
+ console.log(values)
+ }
+}
+```
+
+Since `FormField` is using a controlled component, you need to provide a default value for the field. See the [React Hook Form docs](https://react-hook-form.com/docs/usecontroller) to learn more about controlled components.
+
+### Build your form
+
+We can now use the `` components to build our form.
+
+```tsx showLineNumbers {7-17,28-50}
+'use client'
+
+import { zodResolver } from '@hookform/resolvers/zod'
+import { useForm } from 'react-hook-form'
+import { z } from 'zod'
+
+import { Button } from '@/components/ui/button'
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form'
+import { Input } from '@/components/ui/input'
+
+const formSchema = z.object({
+ username: z.string().min(2, {
+ message: 'Username must be at least 2 characters.',
+ }),
+})
+
+export function ProfileForm() {
+ // ...
+
+ return (
+
+
+ )
+}
+```
+
+### Done
+
+That's it. You now have a fully accessible form that is type-safe with client-side validation.
+
+
+
+
+
+## Examples
+
+See the following links for more examples on how to use the `` component with other components:
+
+- [Checkbox](/docs/components/checkbox#form)
+- [Date Picker](/docs/components/date-picker#form)
+- [Input](/docs/components/input#form)
+- [Radio Group](/docs/components/radio-group#form)
+- [Select](/docs/components/select#form)
+- [Switch](/docs/components/switch#form)
+- [Textarea](/docs/components/textarea#form)
+- [Combobox](/docs/components/combobox#form)
diff --git a/apps/design-system/content/docs/components/fragment-components.mdx b/apps/design-system/content/docs/components/fragment-components.mdx
new file mode 100644
index 00000000000..1a924430a1f
--- /dev/null
+++ b/apps/design-system/content/docs/components/fragment-components.mdx
@@ -0,0 +1,4 @@
+---
+title: Fragment components
+description: ''
+---
diff --git a/apps/design-system/content/docs/components/hover-card.mdx b/apps/design-system/content/docs/components/hover-card.mdx
new file mode 100644
index 00000000000..7d666ede670
--- /dev/null
+++ b/apps/design-system/content/docs/components/hover-card.mdx
@@ -0,0 +1,64 @@
+---
+title: Hover Card
+description: For sighted users to preview content available behind a link.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/hover-card
+ api: https://www.radix-ui.com/docs/primitives/components/hover-card#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add hover-card
+```
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-hover-card
+```
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
+```
+
+```tsx
+
+ Hover
+ The React Framework – created and maintained by @vercel.
+
+```
diff --git a/apps/design-system/content/docs/components/input-otp.mdx b/apps/design-system/content/docs/components/input-otp.mdx
new file mode 100644
index 00000000000..6743207ab87
--- /dev/null
+++ b/apps/design-system/content/docs/components/input-otp.mdx
@@ -0,0 +1,191 @@
+---
+title: Input OTP
+description: Accessible one-time password component with copy paste functionality.
+component: true
+links:
+ doc: https://input-otp.rodz.dev
+source:
+ shadcn: true
+ inputOtp: true
+---
+
+
+
+## About
+
+Input OTP is built on top of [input-otp](https://github.com/guilhermerodz/input-otp) by [@guilherme_rodz](https://twitter.com/guilherme_rodz).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+
+Run the following command:
+
+```bash
+npx shadcn-ui@latest add input-otp
+```
+
+Update `tailwind.config.js`
+
+Add the following animations to your `tailwind.config.js` file:
+
+```js showLineNumbers title="tailwind.config.js" {6-9,12}
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ theme: {
+ extend: {
+ keyframes: {
+ 'caret-blink': {
+ '0%,70%,100%': { opacity: '1' },
+ '20%,50%': { opacity: '0' },
+ },
+ },
+ animation: {
+ 'caret-blink': 'caret-blink 1.25s ease-out infinite',
+ },
+ },
+ },
+}
+```
+
+
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install input-otp
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+Update `tailwind.config.js`
+
+Add the following animations to your `tailwind.config.js` file:
+
+```js showLineNumbers title="tailwind.config.js" {6-9,12}
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ theme: {
+ extend: {
+ keyframes: {
+ 'caret-blink': {
+ '0%,70%,100%': { opacity: '1' },
+ '20%,50%': { opacity: '0' },
+ },
+ },
+ animation: {
+ 'caret-blink': 'caret-blink 1.25s ease-out infinite',
+ },
+ },
+ },
+}
+```
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@/components/ui/input-otp'
+```
+
+```tsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Examples
+
+### Pattern
+
+Use the `pattern` prop to define a custom pattern for the OTP input.
+
+
+
+```tsx showLineNumbers {1,7}
+import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
+
+...
+
+
+
+
+ {/* ... */}
+
+
+```
+
+### Separator
+
+You can use the `` component to add a separator between the input groups.
+
+
+
+```tsx showLineNumbers {4,15}
+import {
+ InputOTP,
+ InputOTPGroup,
+ InputOTPSeparator,
+ InputOTPSlot,
+} from "@/components/ui/input-otp"
+
+...
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Controlled
+
+You can use the `value` and `onChange` props to control the input value.
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/input.mdx b/apps/design-system/content/docs/components/input.mdx
new file mode 100644
index 00000000000..fdbdd85a6af
--- /dev/null
+++ b/apps/design-system/content/docs/components/input.mdx
@@ -0,0 +1,77 @@
+---
+title: Input
+description: Displays a form input field or a component that looks like an input field.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add input
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Input } from '@/components/ui/input'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Default
+
+
+
+### File
+
+
+
+### Disabled
+
+
+
+### With Label
+
+
+
+### With Button
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/label.mdx b/apps/design-system/content/docs/components/label.mdx
new file mode 100644
index 00000000000..8b13a43f94b
--- /dev/null
+++ b/apps/design-system/content/docs/components/label.mdx
@@ -0,0 +1,32 @@
+---
+title: Label
+description: Renders an accessible label associated with controls.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/label
+ api: https://www.radix-ui.com/docs/primitives/components/label#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+
+
+Please use [FormLabel](/design-system/docs/components/form#anatomy) if you are using [Form](/design-system/docs/components/form) based components.
+
+
+
+## Usage
+
+```tsx
+import { Label_Shadcn_ } from '@/components/ui/label'
+```
+
+```tsx
+Your email address
+```
diff --git a/apps/design-system/content/docs/components/menubar.mdx b/apps/design-system/content/docs/components/menubar.mdx
new file mode 100644
index 00000000000..ff88641610d
--- /dev/null
+++ b/apps/design-system/content/docs/components/menubar.mdx
@@ -0,0 +1,83 @@
+---
+title: Menubar
+description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/menubar
+ api: https://www.radix-ui.com/docs/primitives/components/menubar#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add menubar
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-menubar
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Menubar,
+ MenubarContent,
+ MenubarItem,
+ MenubarMenu,
+ MenubarSeparator,
+ MenubarShortcut,
+ MenubarTrigger,
+} from '@/components/ui/menubar'
+```
+
+```tsx
+
+
+ File
+
+
+ New Tab ⌘T
+
+ New Window
+
+ Share
+
+ Print
+
+
+
+```
diff --git a/apps/design-system/content/docs/components/navigation-menu.mdx b/apps/design-system/content/docs/components/navigation-menu.mdx
new file mode 100644
index 00000000000..ec074e3a585
--- /dev/null
+++ b/apps/design-system/content/docs/components/navigation-menu.mdx
@@ -0,0 +1,130 @@
+---
+title: Navigation Menu
+description: A collection of links for navigating websites.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/navigation-menu
+ api: https://www.radix-ui.com/docs/primitives/components/navigation-menu#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add navigation-menu
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-navigation-menu
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ NavigationMenu,
+ NavigationMenuContent,
+ NavigationMenuIndicator,
+ NavigationMenuItem,
+ NavigationMenuLink,
+ NavigationMenuList,
+ NavigationMenuTrigger,
+ NavigationMenuViewport,
+} from '@/components/ui/navigation-menu'
+```
+
+```tsx
+
+
+
+ Item One
+
+ Link
+
+
+
+
+```
+
+## Examples
+
+### Link Component
+
+When using the Next.js `` component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger.
+
+```tsx
+import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu'
+```
+
+```tsx {3-5}
+
+
+ Documentation
+
+
+```
+
+See also the [Radix UI documentation](https://www.radix-ui.com/docs/primitives/components/navigation-menu#with-client-side-routing) for handling client side routing.
+
+### With horizontal scroll
+
+We can wrap a the `` in a `` component to make the menu scroll.
+
+However, then we must also make sure the `` is positioned correctly and rendered outside the scroll area.
+We set `renderViewport={false}` on the `` component to prevent the viewport from being rendered.
+And then add our own Viewport with ``.
+
+Then all our content panels will render themselves outside the scroll area and inside the viewport.
+
+You can also add props to `` to style it as you like, including the `containerProps` prop to add classes to the container div element inside the viewport.
+
+```tsx {1, 2, 11-13}
+
+
+
+
+ Item One
+
+ Link
+
+
+
+
+
+
+
+```
+
+
diff --git a/apps/design-system/content/docs/components/pagination.mdx b/apps/design-system/content/docs/components/pagination.mdx
new file mode 100644
index 00000000000..e5fbf626203
--- /dev/null
+++ b/apps/design-system/content/docs/components/pagination.mdx
@@ -0,0 +1,104 @@
+---
+title: Pagination
+description: Pagination with page navigation, next and previous links.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add pagination
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Pagination,
+ PaginationContent,
+ PaginationEllipsis,
+ PaginationItem,
+ PaginationLink,
+ PaginationNext,
+ PaginationPrevious,
+} from '@/components/ui/pagination'
+```
+
+```tsx
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+```
+
+### Next.js
+
+By default the `` component will render an `` tag.
+
+To use the Next.js `` component, make the following updates to `pagination.tsx`.
+
+```diff showLineNumbers /typeof Link/ {1}
++ import Link from "next/link"
+
+- type PaginationLinkProps = ... & React.ComponentProps<"a">
++ type PaginationLinkProps = ... & React.ComponentProps
+
+const PaginationLink = ({...props }: ) => (
+
+-
++
+ // ...
+-
++
+
+)
+
+```
+
+
+
+**Note:** We are making updates to the cli to automatically do this for you.
+
+
diff --git a/apps/design-system/content/docs/components/popover.mdx b/apps/design-system/content/docs/components/popover.mdx
new file mode 100644
index 00000000000..f04fe012c87
--- /dev/null
+++ b/apps/design-system/content/docs/components/popover.mdx
@@ -0,0 +1,64 @@
+---
+title: Popover
+description: Displays rich content in a portal, triggered by a button.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/popover
+ api: https://www.radix-ui.com/docs/primitives/components/popover#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add popover
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-popover
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
+```
+
+```tsx
+
+ Open
+ Place content for the popover here.
+
+```
diff --git a/apps/design-system/content/docs/components/progress.mdx b/apps/design-system/content/docs/components/progress.mdx
new file mode 100644
index 00000000000..a187c3421ae
--- /dev/null
+++ b/apps/design-system/content/docs/components/progress.mdx
@@ -0,0 +1,61 @@
+---
+title: Progress
+description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/progress
+ api: https://www.radix-ui.com/docs/primitives/components/progress#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add progress
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-progress
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Progress } from '@/components/ui/progress'
+```
+
+```tsx
+
+```
diff --git a/apps/design-system/content/docs/components/radio-group-card.mdx b/apps/design-system/content/docs/components/radio-group-card.mdx
new file mode 100644
index 00000000000..26adb02c514
--- /dev/null
+++ b/apps/design-system/content/docs/components/radio-group-card.mdx
@@ -0,0 +1,36 @@
+---
+title: Radio Group Card
+description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/radio-group
+ api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference
+source:
+ radix: true
+---
+
+
+
+## Usage
+
+```tsx
+import { RadioGroupCard, RadioGroupCardItem } from 'ui'
+```
+
+```tsx
+
+
+
+
+
+```
+
+## Examples
+
+### With children
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/radio-group-stacked.mdx b/apps/design-system/content/docs/components/radio-group-stacked.mdx
new file mode 100644
index 00000000000..ff3c80616bf
--- /dev/null
+++ b/apps/design-system/content/docs/components/radio-group-stacked.mdx
@@ -0,0 +1,32 @@
+---
+title: Radio Group Stacked
+description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/radio-group
+ api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference
+source:
+ radix: true
+---
+
+
+
+## Usage
+
+```tsx
+import { RadioGroupStacked, RadioGroupStackedItem } from 'ui'
+```
+
+```tsx
+
+
+
+
+
+```
+
+## Examples
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/radio-group.mdx b/apps/design-system/content/docs/components/radio-group.mdx
new file mode 100644
index 00000000000..8bd7e79ac52
--- /dev/null
+++ b/apps/design-system/content/docs/components/radio-group.mdx
@@ -0,0 +1,77 @@
+---
+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.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/radio-group
+ api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add radio-group
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-radio-group
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Label } from '@/components/ui/label'
+import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
+```
+
+```tsx
+
+
+
+
+
+
+
+
+
+
+```
+
+## Examples
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/resizable.mdx b/apps/design-system/content/docs/components/resizable.mdx
new file mode 100644
index 00000000000..b06c1af8f20
--- /dev/null
+++ b/apps/design-system/content/docs/components/resizable.mdx
@@ -0,0 +1,110 @@
+---
+title: Resizable
+description: Accessible resizable panel groups and layouts with keyboard support.
+component: true
+links:
+ doc: https://github.com/bvaughn/react-resizable-panels
+ api: https://github.com/bvaughn/react-resizable-panels/tree/main/packages/react-resizable-panels
+source:
+ shadcn: true
+---
+
+
+
+## About
+
+The `Resizable` component is built on top of [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) by [bvaughn](https://github.com/bvaughn).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add resizable
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install react-resizable-panels
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
+```
+
+```tsx
+
+ One
+
+ Two
+
+```
+
+## Examples
+
+### Vertical
+
+Use the `direction` prop to set the direction of the resizable panels.
+
+
+
+```tsx showLineNumbers {9}
+import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
+
+export default function Example() {
+ return (
+
+ One
+
+ Two
+
+ )
+}
+```
+
+### Handle
+
+You can set or hide the handle by using the `withHandle` prop on the `ResizableHandle` component.
+
+
+
+```tsx showLineNumbers {11}
+import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
+
+export default function Example() {
+ return (
+
+ One
+
+ Two
+
+ )
+}
+```
diff --git a/apps/design-system/content/docs/components/scroll-area.mdx b/apps/design-system/content/docs/components/scroll-area.mdx
new file mode 100644
index 00000000000..55d039eec5a
--- /dev/null
+++ b/apps/design-system/content/docs/components/scroll-area.mdx
@@ -0,0 +1,73 @@
+---
+title: Scroll-area
+description: Augments native scroll functionality for custom, cross-browser styling.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/scroll-area
+ api: https://www.radix-ui.com/docs/primitives/components/scroll-area#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add scroll-area
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-scroll-area
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { ScrollArea } from '@/components/ui/scroll-area'
+```
+
+```tsx
+
+ Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the
+ place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but
+ he couldn't seem to stop Jokester. And then, one day, the people of the kingdom discovered that
+ the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started
+ laughing, they couldn't stop.
+
+```
+
+## Examples
+
+### Horizontal Scrolling
+
+
diff --git a/apps/design-system/content/docs/components/select.mdx b/apps/design-system/content/docs/components/select.mdx
new file mode 100644
index 00000000000..64a0fd5181b
--- /dev/null
+++ b/apps/design-system/content/docs/components/select.mdx
@@ -0,0 +1,87 @@
+---
+title: Select
+description: Displays a list of options for the user to pick from—triggered by a button.
+component: true
+featured: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/select
+ api: https://www.radix-ui.com/docs/primitives/components/select#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add select
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-select
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Scrollable
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/separator.mdx b/apps/design-system/content/docs/components/separator.mdx
new file mode 100644
index 00000000000..92fa9bc2b43
--- /dev/null
+++ b/apps/design-system/content/docs/components/separator.mdx
@@ -0,0 +1,59 @@
+---
+title: Separator
+description: Visually or semantically separates content.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/separator
+ api: https://www.radix-ui.com/docs/primitives/components/separator#api-reference
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add separator
+```
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-separator
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Separator } from '@/components/ui/separator'
+```
+
+```tsx
+
+```
diff --git a/apps/design-system/content/docs/components/sheet.mdx b/apps/design-system/content/docs/components/sheet.mdx
new file mode 100644
index 00000000000..96220e63eb5
--- /dev/null
+++ b/apps/design-system/content/docs/components/sheet.mdx
@@ -0,0 +1,106 @@
+---
+title: Sheet
+description: Extends the Dialog component to display content that complements the main content of the screen.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/dialog
+ api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add sheet
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-dialog
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+### Usage
+
+```tsx
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet'
+```
+
+```tsx
+
+ Open
+
+
+ Are you absolutely sure?
+
+ This action cannot be undone. This will permanently delete your account and remove your data
+ from our servers.
+
+
+
+
+```
+
+## Examples
+
+### Side
+
+Use the `side` property to `` to indicate the edge of the screen where the component will appear. The values can be `top`, `right`, `bottom` or `left`.
+
+
+
+### Size
+
+You can adjust the size of the sheet using CSS classes:
+
+```tsx {3}
+
+ Open
+
+
+ Are you absolutely sure?
+
+ This action cannot be undone. This will permanently delete your account and remove your data
+ from our servers.
+
+
+
+
+```
diff --git a/apps/design-system/content/docs/components/skeleton.mdx b/apps/design-system/content/docs/components/skeleton.mdx
new file mode 100644
index 00000000000..5ab50f02500
--- /dev/null
+++ b/apps/design-system/content/docs/components/skeleton.mdx
@@ -0,0 +1,57 @@
+---
+title: Skeleton
+description: Use to show a placeholder while content is loading.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add skeleton
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Card
+
+
diff --git a/apps/design-system/content/docs/components/slider.mdx b/apps/design-system/content/docs/components/slider.mdx
new file mode 100644
index 00000000000..e2f1120559c
--- /dev/null
+++ b/apps/design-system/content/docs/components/slider.mdx
@@ -0,0 +1,61 @@
+---
+title: Slider
+description: An input where the user selects a value from within a given range.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/slider
+ api: https://www.radix-ui.com/docs/primitives/components/slider#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add slider
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-slider
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Slider } from '@/components/ui/slider'
+```
+
+```tsx
+
+```
diff --git a/apps/design-system/content/docs/components/sonner.mdx b/apps/design-system/content/docs/components/sonner.mdx
new file mode 100644
index 00000000000..3af18cfd4a8
--- /dev/null
+++ b/apps/design-system/content/docs/components/sonner.mdx
@@ -0,0 +1,103 @@
+---
+title: Sonner
+description: An opinionated toast component for React.
+component: true
+links:
+ doc: https://sonner.emilkowal.ski
+source:
+ shadcn: true
+---
+
+
+
+## About
+
+Sonner is built and maintained by [emilkowalski\_](https://twitter.com/emilkowalski_).
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+
+Run the following command:
+
+```bash
+npx shadcn-ui@latest add sonner
+```
+
+Add the Toaster component
+
+```tsx title="app/layout.tsx" {1,9}
+import { Toaster } from '@/components/ui/sonner'
+
+export default function RootLayout({ children }) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+```
+
+
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install sonner next-themes
+```
+
+Copy and paste the following code into your project.
+
+
+
+Add the Toaster component
+
+```tsx title="app/layout.tsx" {1,9}
+import { Toaster } from '@/components/ui/sonner'
+
+export default function RootLayout({ children }) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+```
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { toast } from 'sonner'
+```
+
+```tsx
+toast('Event has been created.')
+```
diff --git a/apps/design-system/content/docs/components/switch.mdx b/apps/design-system/content/docs/components/switch.mdx
new file mode 100644
index 00000000000..3dcf332821f
--- /dev/null
+++ b/apps/design-system/content/docs/components/switch.mdx
@@ -0,0 +1,67 @@
+---
+title: Switch
+description: A control that allows the user to toggle between checked and not checked.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/switch
+ api: https://www.radix-ui.com/docs/primitives/components/switch#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add switch
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-switch
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Switch } from '@/components/ui/switch'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/table.mdx b/apps/design-system/content/docs/components/table.mdx
new file mode 100644
index 00000000000..ff05bebe235
--- /dev/null
+++ b/apps/design-system/content/docs/components/table.mdx
@@ -0,0 +1,85 @@
+---
+title: Table
+description: A responsive table component.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add table
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from '@/components/ui/table'
+```
+
+```tsx
+
+ A list of your recent invoices.
+
+
+ Invoice
+ Status
+ Method
+ Amount
+
+
+
+
+ INV001
+ Paid
+ Credit Card
+ $250.00
+
+
+
+```
+
+## Data Table
+
+You can use the `
` component to build more complex data tables. Combine it with [@tanstack/react-table](https://tanstack.com/table/v8) to create tables with sorting, filtering and pagination.
+
+See the [Data Table](/docs/components/data-table) documentation for more information.
+
+You can also see an example of a data table in the [Tasks](/examples/tasks) demo.
diff --git a/apps/design-system/content/docs/components/tabs.mdx b/apps/design-system/content/docs/components/tabs.mdx
new file mode 100644
index 00000000000..8085115c240
--- /dev/null
+++ b/apps/design-system/content/docs/components/tabs.mdx
@@ -0,0 +1,68 @@
+---
+title: Tabs
+description: A set of layered sections of content—known as tab panels—that are displayed one at a time.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/tabs
+ api: https://www.radix-ui.com/docs/primitives/components/tabs#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add tabs
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-tabs
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
+```
+
+```tsx
+
+
+ Account
+ Password
+
+ Make changes to your account here.
+ Change your password here.
+
+```
diff --git a/apps/design-system/content/docs/components/textarea.mdx b/apps/design-system/content/docs/components/textarea.mdx
new file mode 100644
index 00000000000..07b91d58963
--- /dev/null
+++ b/apps/design-system/content/docs/components/textarea.mdx
@@ -0,0 +1,77 @@
+---
+title: Textarea
+description: Displays a form textarea or a component that looks like a textarea.
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add textarea
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Textarea } from '@/components/ui/textarea'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Default
+
+
+
+### Disabled
+
+
+
+### With Label
+
+
+
+### With Text
+
+
+
+### With Button
+
+
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/components/toast.mdx b/apps/design-system/content/docs/components/toast.mdx
new file mode 100644
index 00000000000..34dd53ac580
--- /dev/null
+++ b/apps/design-system/content/docs/components/toast.mdx
@@ -0,0 +1,155 @@
+---
+title: Toast
+description: A succinct message that is displayed temporarily.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/toast
+ api: https://www.radix-ui.com/docs/primitives/components/toast#api-reference
+source:
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+
+
+Run the following command:
+
+```bash
+npx shadcn-ui@latest add toast
+```
+
+Add the Toaster component
+
+```tsx title="app/layout.tsx" {1,9}
+import { Toaster } from '@/components/ui/toaster'
+
+export default function RootLayout({ children }) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+```
+
+
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-toast
+```
+
+Copy and paste the following code into your project.
+
+`toast.tsx`
+
+
+
+`toaster.tsx`
+
+
+
+`use-toast.tsx`
+
+
+
+Update the import paths to match your project setup.
+
+Add the Toaster component
+
+```tsx title="app/layout.tsx" {1,9}
+import { Toaster } from '@/components/ui/toaster'
+
+export default function RootLayout({ children }) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+```
+
+
+
+
+
+
+
+## Usage
+
+The `useToast` hook returns a `toast` function that you can use to display a toast.
+
+```tsx
+import { useToast } from '@/components/ui/use-toast'
+```
+
+```tsx {2,7-10}
+export const ToastDemo = () => {
+ const { toast } = useToast()
+
+ return (
+
+ )
+}
+```
+
+
+
+To display multiple toasts at the same time, you can update the `TOAST_LIMIT` in `use-toast.tsx`.
+
+
+
+## Examples
+
+### Simple
+
+
+
+### With title
+
+
+
+### With Action
+
+
+
+### Destructive
+
+Use `toast({ variant: "destructive" })` to display a destructive toast.
+
+
diff --git a/apps/design-system/content/docs/components/toggle-group.mdx b/apps/design-system/content/docs/components/toggle-group.mdx
new file mode 100644
index 00000000000..5cedba42af4
--- /dev/null
+++ b/apps/design-system/content/docs/components/toggle-group.mdx
@@ -0,0 +1,91 @@
+---
+title: Toggle Group
+description: A set of two-state buttons that can be toggled on or off.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/toggle-group
+ api: https://www.radix-ui.com/docs/primitives/components/toggle-group#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add toggle-group
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-toggle-group
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
+```
+
+```tsx
+
+ A
+ B
+ C
+
+```
+
+## Examples
+
+### Default
+
+
+
+### Outline
+
+
+
+### Single
+
+
+
+### Small
+
+
+
+### Large
+
+
+
+### Disabled
+
+
diff --git a/apps/design-system/content/docs/components/toggle.mdx b/apps/design-system/content/docs/components/toggle.mdx
new file mode 100644
index 00000000000..2f09c0b26bf
--- /dev/null
+++ b/apps/design-system/content/docs/components/toggle.mdx
@@ -0,0 +1,87 @@
+---
+title: Toggle
+description: A two-state button that can be either on or off.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/toggle
+ api: https://www.radix-ui.com/docs/primitives/components/toggle#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add toggle
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-toggle
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Toggle } from '@/components/ui/toggle'
+```
+
+```tsx
+Toggle
+```
+
+## Examples
+
+### Default
+
+
+
+### Outline
+
+
+
+### With Text
+
+
+
+### Small
+
+
+
+### Large
+
+
+
+### Disabled
+
+
diff --git a/apps/design-system/content/docs/components/tooltip.mdx b/apps/design-system/content/docs/components/tooltip.mdx
new file mode 100644
index 00000000000..0e013ffe8d5
--- /dev/null
+++ b/apps/design-system/content/docs/components/tooltip.mdx
@@ -0,0 +1,68 @@
+---
+title: Tooltip
+description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/tooltip
+ api: https://www.radix-ui.com/docs/primitives/components/tooltip#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn-ui@latest add tooltip
+```
+
+
+
+
+
+
+
+Install the following dependencies:
+
+```bash
+npm install @radix-ui/react-tooltip
+```
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Usage
+
+```tsx
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
+```
+
+```tsx
+
+
+ Hover
+
+
Add to library
+
+
+
+```
diff --git a/apps/design-system/content/docs/components/tree-view.mdx b/apps/design-system/content/docs/components/tree-view.mdx
new file mode 100644
index 00000000000..afd4b2b65c5
--- /dev/null
+++ b/apps/design-system/content/docs/components/tree-view.mdx
@@ -0,0 +1,121 @@
+---
+title: Tree View
+description: A tree view that assembles all the functionalities of the Accordion component to create a tree view.
+component: true
+links:
+ doc: https://dgreene1.github.io/react-accessible-treeview/
+ api: https://dgreene1.github.io/react-accessible-treeview/docs/api
+source:
+ reactAccessibleTreeview: true
+---
+
+
+
+## Usage
+
+```tsx
+import { TreeView, TreeViewItem } from 'ui'
+import { flattenTree } from 'react-accessible-treeview'
+```
+
+```tsx
+const data: {
+ name: ''
+ children: [
+ {
+ name: 'Current batch'
+ },
+ {
+ name: 'Older queries'
+ },
+ {
+ name: 'query all users'
+ },
+ {
+ name: 'users in last day'
+ },
+ {
+ name: 'new users over time'
+ },
+ ]
+}
+
+function App() {
+ return (
+ (
+
+ )}
+ />
+ )
+}
+```
+
+## Examples
+
+### With directories
+
+Use a `children` node in your data object to create a tree view with directories.
+
+```tsx {9-16}
+const data = {
+ //..
+ children: [
+ {
+ name: 'Current batch',
+ },
+ {
+ name: 'Older queries',
+ children: [
+ {
+ name: 'all countries',
+ },
+ {
+ name: 'add new countries',
+ },
+ ],
+ },
+ ],
+}
+```
+
+
+
+### With inline editing
+
+The Tree View can be edited in the app to enable different types of inline editing.
+
+In this example, right click on any item to rename it, and we traverse the data object setting `isEditing` to true.
+`TreeViewItem` then accepts a `isEditing` prop to show and focus an inline input to edit.
+
+
+
+### With multi selection
+
+Use the `multiSelect`, `togglableSelect`, `clickAction` set to "EXCLUSIVE_SELECT" to enable a multi-select tree view.
+
+An example can be seen on the [react-accessible-treeview docs](https://dgreene1.github.io/react-accessible-treeview/docs/examples-MultiSelectDirectoryTree).
+
+```tsx {4-6}
+
+```
+
+
diff --git a/apps/design-system/content/docs/components/typography.mdx b/apps/design-system/content/docs/components/typography.mdx
new file mode 100644
index 00000000000..d71c080c9a2
--- /dev/null
+++ b/apps/design-system/content/docs/components/typography.mdx
@@ -0,0 +1,61 @@
+---
+title: Typography
+description: Styles for headings, paragraphs, lists...etc
+component: true
+source:
+ shadcn: true
+---
+
+
+
+## h1
+
+
+
+## h2
+
+
+
+## h3
+
+
+
+## h4
+
+
+
+## p
+
+
+
+## blockquote
+
+
+
+## table
+
+
+
+## list
+
+
+
+## Inline code
+
+
+
+## Lead
+
+
+
+## Large
+
+
+
+## Small
+
+
+
+## Muted
+
+
diff --git a/apps/design-system/content/docs/figma.mdx b/apps/design-system/content/docs/figma.mdx
new file mode 100644
index 00000000000..35b3f81de83
--- /dev/null
+++ b/apps/design-system/content/docs/figma.mdx
@@ -0,0 +1,28 @@
+---
+title: Figma
+description: Every component recreated in Figma. With customizable props, typography and icons.
+---
+
+The Figma UI Kit is open sourced by [Pietro Schirano](https://twitter.com/skirano).
+
+
+
+
+
+## Additional resources
+
+### Figma Diagram Kit
+
+
+
+
+
+## Grab a copy
+
+https://www.figma.com/community/file/1203061493325953101
diff --git a/apps/design-system/content/docs/fragments/admonition.mdx b/apps/design-system/content/docs/fragments/admonition.mdx
new file mode 100644
index 00000000000..5df52e91ceb
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/admonition.mdx
@@ -0,0 +1,45 @@
+---
+title: Admonition
+description: Displays a callout for user attention.
+fragment: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/alert
+ api: https://www.radix-ui.com/docs/primitives/components/alert#api-reference
+---
+
+
+
+## Usage
+
+```tsx
+import { Admonition } from 'ui-patterns/admonition'
+```
+
+```tsx
+
+```
+
+## Examples
+
+### Warning
+
+
+
+### Destructive
+
+
diff --git a/apps/design-system/content/docs/fragments/form-item-layout.mdx b/apps/design-system/content/docs/fragments/form-item-layout.mdx
new file mode 100644
index 00000000000..dfa5402563c
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/form-item-layout.mdx
@@ -0,0 +1,108 @@
+---
+title: Form Item Layout
+description: A helper component that provides a layout for form items.
+component: true
+fragment: true
+---
+
+
+
+## Usage
+
+This component is to help with the layout of form items. It automatically provides `FormItem`, `FormLabel`, `FormMessage` and `FormDescription`.
+The styling and layout of these components can be customized by passing in the components as props.
+
+The components that can be replaced in `react-hook-form` atoms are highlighted below:
+
+```tsx showLineNumbers {1-2,6-8}
+
+ Username
+
+
+
+ This is your public display name.
+
+
+```
+
+Using `FormItemLayout` it can look like this:
+
+```tsx
+
+
+
+
+
+```
+
+Please note that you must still use `FormControl_Shadcn_` to wrap input fields.
+
+## Examples
+
+## With Select component
+
+
+
+## Horizontal layout
+
+This is useful for forms inside a `` / `` component.
+
+
+
+## With Switch component
+
+
+
+## With Checkbox component
+
+
+
+## List of items as Checkboxes
+
+
+
+## Before label
+
+You can insert any `React.Node` or string before the label using the `beforeLabel` prop.
+
+
+
+## After label
+
+You can insert any `React.Node` or string after the label using the `afterLabel` prop.
+
+
diff --git a/apps/design-system/content/docs/fragments/info-tooltip.mdx b/apps/design-system/content/docs/fragments/info-tooltip.mdx
new file mode 100644
index 00000000000..c2264049c7d
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/info-tooltip.mdx
@@ -0,0 +1,23 @@
+---
+title: Info Tooltip
+description: InfoTooltip provides a tooltip with an information icon.
+component: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/avatar
+ api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference
+source:
+ radix: true
+ shadcn: true
+---
+
+
+
+## Usage
+
+```tsx
+import { InfoTooltip } from 'ui'
+```
+
+```tsx
+This is the tooltip content
+```
diff --git a/apps/design-system/content/docs/fragments/modal.mdx b/apps/design-system/content/docs/fragments/modal.mdx
new file mode 100644
index 00000000000..2bbd59837cf
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/modal.mdx
@@ -0,0 +1,24 @@
+---
+title: Modal
+description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
+fragment: true
+links:
+ doc: https://www.radix-ui.com/docs/primitives/components/dialog
+ api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
+---
+
+
+
+## Examples
+
+### Aligned footer
+
+
+
+### Hide footer
+
+
+
+### Custom footer
+
+
diff --git a/apps/design-system/content/docs/fragments/multi-select.mdx b/apps/design-system/content/docs/fragments/multi-select.mdx
new file mode 100644
index 00000000000..d1566b198ac
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/multi-select.mdx
@@ -0,0 +1,42 @@
+---
+title: Multi Select
+description: Multiple selection component.
+component: true
+fragment: true
+---
+
+
+
+## Usage
+
+```tsx
+import {
+ MultiSelector,
+ MultiSelectorContent,
+ MultiSelectorInput,
+ MultiSelectorItem,
+ MultiSelectorList,
+ MultiSelectorTrigger,
+} from 'ui-patterns/multi-select'
+```
+
+```tsx
+
+
+
+
+
+
+ Item 1
+ Item 2
+ Item 3
+
+
+
+```
+
+## Examples
+
+### Form
+
+
diff --git a/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx b/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx
new file mode 100644
index 00000000000..f9127a0ebe7
--- /dev/null
+++ b/apps/design-system/content/docs/fragments/text-confirm-dialog.mdx
@@ -0,0 +1,57 @@
+---
+title: Text Confirm Dialog
+description: A modal dialog that interrupts the user with important content and expects a response.
+component: true
+---
+
+
+
+## Examples
+
+### With Info Alert
+
+
+
+### With warning Alert
+
+
+
+### With destructive Alert
+
+
+
+### With cancel button
+
+
+
+### With children
+
+
+
+### With size
+
+
diff --git a/apps/design-system/content/docs/icons.mdx b/apps/design-system/content/docs/icons.mdx
new file mode 100644
index 00000000000..e3d259cb7f3
--- /dev/null
+++ b/apps/design-system/content/docs/icons.mdx
@@ -0,0 +1,6 @@
+---
+title: Icons
+description: Icons system breakdown. Copy values of Icons.
+---
+
+
diff --git a/apps/design-system/content/docs/index.mdx b/apps/design-system/content/docs/index.mdx
new file mode 100644
index 00000000000..7e392c1b574
--- /dev/null
+++ b/apps/design-system/content/docs/index.mdx
@@ -0,0 +1,24 @@
+---
+title: Introduction
+description: Components and patterns that you can copy and paste into Supabase apps. Accessible. Customizable. Open Source.
+---
+
+## FAQ
+
+
+
+
+
+ Why copy/paste and not packaged as a dependency?
+
+
+The idea behind this is to give you ownership and control over the code, allowing you to decide how the components are built and styled.
+
+Start with some sensible defaults, then customize the components to your needs.
+
+One of the drawback of packaging the components in an npm package is that the style is coupled with the implementation. _The design of your components should be separate from their implementation._
+
+
+
+
+
diff --git a/apps/design-system/content/docs/tailwind-classes.mdx b/apps/design-system/content/docs/tailwind-classes.mdx
new file mode 100644
index 00000000000..270d4886e58
--- /dev/null
+++ b/apps/design-system/content/docs/tailwind-classes.mdx
@@ -0,0 +1,194 @@
+---
+title: Tailwind Classes
+description: Icons system breakdown. Copy values of Icons.
+---
+
+Supabase is migrating to use tailwind classes that use CSS properties.
+This is to support the concept of theming, so that:
+
+1. It is easy for the team to update the theme without changing 100s of files.
+2. We could offer custom or additional themes in future.
+
+## Primitives
+
+We (the Supabase Design team ✨) define primitive color values using Figma Variables.
+
+- `background`
+- `foreground`
+- `border`
+- `brand`
+- `destructive`
+- `warning`
+
+These values are exported from Figma as a .json file and transformed into tailwind utilities through some scripts under `packages/ui/internals/tokens`.
+
+Any of these colors are available on any tailwind utility that accepts color. For example:
+
+```jsx
+// this uses the default foreground color
+
+
+// this uses the 'light' foreground color
+
+
+// this uses the default warning color
+
+
+// this uses the '500' warning color
+
+```
+
+## Shorthands
+
+We support shorthand classes for `background`, `foreground` and `border`. For example:
+
+- `text-muted` is the same as `text-foreground-muted`
+- `bg-surface` is the same as `bg-background-surface-100`
+- `border-strong` is the same as `border-border-strong`
+
+This will stop you from needing to 'double type' the same utlity name.
+
+You might notice we use `foreground` and `background` as prefixes, this is only because it is a Design Token standard, where as tailwind uses `bg` and `text`.
+
+## Mixing colors
+
+Even with shorthands, remember you can use any color. For example, `foreground-light` can also be applied on borders and backgrounds as `border-foreground-light` and `bg-foreground-light`, if needed.
+Similarly, background and border primitives can be used on other tailwind utilities.
+
+```jsx
+// use the text light color for some text
+
+
+// we can use the same color for a background
+
+ I have the same color background as the left example
+
+```
+
+## Opacity support
+
+All the colors are generated using tailwind opacity, like `hsl(--background-default) / var(--tw-bg-opacity)`.
+This means all the color options in our themes can support opacity rules. For example:
+
+```jsx
+
+
+
+
+
+
+
+```
+
+## Usage
+
+The following tailwind classes are a combination of tailwind utilities and our primitives. They're under development and are likely to change but most are now in use and will probably be permanent fixtures.
+
+### Foreground (Text)
+
+| Value | Usage |
+| ---------------------- | -------------------------------------- |
+| `foreground-{DEFAULT}` | Default text (**DEFAULT** is optional) |
+| `foreground-light` | Light text |
+| `foreground-lighter` | Lighter text |
+| `foreground-muted` | Muted text |
+
+Examples:
+
+```jsx
+
/div>
+
/div>
+
/div>
+
/div>
+
/div>
+```
+
+---
+
+### Background
+
+| Value | Usage |
+| ----------------------------- | ------------------------------------------------------------ |
+| `background-{DEFAULT}` | Main body background (**DEFAULT** is optional) |
+| `background-surface-100` | Panels and surfaces on the same level of the main background |
+| `background-surface-200` | Surfaces that overlap the main content (ex. dropdowns) |
+| `background-surface-300` | Surfaces that are stacked above background-surface-200 |
+| `background-alternative` | Alternative background (inverted) |
+| `background-overlay` | Overlays, Dropdowns, Popovers |
+| `background-control` | Inputs, Radios, Checkboxes |
+| `background-button-{DEFAULT}` | Button default |
+
+The `background` part can be omitted when used on the `bg` tailwind utility.
+
+Examples:
+
+```
+bg-surface-100
+bg-overlay
+bg-alternative
+text-background-surface-100
+```
+
+---
+
+### Border
+
+| Value | Usage |
+| ------------------------- | ---------------------------------------- |
+| `border-{DEFAULT}` | Default border (**DEFAULT** is optional) |
+| `border-secondary` | Secondary border |
+| `border-alternative` | Alternative border (inverted) |
+| `border-overlay` | Overlays, Dropdowns, Popovers |
+| `border-control` | Inputs, Radios, Checkboxes |
+| `border-strong` | Hover, Focus |
+| `border-stronger` | Highlighted border |
+| `border-button-{DEFAULT}` | Button default border |
+| `border-button-hover` | Button default border hover |
+
+Examples:
+
+```
+border-overlay
+border-alternative
+text-border-control
+```
+
+### Brand
+
+| Value |
+| --------- |
+| `200` |
+| `300` |
+| `400` |
+| `500` |
+| `DEFAULT` |
+| `600` |
+| `button` |
+
+### Destructive
+
+| Value |
+| --------- |
+| `200` |
+| `300` |
+| `400` |
+| `500` |
+| `DEFAULT` |
+| `600` |
+
+### Warning
+
+| Value |
+| --------- |
+| `200` |
+| `300` |
+| `400` |
+| `500` |
+| `DEFAULT` |
+| `600` |
+
+## Storybook
+
+The current colors are also auto documented in Storybook
+
+[Storybook Colors](https://ui-storybook-pre-release.vercel.app/)
diff --git a/apps/design-system/content/docs/theming.mdx b/apps/design-system/content/docs/theming.mdx
new file mode 100644
index 00000000000..91b144803c9
--- /dev/null
+++ b/apps/design-system/content/docs/theming.mdx
@@ -0,0 +1,30 @@
+---
+title: Themes
+description: Themes used in Supabase
+---
+
+Design System currently takes into account varying themes.
+
+Themes currently in development:
+
+- Light
+- Dark (Classic dark)
+- Deep dark
+
+We also support a system theme, which will automatically switch between light and dark themes based on the user's system settings.
+
+- System
+
+## Try a theme
+
+You can set the theme of this website using the radio buttons below
+
+
+
+## Theme Pipeline
+
+Supabase is migrating to use tailwind classes that use CSS properties.
+This is to support the concept of theming, so that:
+
+1. It is easy for the team to update the theme without changing 100s of files.
+2. We could offer custom or additional themes in future.
diff --git a/apps/design-system/contentlayer.config.js b/apps/design-system/contentlayer.config.js
new file mode 100644
index 00000000000..edc30b91b1d
--- /dev/null
+++ b/apps/design-system/contentlayer.config.js
@@ -0,0 +1,204 @@
+import path from 'path'
+import { getHighlighter, loadTheme } from '@shikijs/compat'
+import { defineDocumentType, defineNestedType, makeSource } from 'contentlayer2/source-files'
+import rehypeAutolinkHeadings from 'rehype-autolink-headings'
+import rehypePrettyCode from 'rehype-pretty-code'
+import rehypeSlug from 'rehype-slug'
+import { codeImport } from 'remark-code-import'
+import remarkGfm from 'remark-gfm'
+import { visit } from 'unist-util-visit'
+
+import { rehypeComponent } from './lib/rehype-component'
+import { rehypeNpmCommand } from './lib/rehype-npm-command'
+
+/** @type {import('contentlayer2/source-files').ComputedFields} */
+const computedFields = {
+ slug: {
+ type: 'string',
+ resolve: (doc) => `/${doc._raw.flattenedPath}`,
+ },
+ slugAsParams: {
+ type: 'string',
+ resolve: (doc) => doc._raw.flattenedPath.split('/').slice(1).join('/'),
+ },
+}
+
+const LinksProperties = defineNestedType(() => ({
+ name: 'LinksProperties',
+ fields: {
+ doc: {
+ type: 'string',
+ },
+ api: {
+ type: 'string',
+ },
+ },
+}))
+
+const NestedProperties = defineNestedType(() => ({
+ name: 'NestedProperties',
+ fields: {
+ radix: {
+ type: 'boolean',
+ },
+ shadcn: {
+ type: 'boolean',
+ },
+ vaul: {
+ type: 'boolean',
+ },
+ inputOtp: {
+ type: 'boolean',
+ },
+ reactAccessibleTreeview: {
+ type: 'boolean',
+ },
+ },
+}))
+
+export const Doc = defineDocumentType(() => ({
+ name: 'Doc',
+ filePathPattern: `docs/**/*.mdx`,
+ contentType: 'mdx',
+ fields: {
+ title: {
+ type: 'string',
+ required: true,
+ },
+ description: {
+ type: 'string',
+ required: true,
+ },
+ published: {
+ type: 'boolean',
+ default: true,
+ },
+ links: {
+ type: 'nested',
+ of: LinksProperties,
+ },
+ featured: {
+ type: 'boolean',
+ default: false,
+ required: false,
+ },
+ component: {
+ type: 'boolean',
+ default: false,
+ required: false,
+ },
+ fragment: {
+ type: 'boolean',
+ default: false,
+ required: false,
+ },
+ toc: {
+ type: 'boolean',
+ default: true,
+ required: false,
+ },
+ source: {
+ type: 'nested',
+ of: NestedProperties,
+ },
+ },
+ computedFields,
+}))
+
+export default makeSource({
+ contentDirPath: './content',
+ documentTypes: [Doc],
+ mdx: {
+ remarkPlugins: [remarkGfm, codeImport],
+ rehypePlugins: [
+ rehypeSlug,
+ rehypeComponent,
+ () => (tree) => {
+ visit(tree, (node) => {
+ if (node?.type === 'element' && node?.tagName === 'pre') {
+ const [codeEl] = node.children
+ if (codeEl.tagName !== 'code') {
+ return
+ }
+
+ if (codeEl.data?.meta) {
+ // Extract event from meta and pass it down the tree.
+ const regex = /event="([^"]*)"/
+ const match = codeEl.data?.meta.match(regex)
+ if (match) {
+ node.__event__ = match ? match[1] : null
+ codeEl.data.meta = codeEl.data.meta.replace(regex, '')
+ }
+ }
+
+ node.__rawString__ = codeEl.children?.[0].value
+ node.__src__ = node.properties?.__src__
+ node.__style__ = node.properties?.__style__
+ }
+ })
+ },
+ [
+ rehypePrettyCode,
+ // rehypePrettyCodeOptions,
+ {
+ getHighlighter: async () => {
+ const theme = await loadTheme(path.join(process.cwd(), '/lib/themes/supabase-2.json'))
+ return await getHighlighter({ theme })
+ },
+ onVisitLine(node) {
+ // Prevent lines from collapsing in `display: grid` mode, and allow empty
+ // lines to be copy/pasted
+ if (node.children.length === 0) {
+ node.children = [{ type: 'text', value: ' ' }]
+ }
+ },
+ onVisitHighlightedLine(node) {
+ node.properties.className.push('line--highlighted')
+ },
+ onVisitHighlightedWord(node) {
+ node.properties.className = ['word--highlighted']
+ },
+ },
+ ],
+ () => (tree) => {
+ visit(tree, (node) => {
+ if (node?.type === 'element' && node?.tagName === 'div') {
+ if (!('data-rehype-pretty-code-fragment' in node.properties)) {
+ return
+ }
+
+ const preElement = node.children.at(-1)
+ if (preElement.tagName !== 'pre') {
+ return
+ }
+
+ preElement.properties['__withMeta__'] = node.children.at(0).tagName === 'div'
+ preElement.properties['__rawString__'] = node.__rawString__
+
+ if (node.__src__) {
+ preElement.properties['__src__'] = node.__src__
+ }
+
+ if (node.__event__) {
+ preElement.properties['__event__'] = node.__event__
+ }
+
+ if (node.__style__) {
+ preElement.properties['__style__'] = node.__style__
+ }
+ }
+ })
+ },
+ // rehypeNpmCommand,
+ [
+ rehypeAutolinkHeadings,
+ {
+ properties: {
+ className: ['subheading-anchor'],
+ ariaLabel: 'Link to section',
+ },
+ },
+ ],
+ ],
+ },
+})
diff --git a/apps/design-system/hooks/use-config.ts b/apps/design-system/hooks/use-config.ts
new file mode 100644
index 00000000000..858ffacc11e
--- /dev/null
+++ b/apps/design-system/hooks/use-config.ts
@@ -0,0 +1,24 @@
+import { useAtom } from 'jotai'
+import { atomWithStorage } from 'jotai/utils'
+
+// import { BackendProvider } from '@/registry/backend-provider'
+import { Style } from '@/registry/styles'
+import { Theme } from '@/registry/themes'
+
+type Config = {
+ style: Style['name']
+ theme: Theme['name']
+ radius: number
+ // backendProvider: BackendProvider['name'] | undefined
+}
+
+const configAtom = atomWithStorage('config', {
+ style: 'default',
+ // backendProvider: 'nextjs-auth',
+ theme: 'zinc',
+ radius: 0.5,
+})
+
+export function useConfig() {
+ return useAtom(configAtom)
+}
diff --git a/apps/design-system/hooks/use-media-query.tsx b/apps/design-system/hooks/use-media-query.tsx
new file mode 100644
index 00000000000..1f02308ba76
--- /dev/null
+++ b/apps/design-system/hooks/use-media-query.tsx
@@ -0,0 +1,19 @@
+import * as React from 'react'
+
+export function useMediaQuery(query: string) {
+ const [value, setValue] = React.useState(false)
+
+ React.useEffect(() => {
+ function onChange(event: MediaQueryListEvent) {
+ setValue(event.matches)
+ }
+
+ const result = matchMedia(query)
+ result.addEventListener('change', onChange)
+ setValue(result.matches)
+
+ return () => result.removeEventListener('change', onChange)
+ }, [query])
+
+ return value
+}
diff --git a/apps/design-system/hooks/use-mounted.ts b/apps/design-system/hooks/use-mounted.ts
new file mode 100644
index 00000000000..13256dce0c1
--- /dev/null
+++ b/apps/design-system/hooks/use-mounted.ts
@@ -0,0 +1,11 @@
+import * as React from 'react'
+
+export function useMounted() {
+ const [mounted, setMounted] = React.useState(false)
+
+ React.useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ return mounted
+}
diff --git a/apps/design-system/lib/rehype-component.ts b/apps/design-system/lib/rehype-component.ts
new file mode 100644
index 00000000000..adc038328ea
--- /dev/null
+++ b/apps/design-system/lib/rehype-component.ts
@@ -0,0 +1,406 @@
+import fs from 'fs'
+import path from 'path'
+import { UnistNode, UnistTree } from 'types/unist'
+import { u } from 'unist-builder'
+import { visit } from 'unist-util-visit'
+
+import { Index } from '../__registry__'
+import { styles } from '../registry/styles'
+
+// import { parse } from 'react-docgen'
+
+// import * as reactDocgenTypescript from 'react-docgen-typescript'
+
+// import { Column, IColumnProps } from './sample-component'
+import React from 'react' // ComponentType
+
+function inspectComponentProps(component: React.ComponentType): void {
+ // Assert the component's props type
+ const defaultProps = (component as React.ComponentType).defaultProps || {}
+
+ // console.log('Component props:')
+ // console.log('----------------')
+
+ for (const propName in defaultProps) {
+ const propType = typeof defaultProps[propName]
+ console.log(`${propName}: ${propType}`)
+ }
+}
+
+export function rehypeComponent() {
+ return async (tree: UnistTree) => {
+ visit(tree, (node: UnistNode) => {
+ // src prop overrides both name and fileName.
+ const { value: srcPath, name: componentName } =
+ (getNodeAttributeByName(node, 'src') as {
+ name: string
+ value?: string
+ type?: string
+ }) || {}
+
+ // console.log(srcPath, componentName)
+
+ // inspectComponentProps(Column)
+
+ // console.log('NEW NODE: ', node.name)
+
+ // if (node.name === 'ComponentProps') {
+ // // Parse a file for docgen info
+ // const options = {
+ // // savePropValueAsString: true,
+ // }
+
+ // // const parser = reactDocgenTypescript.parse('./sample-component.tsx', options)
+
+ // // console.log('PARSER', parser)
+
+ // const code = `
+ // /** My first component */
+ // export default ({ name, title }: {
+ // /** My first component */
+ // name: string,
+ // /** My first component */
+ // title: string
+ // }) =>