From 3a338b33dddb16d1fb55d29974d70384893c732a Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Mon, 16 Mar 2026 14:23:23 +0530 Subject: [PATCH] chore: initial Untitled UI Vite scaffold with FontAwesome Pro --- .github/last-sync-commit | 1 + .github/workflows/README.md | 73 + .github/workflows/sync-components.yml | 380 ++ .gitignore | 25 + .npmrc | 3 + .prettierrc | 19 + CLAUDE.md | 811 +++ README.md | 56 + bun.lock | 848 +++ index.html | 29 + package-lock.json | 5938 +++++++++++++++++ package.json | 50 + public/vite.svg | 1 + .../base-components/mobile-header.tsx | 56 + .../base-components/nav-account-card.tsx | 209 + .../base-components/nav-item-button.tsx | 67 + .../base-components/nav-item.tsx | 108 + .../base-components/nav-list.tsx | 83 + .../application/app-navigation/config.ts | 23 + .../app-navigation/header-navigation.tsx | 202 + .../sidebar-navigation-base.tsx | 5 + .../sidebar-navigation/sidebar-dual-tier.tsx | 149 + .../sidebar-section-dividers.tsx | 58 + .../sidebar-sections-subheadings.tsx | 72 + .../sidebar-navigation/sidebar-simple.tsx | 97 + .../sidebar-navigation/sidebar-slim.tsx | 226 + .../application/date-picker/calendar.tsx | 99 + .../application/date-picker/cell.tsx | 104 + .../application/date-picker/date-input.tsx | 30 + .../application/date-picker/date-picker.tsx | 84 + .../date-picker/date-range-picker.tsx | 161 + .../date-picker/range-calendar.tsx | 159 + .../application/date-picker/range-preset.tsx | 26 + .../application/empty-state/empty-state.tsx | 144 + .../file-upload/file-upload-base.tsx | 394 ++ .../loading-indicator/loading-indicator.tsx | 121 + src/components/application/modals/modal.tsx | 39 + .../pagination/pagination-base.tsx | 376 ++ .../application/pagination/pagination-dot.tsx | 52 + .../pagination/pagination-line.tsx | 48 + .../application/pagination/pagination.tsx | 328 + .../slideout-menus/slideout-menu.tsx | 120 + src/components/application/table/table.tsx | 298 + src/components/application/tabs/tabs.tsx | 223 + .../base/avatar/avatar-label-group.tsx | 28 + .../base/avatar/avatar-profile-photo.tsx | 123 + src/components/base/avatar/avatar.tsx | 129 + .../base-components/avatar-add-button.tsx | 32 + .../base-components/avatar-company-icon.tsx | 24 + .../avatar-online-indicator.tsx | 29 + .../base/avatar/base-components/index.tsx | 4 + .../avatar/base-components/verified-tick.tsx | 32 + src/components/base/avatar/utils.ts | 12 + src/components/base/badges/badge-groups.tsx | 174 + src/components/base/badges/badge-types.ts | 264 + src/components/base/badges/badges.tsx | 415 ++ .../base/button-group/button-group.tsx | 104 + .../buttons/app-store-buttons-outline.tsx | 376 ++ .../base/buttons/app-store-buttons.tsx | 565 ++ .../base/buttons/button-utility.tsx | 117 + src/components/base/buttons/button.tsx | 267 + src/components/base/buttons/close-button.tsx | 40 + src/components/base/buttons/social-button.tsx | 149 + src/components/base/buttons/social-logos.tsx | 113 + src/components/base/checkbox/checkbox.tsx | 118 + src/components/base/dropdown/dropdown.tsx | 161 + .../file-upload-trigger.tsx | 71 + src/components/base/form/form.tsx | 8 + src/components/base/input/hint-text.tsx | 31 + src/components/base/input/input-group.tsx | 131 + src/components/base/input/input-payment.tsx | 121 + src/components/base/input/input.tsx | 269 + src/components/base/input/label.tsx | 48 + src/components/base/pin-input/pin-input.tsx | 152 + .../progress-indicators/progress-circles.tsx | 174 + .../progress-indicators.tsx | 121 + .../progress-indicators/simple-circle.tsx | 27 + .../base/radio-buttons/radio-buttons.tsx | 127 + src/components/base/select/combobox.tsx | 150 + src/components/base/select/multi-select.tsx | 361 + src/components/base/select/popover.tsx | 32 + src/components/base/select/select-item.tsx | 95 + src/components/base/select/select-native.tsx | 67 + src/components/base/select/select.tsx | 144 + src/components/base/slider/slider.tsx | 73 + .../tags/base-components/tag-checkbox.tsx | 43 + .../base/tags/base-components/tag-close-x.tsx | 32 + src/components/base/tags/tags.tsx | 161 + src/components/base/textarea/textarea.tsx | 109 + src/components/base/toggle/toggle.tsx | 138 + src/components/base/tooltip/tooltip.tsx | 107 + src/components/foundations/dot-icon.tsx | 22 + .../featured-icon/featured-icon.tsx | 154 + .../logo/untitledui-logo-minimal.tsx | 170 + .../foundations/logo/untitledui-logo.tsx | 58 + .../foundations/payment-icons/amex-icon.tsx | 17 + .../payment-icons/apple-pay-icon.tsx | 25 + .../payment-icons/discover-icon.tsx | 32 + .../foundations/payment-icons/index.tsx | 8 + .../payment-icons/mastercard-icon.tsx | 37 + .../foundations/payment-icons/paypal-icon.tsx | 43 + .../foundations/payment-icons/stripe-icon.tsx | 25 + .../payment-icons/union-pay-icon.tsx | 35 + .../foundations/payment-icons/visa-icon.tsx | 25 + src/components/foundations/rating-badge.tsx | 142 + src/components/foundations/rating-stars.tsx | 75 + .../foundations/social-icons/angel-list.tsx | 18 + .../foundations/social-icons/apple.tsx | 18 + .../foundations/social-icons/clubhouse.tsx | 22 + .../foundations/social-icons/discord.tsx | 28 + .../foundations/social-icons/dribbble.tsx | 20 + .../foundations/social-icons/facebook.tsx | 18 + .../foundations/social-icons/figma.tsx | 20 + .../foundations/social-icons/github.tsx | 20 + .../foundations/social-icons/google.tsx | 20 + .../foundations/social-icons/index.tsx | 22 + .../foundations/social-icons/instagram.tsx | 26 + .../foundations/social-icons/layers.tsx | 36 + .../foundations/social-icons/linkedin.tsx | 18 + .../foundations/social-icons/pinterest.tsx | 18 + .../foundations/social-icons/reddit.tsx | 20 + .../foundations/social-icons/signal.tsx | 18 + .../foundations/social-icons/snapchat.tsx | 18 + .../foundations/social-icons/telegram.tsx | 20 + .../foundations/social-icons/tiktok.tsx | 18 + .../foundations/social-icons/tumblr.tsx | 18 + .../foundations/social-icons/twitter.tsx | 18 + src/components/foundations/social-icons/x.tsx | 20 + .../foundations/social-icons/youtube.tsx | 18 + .../base-components/nav-menu-item.tsx | 42 + .../dropdown-header-navigation.tsx | 51 + .../marketing/header-navigation/header.tsx | 248 + .../background-patterns/circle.tsx | 113 + .../background-patterns/grid-check.tsx | 2520 +++++++ .../background-patterns/grid.tsx | 231 + .../background-patterns/index.tsx | 25 + .../background-patterns/square.tsx | 180 + .../shared-assets/illustrations/box.tsx | 257 + .../shared-assets/illustrations/cloud.tsx | 281 + .../illustrations/credit-card.tsx | 303 + .../shared-assets/illustrations/documents.tsx | 538 ++ .../shared-assets/illustrations/index.tsx | 26 + src/components/shared-assets/qr-code.tsx | 83 + .../shared-assets/section-divider.tsx | 10 + src/hooks/use-breakpoint.ts | 34 + src/hooks/use-clipboard.ts | 77 + src/hooks/use-resize-observer.ts | 67 + src/main.tsx | 23 + src/pages/home-screen.tsx | 75 + src/pages/not-found.tsx | 32 + src/providers/router-provider.tsx | 16 + src/providers/theme-provider.tsx | 82 + src/styles/globals.css | 69 + src/styles/theme.css | 1326 ++++ src/styles/typography.css | 430 ++ src/types/vite-env.d.ts | 1 + src/utils/cx.ts | 24 + src/utils/is-react-component.ts | 33 + tsconfig.app.json | 30 + tsconfig.json | 13 + tsconfig.node.json | 24 + vite.config.ts | 13 + vite.svg | 1 + 163 files changed, 27081 insertions(+) create mode 100644 .github/last-sync-commit create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/sync-components.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .prettierrc create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100644 bun.lock create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/components/application/app-navigation/base-components/mobile-header.tsx create mode 100644 src/components/application/app-navigation/base-components/nav-account-card.tsx create mode 100644 src/components/application/app-navigation/base-components/nav-item-button.tsx create mode 100644 src/components/application/app-navigation/base-components/nav-item.tsx create mode 100644 src/components/application/app-navigation/base-components/nav-list.tsx create mode 100644 src/components/application/app-navigation/config.ts create mode 100644 src/components/application/app-navigation/header-navigation.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation-base.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation/sidebar-dual-tier.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation/sidebar-section-dividers.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation/sidebar-sections-subheadings.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation/sidebar-simple.tsx create mode 100644 src/components/application/app-navigation/sidebar-navigation/sidebar-slim.tsx create mode 100644 src/components/application/date-picker/calendar.tsx create mode 100644 src/components/application/date-picker/cell.tsx create mode 100644 src/components/application/date-picker/date-input.tsx create mode 100644 src/components/application/date-picker/date-picker.tsx create mode 100644 src/components/application/date-picker/date-range-picker.tsx create mode 100644 src/components/application/date-picker/range-calendar.tsx create mode 100644 src/components/application/date-picker/range-preset.tsx create mode 100644 src/components/application/empty-state/empty-state.tsx create mode 100644 src/components/application/file-upload/file-upload-base.tsx create mode 100644 src/components/application/loading-indicator/loading-indicator.tsx create mode 100644 src/components/application/modals/modal.tsx create mode 100644 src/components/application/pagination/pagination-base.tsx create mode 100644 src/components/application/pagination/pagination-dot.tsx create mode 100644 src/components/application/pagination/pagination-line.tsx create mode 100644 src/components/application/pagination/pagination.tsx create mode 100644 src/components/application/slideout-menus/slideout-menu.tsx create mode 100644 src/components/application/table/table.tsx create mode 100644 src/components/application/tabs/tabs.tsx create mode 100644 src/components/base/avatar/avatar-label-group.tsx create mode 100644 src/components/base/avatar/avatar-profile-photo.tsx create mode 100644 src/components/base/avatar/avatar.tsx create mode 100644 src/components/base/avatar/base-components/avatar-add-button.tsx create mode 100644 src/components/base/avatar/base-components/avatar-company-icon.tsx create mode 100644 src/components/base/avatar/base-components/avatar-online-indicator.tsx create mode 100644 src/components/base/avatar/base-components/index.tsx create mode 100644 src/components/base/avatar/base-components/verified-tick.tsx create mode 100644 src/components/base/avatar/utils.ts create mode 100644 src/components/base/badges/badge-groups.tsx create mode 100644 src/components/base/badges/badge-types.ts create mode 100644 src/components/base/badges/badges.tsx create mode 100644 src/components/base/button-group/button-group.tsx create mode 100644 src/components/base/buttons/app-store-buttons-outline.tsx create mode 100644 src/components/base/buttons/app-store-buttons.tsx create mode 100644 src/components/base/buttons/button-utility.tsx create mode 100644 src/components/base/buttons/button.tsx create mode 100644 src/components/base/buttons/close-button.tsx create mode 100644 src/components/base/buttons/social-button.tsx create mode 100644 src/components/base/buttons/social-logos.tsx create mode 100644 src/components/base/checkbox/checkbox.tsx create mode 100644 src/components/base/dropdown/dropdown.tsx create mode 100644 src/components/base/file-upload-trigger/file-upload-trigger.tsx create mode 100644 src/components/base/form/form.tsx create mode 100644 src/components/base/input/hint-text.tsx create mode 100644 src/components/base/input/input-group.tsx create mode 100644 src/components/base/input/input-payment.tsx create mode 100644 src/components/base/input/input.tsx create mode 100644 src/components/base/input/label.tsx create mode 100644 src/components/base/pin-input/pin-input.tsx create mode 100644 src/components/base/progress-indicators/progress-circles.tsx create mode 100644 src/components/base/progress-indicators/progress-indicators.tsx create mode 100644 src/components/base/progress-indicators/simple-circle.tsx create mode 100644 src/components/base/radio-buttons/radio-buttons.tsx create mode 100644 src/components/base/select/combobox.tsx create mode 100644 src/components/base/select/multi-select.tsx create mode 100644 src/components/base/select/popover.tsx create mode 100644 src/components/base/select/select-item.tsx create mode 100644 src/components/base/select/select-native.tsx create mode 100644 src/components/base/select/select.tsx create mode 100644 src/components/base/slider/slider.tsx create mode 100644 src/components/base/tags/base-components/tag-checkbox.tsx create mode 100644 src/components/base/tags/base-components/tag-close-x.tsx create mode 100644 src/components/base/tags/tags.tsx create mode 100644 src/components/base/textarea/textarea.tsx create mode 100644 src/components/base/toggle/toggle.tsx create mode 100644 src/components/base/tooltip/tooltip.tsx create mode 100644 src/components/foundations/dot-icon.tsx create mode 100644 src/components/foundations/featured-icon/featured-icon.tsx create mode 100644 src/components/foundations/logo/untitledui-logo-minimal.tsx create mode 100644 src/components/foundations/logo/untitledui-logo.tsx create mode 100644 src/components/foundations/payment-icons/amex-icon.tsx create mode 100644 src/components/foundations/payment-icons/apple-pay-icon.tsx create mode 100644 src/components/foundations/payment-icons/discover-icon.tsx create mode 100644 src/components/foundations/payment-icons/index.tsx create mode 100644 src/components/foundations/payment-icons/mastercard-icon.tsx create mode 100644 src/components/foundations/payment-icons/paypal-icon.tsx create mode 100644 src/components/foundations/payment-icons/stripe-icon.tsx create mode 100644 src/components/foundations/payment-icons/union-pay-icon.tsx create mode 100644 src/components/foundations/payment-icons/visa-icon.tsx create mode 100644 src/components/foundations/rating-badge.tsx create mode 100644 src/components/foundations/rating-stars.tsx create mode 100644 src/components/foundations/social-icons/angel-list.tsx create mode 100644 src/components/foundations/social-icons/apple.tsx create mode 100644 src/components/foundations/social-icons/clubhouse.tsx create mode 100644 src/components/foundations/social-icons/discord.tsx create mode 100644 src/components/foundations/social-icons/dribbble.tsx create mode 100644 src/components/foundations/social-icons/facebook.tsx create mode 100644 src/components/foundations/social-icons/figma.tsx create mode 100644 src/components/foundations/social-icons/github.tsx create mode 100644 src/components/foundations/social-icons/google.tsx create mode 100644 src/components/foundations/social-icons/index.tsx create mode 100644 src/components/foundations/social-icons/instagram.tsx create mode 100644 src/components/foundations/social-icons/layers.tsx create mode 100644 src/components/foundations/social-icons/linkedin.tsx create mode 100644 src/components/foundations/social-icons/pinterest.tsx create mode 100644 src/components/foundations/social-icons/reddit.tsx create mode 100644 src/components/foundations/social-icons/signal.tsx create mode 100644 src/components/foundations/social-icons/snapchat.tsx create mode 100644 src/components/foundations/social-icons/telegram.tsx create mode 100644 src/components/foundations/social-icons/tiktok.tsx create mode 100644 src/components/foundations/social-icons/tumblr.tsx create mode 100644 src/components/foundations/social-icons/twitter.tsx create mode 100644 src/components/foundations/social-icons/x.tsx create mode 100644 src/components/foundations/social-icons/youtube.tsx create mode 100644 src/components/marketing/header-navigation/base-components/nav-menu-item.tsx create mode 100644 src/components/marketing/header-navigation/dropdown-header-navigation.tsx create mode 100644 src/components/marketing/header-navigation/header.tsx create mode 100644 src/components/shared-assets/background-patterns/circle.tsx create mode 100644 src/components/shared-assets/background-patterns/grid-check.tsx create mode 100644 src/components/shared-assets/background-patterns/grid.tsx create mode 100644 src/components/shared-assets/background-patterns/index.tsx create mode 100644 src/components/shared-assets/background-patterns/square.tsx create mode 100644 src/components/shared-assets/illustrations/box.tsx create mode 100644 src/components/shared-assets/illustrations/cloud.tsx create mode 100644 src/components/shared-assets/illustrations/credit-card.tsx create mode 100644 src/components/shared-assets/illustrations/documents.tsx create mode 100644 src/components/shared-assets/illustrations/index.tsx create mode 100644 src/components/shared-assets/qr-code.tsx create mode 100644 src/components/shared-assets/section-divider.tsx create mode 100644 src/hooks/use-breakpoint.ts create mode 100644 src/hooks/use-clipboard.ts create mode 100644 src/hooks/use-resize-observer.ts create mode 100644 src/main.tsx create mode 100644 src/pages/home-screen.tsx create mode 100644 src/pages/not-found.tsx create mode 100644 src/providers/router-provider.tsx create mode 100644 src/providers/theme-provider.tsx create mode 100755 src/styles/globals.css create mode 100644 src/styles/theme.css create mode 100644 src/styles/typography.css create mode 100644 src/types/vite-env.d.ts create mode 100644 src/utils/cx.ts create mode 100644 src/utils/is-react-component.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts create mode 100644 vite.svg diff --git a/.github/last-sync-commit b/.github/last-sync-commit new file mode 100644 index 0000000..a7b3ea1 --- /dev/null +++ b/.github/last-sync-commit @@ -0,0 +1 @@ +3cdabc0b462049086ebc0f954fc661dc4ca2a594 diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..a93df5d --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,73 @@ +# Component sync workflow + +This workflow synchronizes components from the main [untitleduico/react](https://github.com/untitleduico/react) repository with intelligent commit tracking. + +## How to use + +1. Go to the "Actions" tab in your GitHub repository +2. Select "Sync Components from Main Repository" +3. Click "Run workflow" +4. Configure options: + - **Directories**: Which directories to sync (default: `components,hooks,utils,styles`) + - **Sync mode**: Choose between `all` or `existing-only` +5. Click "Run workflow" to start the sync + +## What it does + +1. **Fetches** the latest commit information from the main repository +2. **Tracks** previously synced commits to show what's new +3. **Creates** a branch named `sync/YYYY-MM-DD-[commit-hash]` +4. **Processes** files by removing `"use client";` directives +5. **Generates** a PR with commit history and detailed diff summaries +6. **Stores** the sync state for future runs + +## Sync modes + +### `all` (default) +- Syncs all files from the main repository +- Adds new files and updates existing ones +- Creates complete mirror of main repo structure + +### `existing-only` +- Only updates files that already exist in your repository +- Skips new files from the main repository +- Useful for maintaining a subset of components + +## Smart commit tracking + +- **First run**: Shows "Initial sync" with latest commit details +- **Subsequent runs**: Shows commit range since last sync +- **Up-to-date**: Indicates when no new commits are available +- **Commit history**: Collapsible list of all commits since last sync + +## Branch naming + +Branches follow the pattern: `sync/YYYY-MM-DD-[short-commit-hash]` +- Example: `sync/2024-03-15-a1b2c3d` + +## PR format + +The generated PR includes: + +### Title +- **New commits**: `🔄 Sync components (X commits) → a1b2c3d` +- **First sync**: `🎉 Initial sync from main repository → a1b2c3d` + +### Content +- **Commits since last sync**: Collapsible commit history with links +- **Changed files**: Each file with collapsible diff view +- **Sync details**: Source repo, latest commit, date, directories synced +- **Automated processing**: Notes about `"use client"` removal + +## State management + +The workflow stores sync state in `.github/last-sync-commit` to track: +- Last successfully synced commit hash +- Enables incremental sync reporting +- Shows commit ranges in PR descriptions + +## Requirements + +- Repository must have `contents: write` and `pull-requests: write` permissions +- Uses `GITHUB_TOKEN` (automatically available in GitHub Actions) +- GitHub CLI (`gh`) for PR creation \ No newline at end of file diff --git a/.github/workflows/sync-components.yml b/.github/workflows/sync-components.yml new file mode 100644 index 0000000..c5a828c --- /dev/null +++ b/.github/workflows/sync-components.yml @@ -0,0 +1,380 @@ +name: Sync Components from Main Repository + +on: + workflow_dispatch: + inputs: + sync_directories: + description: "Directories to sync (comma-separated)" + required: false + default: "components,hooks,utils,styles" + type: string + sync_mode: + description: "Sync mode" + required: false + default: "all" + type: choice + options: + - all + - existing-only + +jobs: + sync-components: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "18" + + - name: Configure git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Fetch main repository and get commit info + id: fetch-main-repo + run: | + echo "Fetching main repository..." + + # Create a temporary directory for cloning + mkdir -p /tmp/main-repo + cd /tmp/main-repo + + # Clone the main repository + git clone https://github.com/untitleduico/react.git . + + # Get latest commit info + LATEST_COMMIT_HASH=$(git rev-parse HEAD) + LATEST_COMMIT_SHORT=$(git rev-parse --short HEAD) + LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s") + LATEST_COMMIT_AUTHOR=$(git log -1 --pretty=format:"%an") + LATEST_COMMIT_DATE=$(git log -1 --pretty=format:"%ci") + + echo "LATEST_COMMIT_HASH=$LATEST_COMMIT_HASH" >> $GITHUB_ENV + echo "LATEST_COMMIT_SHORT=$LATEST_COMMIT_SHORT" >> $GITHUB_ENV + echo "LATEST_COMMIT_MESSAGE=$LATEST_COMMIT_MESSAGE" >> $GITHUB_ENV + echo "LATEST_COMMIT_AUTHOR=$LATEST_COMMIT_AUTHOR" >> $GITHUB_ENV + echo "LATEST_COMMIT_DATE=$LATEST_COMMIT_DATE" >> $GITHUB_ENV + + echo "Latest commit: $LATEST_COMMIT_SHORT - $LATEST_COMMIT_MESSAGE" + + # Get the directory structure (main repo has directories at root level, not in src/) + # Exclude demo and story files + find components hooks utils styles -type f ! -name "*.demo.tsx" ! -name "*.story.tsx" ! -name "*.stories.tsx" 2>/dev/null | sort > /tmp/main-repo-files.txt || echo "Some directories may not exist" + + echo "Files to sync:" + cat /tmp/main-repo-files.txt + + - name: Get last synced commit + id: get-last-sync + run: | + cd $GITHUB_WORKSPACE + + # Check if we have a previous sync record + if [ -f ".github/last-sync-commit" ] && [ -s ".github/last-sync-commit" ]; then + # Read the first line and trim whitespace, ignore comments + LAST_SYNC_COMMIT=$(head -n 1 .github/last-sync-commit | xargs | grep -v '^#' || echo "") + + if [ -n "$LAST_SYNC_COMMIT" ] && [ "$LAST_SYNC_COMMIT" != "" ]; then + echo "LAST_SYNC_COMMIT=$LAST_SYNC_COMMIT" >> $GITHUB_ENV + echo "Found previous sync commit: $LAST_SYNC_COMMIT" + else + echo "LAST_SYNC_COMMIT=" >> $GITHUB_ENV + echo "Sync file exists but no valid commit hash found" + fi + else + echo "LAST_SYNC_COMMIT=" >> $GITHUB_ENV + echo "No previous sync record found" + fi + + - name: Get commits since last sync + id: get-commits-since-sync + run: | + cd /tmp/main-repo + + if [ -n "$LAST_SYNC_COMMIT" ]; then + echo "Getting commits since $LAST_SYNC_COMMIT..." + + # Get commit log since last sync + git log --oneline "$LAST_SYNC_COMMIT".."$LATEST_COMMIT_HASH" > /tmp/commits-since-sync.txt || echo "Could not get commit range" + + # Count commits + COMMIT_COUNT=$(wc -l < /tmp/commits-since-sync.txt) + echo "COMMIT_COUNT=$COMMIT_COUNT" >> $GITHUB_ENV + + echo "Commits since last sync ($COMMIT_COUNT):" + cat /tmp/commits-since-sync.txt + else + echo "COMMIT_COUNT=unknown" >> $GITHUB_ENV + echo "No previous sync - this is the first sync" + echo "First sync - syncing from latest commit" > /tmp/commits-since-sync.txt + fi + + - name: Create sync branch + run: | + cd $GITHUB_WORKSPACE + BRANCH_NAME="sync/$(date +%Y-%m-%d-%H%M%S)-$LATEST_COMMIT_SHORT" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + + # Delete branch if it exists locally + git branch -D "$BRANCH_NAME" 2>/dev/null || true + + # Delete branch if it exists remotely + git push origin --delete "$BRANCH_NAME" 2>/dev/null || true + + # Create fresh branch + git checkout -b "$BRANCH_NAME" + echo "Created branch: $BRANCH_NAME" + + - name: Sync files from main repository + run: | + cd /tmp/main-repo + + # Read the sync directories from input + IFS=',' read -ra DIRS <<< "${{ github.event.inputs.sync_directories }}" + + # Create sync summary file + echo "# Sync Summary" > /tmp/sync-summary.md + echo "" >> /tmp/sync-summary.md + + for dir in "${DIRS[@]}"; do + dir=$(echo "$dir" | xargs) # trim whitespace + echo "## Syncing $dir directory" >> /tmp/sync-summary.md + + # Main repo has directories at root level, target repo has them in src/ + if [ -d "$dir" ]; then + # Create directory in target repo if it doesn't exist + mkdir -p "$GITHUB_WORKSPACE/src/$dir" + + # Find all files in the directory from main repo, excluding demo and story files + find "$dir" -type f ! -name "*.demo.tsx" ! -name "*.story.tsx" ! -name "*.stories.tsx" | while read -r file; do + target_file="$GITHUB_WORKSPACE/src/$file" + + # Check sync mode + if [ "${{ github.event.inputs.sync_mode }}" = "existing-only" ]; then + # Only process if target file already exists + if [ ! -f "$target_file" ]; then + echo "Skipping new file: $file (existing-only mode)" + continue + fi + fi + + echo "Processing $file..." + + # Copy file content and process it + content=$(cat "$file") + + # Remove "use client" directive if present (including double newlines after it) + # This handles both double quotes and single quotes, with optional semicolon + processed_content=$(echo "$content" | sed -E ' + /^"use client";?\s*$/{ + N + N + s/"use client";?\s*\n\s*\n// + } + /^'\''use client'\'';?\s*$/{ + N + N + s/'\''use client'\'';?\s*\n\s*\n// + } + ') + + # Target file goes in src/ directory + target_dir=$(dirname "$target_file") + mkdir -p "$target_dir" + + # Write processed content to target file + echo "$processed_content" > "$target_file" + + echo "- src/$file" >> /tmp/sync-summary.md + done + + # Log skipped files for transparency + DEMO_STORY_SKIPPED=$(find "$dir" -type f \( -name "*.demo.tsx" -o -name "*.story.tsx" -o -name "*.stories.tsx" \) | wc -l) + + if [ "${{ github.event.inputs.sync_mode }}" = "existing-only" ]; then + # Count new files that were skipped + NEW_FILES_SKIPPED=0 + find "$dir" -type f ! -name "*.demo.tsx" ! -name "*.story.tsx" ! -name "*.stories.tsx" | while read -r file; do + target_file="$GITHUB_WORKSPACE/src/$file" + if [ ! -f "$target_file" ]; then + NEW_FILES_SKIPPED=$((NEW_FILES_SKIPPED + 1)) + fi + done + + if [ "$NEW_FILES_SKIPPED" -gt 0 ]; then + echo "Skipped $NEW_FILES_SKIPPED new files (existing-only mode)" + echo "- Skipped $NEW_FILES_SKIPPED new files (existing-only mode)" >> /tmp/sync-summary.md + fi + fi + + if [ "$DEMO_STORY_SKIPPED" -gt 0 ]; then + echo "Skipped $DEMO_STORY_SKIPPED demo/story files" + echo "- Skipped $DEMO_STORY_SKIPPED demo/story files" >> /tmp/sync-summary.md + fi + else + echo "Directory $dir not found in main repository" >> /tmp/sync-summary.md + fi + done + + - name: Check for changes + id: check-changes + run: | + cd $GITHUB_WORKSPACE + if git diff --quiet; then + echo "changes=false" >> $GITHUB_OUTPUT + echo "No changes detected" + else + echo "changes=true" >> $GITHUB_OUTPUT + echo "Changes detected" + fi + + - name: Generate detailed diff summary + if: steps.check-changes.outputs.changes == 'true' + run: | + cd $GITHUB_WORKSPACE + + echo "# Component sync changes" > /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + echo "This PR synchronizes components from the main repository [untitleduico/react](https://github.com/untitleduico/react)." >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + + # Add commits since last sync section + echo "## 📝 Commits since last sync" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + if [ -n "$LAST_SYNC_COMMIT" ] && [ "$COMMIT_COUNT" != "unknown" ]; then + if [ "$COMMIT_COUNT" -gt 0 ]; then + echo "**$COMMIT_COUNT new commits** from [\`$LAST_SYNC_COMMIT\`](https://github.com/untitleduico/react/commit/$LAST_SYNC_COMMIT) to [\`$LATEST_COMMIT_SHORT\`](https://github.com/untitleduico/react/commit/$LATEST_COMMIT_HASH):" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + echo "
" >> /tmp/pr-description.md + echo "View commit history" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + while IFS= read -r commit_line; do + if [ -n "$commit_line" ]; then + commit_hash=$(echo "$commit_line" | cut -d' ' -f1) + commit_msg=$(echo "$commit_line" | cut -d' ' -f2-) + echo "- [\`$commit_hash\`](https://github.com/untitleduico/react/commit/$commit_hash) $commit_msg" >> /tmp/pr-description.md + fi + done < /tmp/commits-since-sync.txt + echo "" >> /tmp/pr-description.md + echo "
" >> /tmp/pr-description.md + else + echo "✅ **Repository is up to date** - no new commits since last sync [\`$LAST_SYNC_COMMIT\`](https://github.com/untitleduico/react/commit/$LAST_SYNC_COMMIT)" >> /tmp/pr-description.md + fi + else + echo "🎉 **First sync** - syncing from latest commit [\`$LATEST_COMMIT_SHORT\`](https://github.com/untitleduico/react/commit/$LATEST_COMMIT_HASH)" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + echo "**Latest commit**: $LATEST_COMMIT_MESSAGE" >> /tmp/pr-description.md + echo "**Author**: $LATEST_COMMIT_AUTHOR" >> /tmp/pr-description.md + echo "**Date**: $LATEST_COMMIT_DATE" >> /tmp/pr-description.md + fi + echo "" >> /tmp/pr-description.md + + echo "## 📁 Modified files" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + + # Get file statistics + TOTAL_FILES=$(git diff --name-only | wc -l) + echo "**$TOTAL_FILES files modified**" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + + # List all changed files + git diff --name-only | while read -r file; do + if [ -n "$file" ]; then + echo "- \`$file\`" >> /tmp/pr-description.md + fi + done + echo "" >> /tmp/pr-description.md + + echo "## 🔧 Sync details" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + echo "- **Source repository**: [untitleduico/react](https://github.com/untitleduico/react)" >> /tmp/pr-description.md + echo "- **Latest commit**: [\`$LATEST_COMMIT_SHORT\`](https://github.com/untitleduico/react/commit/$LATEST_COMMIT_HASH)" >> /tmp/pr-description.md + echo "- **Sync date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> /tmp/pr-description.md + echo "- **Directories synced**: ${{ github.event.inputs.sync_directories }}" >> /tmp/pr-description.md + echo "- **Sync mode**: ${{ github.event.inputs.sync_mode }}" >> /tmp/pr-description.md + echo "- **Automated processing**: Removed \`\"use client\";\` directives, excluded demo/story files" >> /tmp/pr-description.md + echo "" >> /tmp/pr-description.md + echo "---" >> /tmp/pr-description.md + echo "*This PR was automatically generated by the sync-components workflow.*" >> /tmp/pr-description.md + + - name: Store sync commit record + if: steps.check-changes.outputs.changes == 'true' + run: | + cd $GITHUB_WORKSPACE + + # Create .github directory if it doesn't exist + mkdir -p .github + + # Store the latest commit hash for next sync + echo "$LATEST_COMMIT_HASH" > .github/last-sync-commit + + echo "Stored sync commit: $LATEST_COMMIT_HASH" + + - name: Commit changes + if: steps.check-changes.outputs.changes == 'true' + run: | + cd $GITHUB_WORKSPACE + git add . + + # Create commit message + if [ -n "$LAST_SYNC_COMMIT" ] && [ "$COMMIT_COUNT" != "unknown" ] && [ "$COMMIT_COUNT" -gt 0 ]; then + COMMIT_MSG="sync: Update components from main repository ($COMMIT_COUNT commits) + + Synced from: $LAST_SYNC_COMMIT..$LATEST_COMMIT_SHORT + Latest commit: $LATEST_COMMIT_MESSAGE + Directories: ${{ github.event.inputs.sync_directories }} + Source: https://github.com/untitleduico/react/commit/$LATEST_COMMIT_HASH + Automated processing: Removed 'use client' directives" + else + COMMIT_MSG="sync: Initial sync from main repository + + Latest commit: $LATEST_COMMIT_SHORT - $LATEST_COMMIT_MESSAGE + Author: $LATEST_COMMIT_AUTHOR + Directories: ${{ github.event.inputs.sync_directories }} + Source: https://github.com/untitleduico/react/commit/$LATEST_COMMIT_HASH + Automated processing: Removed 'use client' directives" + fi + + git commit -m "$COMMIT_MSG" + + - name: Push changes and create PR + if: steps.check-changes.outputs.changes == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd $GITHUB_WORKSPACE + git push origin "$BRANCH_NAME" + + # Create PR title based on sync type + if [ -n "$LAST_SYNC_COMMIT" ] && [ "$COMMIT_COUNT" != "unknown" ] && [ "$COMMIT_COUNT" -gt 0 ]; then + PR_TITLE="🔄 Sync components ($COMMIT_COUNT commits) → $LATEST_COMMIT_SHORT" + else + PR_TITLE="🎉 Initial sync from main repository → $LATEST_COMMIT_SHORT" + fi + + # Create PR using GitHub CLI + gh pr create \ + --title "$PR_TITLE" \ + --body-file /tmp/pr-description.md \ + --head "$BRANCH_NAME" \ + --base main + + - name: Output results + run: | + if [ "${{ steps.check-changes.outputs.changes }}" == "true" ]; then + echo "✅ Sync completed successfully. PR created." + echo "Branch: $BRANCH_NAME" + else + echo "â„šī¸ No changes detected. Repository is already in sync." + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ceb59f --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.env diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..16d51e6 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +@awesome.me:registry=https://npm.fontawesome.com/ +@fortawesome:registry=https://npm.fontawesome.com/ +//npm.fontawesome.com/:_authToken=B9FAA215-4936-4B13-BEAA-FA58F042FA1A diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..f4b9b99 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,19 @@ +{ + "printWidth": 160, + "tabWidth": 4, + "plugins": [ + "@trivago/prettier-plugin-sort-imports", + "prettier-plugin-tailwindcss" + ], + "tailwindFunctions": ["sortCx", "cx"], + "importOrder": [ + "^react$", + "^react-dom$", + "^(?!react$|react-dom$|@/|\\.).*", + "^@/.*", + "^\\.{1,2}/.*" + ], + "importOrderSeparation": false, + "importOrderSortSpecifiers": true, + "tailwindStylesheet": "./src/styles/globals.css" +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..721ccac --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,811 @@ +## Project Overview + +This is an **Untitled UI React** component library project built with: + +- **React 19.1.1** with TypeScript +- **Tailwind CSS v4.1** for styling +- **React Aria Components** as the foundation for accessibility and behavior + +## Key Architecture Principles + +### Component Foundation + +- All components are built on **React Aria Components** for consistent accessibility and behavior +- Components follow the compound component pattern with sub-components (e.g., `Select.Item`, `Select.ComboBox`) +- TypeScript is used throughout for type safety + +### Import Naming Convention + +**CRITICAL**: All imports from `react-aria-components` must be prefixed with `Aria*` for clarity and consistency: + +```typescript +// ✅ Correct +import { Button as AriaButton, TextField as AriaTextField } from "react-aria-components"; +// ❌ Incorrect +import { Button, TextField } from "react-aria-components"; +``` + +This convention: + +- Prevents naming conflicts with custom components +- Makes it clear when using base React Aria components +- Maintains consistency across the entire codebase + +### File Naming Convention + +**IMPORTANT**: All files must be named in **kebab-case** for consistency: + +``` +✅ Correct: +- date-picker.tsx +- user-profile.tsx +- api-client.ts +- auth-context.tsx + +❌ Incorrect: +- DatePicker.tsx +- userProfile.tsx +- apiClient.ts +- AuthContext.tsx +``` + +This applies to all file types including: + +- Component files (.tsx, .jsx) +- TypeScript/JavaScript files (.ts, .js) +- Style files (.css, .scss) +- Test files (.test.ts, .spec.tsx) +- Configuration files (when creating new ones) + +## Development Commands + +```bash +# Development +npm run dev # Start Vite development server (http://localhost:5173) +npm run build # Build for production (TypeScript compilation + Vite build) +``` + +## Project Structure + +### Application Architecture + +``` +src/ +├── components/ +│ ├── base/ # Core UI components (Button, Input, Select, etc.) +│ ├── application/ # Complex application components +│ ├── foundations/ # Design tokens and foundational elements +│ ├── marketing/ # Marketing-specific components +│ └── shared-assets/ # Reusable assets and illustrations +├── hooks/ # Custom React hooks +├── pages/ # Route components +├── providers/ # React context providers +├── styles/ # Global styles and theme +├── types/ # TypeScript type definitions +└── utils/ # Utility functions +``` + +### Component Patterns + +#### 1. Base Components + +Located in `components/base/`, these are the building blocks: + +- `Button` - All button variants with loading states +- `Input` - Text inputs with validation and icons +- `Select` - Dropdown selections with complex options +- `Checkbox`, `Radio`, `Toggle` - Form controls +- `Avatar`, `Badge`, `Tooltip` - Display components + +#### 2. Application Components + +Located in `components/application/`, these are complex UI patterns: + +- `DatePicker` - Calendar-based date selection +- `Modal` - Overlay dialogs +- `Pagination` - Data navigation +- `Table` - Data display with sorting +- `Tabs` - Content organization + +#### 3. Styling Architecture + +- Uses a `sortCx` utility for organized style objects +- Follows size variants: `sm`, `md`, `lg`, `xl` +- Color variants: `primary`, `secondary`, `tertiary`, `destructive`, etc. +- Responsive and state-aware styling with Tailwind + +#### 4. Component Props Pattern + +```typescript +interface CommonProps { + size?: "sm" | "md" | "lg"; + isDisabled?: boolean; + isLoading?: boolean; + // ... other common props +} + +interface ButtonProps extends CommonProps, HTMLButtonElement { + color?: "primary" | "secondary" | "tertiary"; + iconLeading?: FC | ReactNode; + iconTrailing?: FC | ReactNode; +} +``` + +## Styling Guidelines + +### Tailwind CSS v4.1 + +- Uses the latest Tailwind CSS v4.1 features +- Custom design tokens defined in theme configuration +- Consistent spacing, colors, and typography scales + +### Brand Color Customization + +To change the main brand color across the entire application: + +1. **Update Brand Color Variables**: Edit `src/styles/theme.css` and modify the `--color-brand-*` variables +2. **Maintain Color Scale**: Ensure you provide a complete color scale from 25 to 950 with proper contrast ratios +3. **Example Brand Color Scale**: + ```css + --color-brand-25: rgb(252 250 255); /* Lightest tint */ + --color-brand-50: rgb(249 245 255); + --color-brand-100: rgb(244 235 255); + --color-brand-200: rgb(233 215 254); + --color-brand-300: rgb(214 187 251); + --color-brand-400: rgb(182 146 246); + --color-brand-500: rgb(158 119 237); /* Base brand color */ + --color-brand-600: rgb(127 86 217); /* Primary interactive color */ + --color-brand-700: rgb(105 65 198); + --color-brand-800: rgb(83 56 158); + --color-brand-900: rgb(66 48 125); + --color-brand-950: rgb(44 28 95); /* Darkest shade */ + ``` + +The color scale automatically adapts to both light and dark modes through the CSS variable system. + +### Style Organization + +```typescript +export const styles = sortCx({ + common: { + root: "base-classes-here", + icon: "icon-classes-here", + }, + sizes: { + sm: { root: "small-size-classes" }, + md: { root: "medium-size-classes" }, + }, + colors: { + primary: { root: "primary-color-classes" }, + secondary: { root: "secondary-color-classes" }, + }, +}); +``` + +### Utility Functions + +- `cx()` - Class name utility (from `@/utils/cx`) +- `sortCx()` - Organized style objects +- `isReactComponent()` - Component type checking + +## Icon Usage + +### Available Libraries + +- `@untitledui/icons` - 1,100+ line-style icons (free) +- `@untitledui/file-icons` - File type icons +- `@untitledui-pro/icons` - 4,600+ icons in 4 styles (Requires PRO access) + +### Import & Usage + +```typescript +// Recommended: Named imports (tree-shakeable) +import { Home01, Settings01, ChevronDown } from "@untitledui/icons"; + +// Component props - pass as reference + + +// Standalone usage + + +// As JSX element - MUST include data-icon + +``` + +### Styling + +```typescript +// Size: use size-4 (16px), size-5 (20px), size-6 (24px) + + +// Color: use semantic text colors + + +// Stroke width (line icons only) + + +// Accessibility: decorative icons need aria-hidden +