Update AGENTS.md. Start fixing old weird errors
This commit is contained in:
@@ -17,8 +17,10 @@ NEXT_PUBLIC_SENTRY_PROJECT_NAME=example
|
||||
CONVEX_SELF_HOSTED_URL=https://api.convex.example.com # convex-backend:3210
|
||||
CONVEX_SELF_HOSTED_ADMIN_KEY= # Generate after hosted on docker
|
||||
# Convex Auth
|
||||
CONVEX_SITE_URL=https://convex.example.com # convex-backend:3211
|
||||
CONVEX_SITE_URL=http://localhost:3000 # Always localhost:3000 for local dev; update in Convex Dashboard for production
|
||||
USESEND_API_KEY=
|
||||
USESEND_URL=https://usesend.example.com
|
||||
USESEND_FROM_EMAIL=My App <noreply@example.com>
|
||||
AUTH_AUTHENTIK_ID=
|
||||
AUTH_AUTHENTIK_SECRET=
|
||||
AUTH_AUTHENTIK_ISSUER=
|
||||
|
||||
287
README.md
287
README.md
@@ -32,15 +32,21 @@ A production-ready Turborepo starter with Next.js, Expo, and self-hosted Convex
|
||||
|
||||
## Getting Started
|
||||
|
||||
This is a self-hosted template. The full setup requires a server (home server or VPS)
|
||||
to host the Convex backend and dashboard, and a reverse proxy (nginx-proxy-manager is
|
||||
recommended) to expose them over HTTPS. The Next.js app can run locally in dev mode
|
||||
once the Convex containers are reachable.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Bun](https://bun.sh) (v1.2.19+)
|
||||
- [Bun](https://bun.sh) (v1.2+)
|
||||
- [Docker](https://www.docker.com/) & Docker Compose (for self-hosted Convex)
|
||||
- Node.js 22.20.0+ (for compatibility)
|
||||
- Node.js 22+ (for compatibility)
|
||||
- A running nginx-proxy-manager instance (or similar reverse proxy) to expose Convex over HTTPS
|
||||
|
||||
### Development Setup
|
||||
---
|
||||
|
||||
#### 1. Clone & Install
|
||||
### Step 1 — Clone & Install
|
||||
|
||||
```bash
|
||||
git clone https://git.gbrown.org/gib/convex-monorepo
|
||||
@@ -48,88 +54,152 @@ cd convex-monorepo
|
||||
bun install
|
||||
```
|
||||
|
||||
#### 2. Configure Environment Variables
|
||||
|
||||
Create a `.env` file in the project root with the following variables:
|
||||
If you're using this as a template for a new project, remove the existing remote and
|
||||
add your own:
|
||||
|
||||
```bash
|
||||
# Convex Backend (Self-Hosted)
|
||||
CONVEX_SELF_HOSTED_URL=https://api.convex.example.com
|
||||
CONVEX_SELF_HOSTED_ADMIN_KEY=<generated>
|
||||
CONVEX_SITE_URL=https://convex.example.com
|
||||
|
||||
# Next.js Public
|
||||
NEXT_PUBLIC_CONVEX_URL=https://api.convex.example.com
|
||||
NEXT_PUBLIC_SITE_URL=https://example.com
|
||||
NEXT_PUBLIC_PLAUSIBLE_URL=https://plausible.example.com
|
||||
NEXT_PUBLIC_SENTRY_DSN=
|
||||
NEXT_PUBLIC_SENTRY_URL=
|
||||
NEXT_PUBLIC_SENTRY_ORG=
|
||||
NEXT_PUBLIC_SENTRY_PROJECT_NAME=
|
||||
|
||||
# Server-side
|
||||
SENTRY_AUTH_TOKEN=
|
||||
|
||||
# Auth (will be synced to Convex)
|
||||
AUTH_AUTHENTIK_ID=
|
||||
AUTH_AUTHENTIK_SECRET=
|
||||
AUTH_AUTHENTIK_ISSUER=
|
||||
USESEND_API_KEY=
|
||||
git remote remove origin
|
||||
git remote add origin https://your-git-host.com/your/new-repo.git
|
||||
```
|
||||
|
||||
**For local development:** Use `http://localhost:3210` for Convex URLs.
|
||||
---
|
||||
|
||||
#### 3. Configure Docker Environment
|
||||
### Step 2 — Configure the Docker Environment
|
||||
|
||||
Check and update environment variables in `docker/.env` for your deployment:
|
||||
The `docker/` directory contains everything needed to run the Convex backend and the
|
||||
Next.js app in production.
|
||||
|
||||
```bash
|
||||
cd docker/
|
||||
cp .env.example .env
|
||||
# Edit .env with your configuration
|
||||
```
|
||||
|
||||
#### 4. Start Self-Hosted Convex
|
||||
Edit `docker/.env` and fill in your values. The variables below the Next.js app section
|
||||
control the Convex containers — you'll need to choose:
|
||||
|
||||
Spin up the Convex backend and dashboard:
|
||||
- `INSTANCE_NAME` — a unique name for your Convex instance
|
||||
- `INSTANCE_SECRET` — a secret string (generate something random)
|
||||
- `CONVEX_CLOUD_ORIGIN` — the public HTTPS URL for your Convex backend API (e.g. `https://api.convex.example.com`)
|
||||
- `CONVEX_SITE_ORIGIN` — the public HTTPS URL for Convex Auth HTTP routes (e.g. `https://api.convex.example.com`)
|
||||
- `NEXT_PUBLIC_DEPLOYMENT_URL` — the URL for the Convex dashboard (e.g. `https://dashboard.convex.example.com`)
|
||||
|
||||
---
|
||||
|
||||
### Step 3 — Start the Convex Containers
|
||||
|
||||
```bash
|
||||
cd docker/
|
||||
docker compose up -d convex-backend convex-dashboard
|
||||
sudo docker compose up -d convex-backend convex-dashboard
|
||||
```
|
||||
|
||||
**Services:**
|
||||
Wait a moment for `convex-backend` to pass its health check, then verify both
|
||||
containers are running:
|
||||
|
||||
- **Backend:** http://localhost:3210
|
||||
- **Dashboard:** http://localhost:6791
|
||||
```bash
|
||||
sudo docker compose ps
|
||||
```
|
||||
|
||||
#### 5. Generate Auth Keys & Sync Environment Variables
|
||||
Reverse-proxy the two Convex services through nginx-proxy-manager (or your preferred
|
||||
proxy) to the URLs you chose in Step 2. Both must be reachable over HTTPS before you
|
||||
can proceed.
|
||||
|
||||
Generate JWT keys for Convex Auth:
|
||||
---
|
||||
|
||||
### Step 4 — Generate the Convex Admin Key
|
||||
|
||||
With the backend container running, generate the admin key:
|
||||
|
||||
```bash
|
||||
cd docker/
|
||||
./generate_convex_admin_key
|
||||
```
|
||||
|
||||
Copy the printed key — you'll need it as `CONVEX_SELF_HOSTED_ADMIN_KEY` in the root
|
||||
`.env` file.
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — Configure Root Environment Variables
|
||||
|
||||
Create the root `.env` file:
|
||||
|
||||
```bash
|
||||
# From the repo root
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Fill out all values in `/.env`:
|
||||
|
||||
```bash
|
||||
# Next.js
|
||||
NODE_ENV=development
|
||||
SENTRY_AUTH_TOKEN= # From your self-hosted Sentry
|
||||
NEXT_PUBLIC_SITE_URL=https://example.com
|
||||
NEXT_PUBLIC_CONVEX_URL=https://api.convex.example.com
|
||||
NEXT_PUBLIC_PLAUSIBLE_URL=https://plausible.example.com
|
||||
NEXT_PUBLIC_SENTRY_DSN=
|
||||
NEXT_PUBLIC_SENTRY_URL=https://sentry.example.com
|
||||
NEXT_PUBLIC_SENTRY_ORG=sentry
|
||||
NEXT_PUBLIC_SENTRY_PROJECT_NAME=my-project
|
||||
|
||||
# Convex
|
||||
CONVEX_SELF_HOSTED_URL=https://api.convex.example.com
|
||||
CONVEX_SELF_HOSTED_ADMIN_KEY= # From Step 4
|
||||
CONVEX_SITE_URL=http://localhost:3000 # Always localhost:3000 for local dev
|
||||
|
||||
# Auth (synced to Convex in Step 6)
|
||||
USESEND_API_KEY=
|
||||
USESEND_URL=https://usesend.example.com
|
||||
USESEND_FROM_EMAIL=My App <noreply@example.com>
|
||||
AUTH_AUTHENTIK_ID=
|
||||
AUTH_AUTHENTIK_SECRET=
|
||||
AUTH_AUTHENTIK_ISSUER=https://auth.example.com/application/o/my-app/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 6 — Generate JWT Keys & Sync Environment Variables to Convex
|
||||
|
||||
Generate the RS256 JWT keypair needed for Convex Auth:
|
||||
|
||||
```bash
|
||||
cd packages/backend
|
||||
bun run scripts/generateKeys.mjs
|
||||
```
|
||||
|
||||
Sync environment variables to Convex deployment (via CLI or Dashboard):
|
||||
This prints `JWT_PRIVATE_KEY` and `JWKS` values. Sync them to your Convex deployment
|
||||
along with all other backend environment variables:
|
||||
|
||||
```bash
|
||||
cd packages/backend
|
||||
bun with-env npx convex env set AUTH_AUTHENTIK_ID "your-value"
|
||||
bun with-env npx convex env set AUTH_AUTHENTIK_SECRET "your-value"
|
||||
# From packages/backend/
|
||||
bun with-env npx convex env set JWT_PRIVATE_KEY "your-private-key"
|
||||
bun with-env npx convex env set JWKS "your-jwks"
|
||||
bun with-env npx convex env set AUTH_AUTHENTIK_ID "your-client-id"
|
||||
bun with-env npx convex env set AUTH_AUTHENTIK_SECRET "your-client-secret"
|
||||
bun with-env npx convex env set AUTH_AUTHENTIK_ISSUER "your-issuer-url"
|
||||
bun with-env npx convex env set USESEND_API_KEY "your-api-key"
|
||||
bun with-env npx convex env set CONVEX_SITE_URL "http://localhost:3000"
|
||||
bun with-env npx convex env set USESEND_URL "https://usesend.example.com"
|
||||
bun with-env npx convex env set USESEND_FROM_EMAIL "My App <noreply@example.com>"
|
||||
```
|
||||
|
||||
**Important:** For local development, set `CONVEX_SITE_URL` to `http://localhost:3000`.
|
||||
**For production auth to work**, you must also update `CONVEX_SITE_URL` in the Convex
|
||||
Dashboard to your production Next.js URL. Go to
|
||||
`https://dashboard.convex.example.com` → Settings → Environment Variables and set:
|
||||
|
||||
#### 6. Start Development Server
|
||||
```
|
||||
CONVEX_SITE_URL = https://example.com
|
||||
```
|
||||
|
||||
The root `.env` value of `http://localhost:3000` is correct for local dev and should
|
||||
not be changed — only update it in the Dashboard for production.
|
||||
|
||||
---
|
||||
|
||||
### Step 7 — Start the Development Server
|
||||
|
||||
```bash
|
||||
# From project root
|
||||
bun dev:next # Next.js app + Convex backend
|
||||
bun dev:next # Next.js app + Convex backend (most common)
|
||||
# or
|
||||
bun dev # All apps (Next.js + Expo + Backend)
|
||||
```
|
||||
@@ -137,7 +207,7 @@ bun dev # All apps (Next.js + Expo + Backend)
|
||||
**App URLs:**
|
||||
|
||||
- **Next.js:** http://localhost:3000
|
||||
- **Convex Dashboard:** http://localhost:6791
|
||||
- **Convex Dashboard:** https://dashboard.convex.example.com
|
||||
|
||||
---
|
||||
|
||||
@@ -193,7 +263,7 @@ convex-monorepo/
|
||||
│
|
||||
├── packages/
|
||||
│ ├── backend/ # Convex backend
|
||||
│ │ ├── convex/ # Convex functions (synced to cloud)
|
||||
│ │ ├── convex/ # Convex functions (synced to deployment)
|
||||
│ │ ├── scripts/ # Utilities (generateKeys.mjs)
|
||||
│ │ └── types/ # Shared types
|
||||
│ └── ui/ # shadcn/ui components
|
||||
@@ -223,16 +293,16 @@ convex-monorepo/
|
||||
- **OAuth:** Authentik SSO integration
|
||||
- **Password:** Custom password auth with email verification
|
||||
- **OTP:** Email verification via self-hosted UseSend
|
||||
- **Session Management:** Secure cookie-based sessions
|
||||
- **Session Management:** Secure cookie-based sessions (30-day max age)
|
||||
|
||||
### Next.js App
|
||||
|
||||
- **App Router:** Next.js 16 with React Server Components
|
||||
- **Data Preloading:** Server-side data fetching with Convex
|
||||
- **Middleware:** Route protection & authentication
|
||||
- **Styling:** Tailwind CSS v4 with dark mode
|
||||
- **Analytics:** Plausible (privacy-focused)
|
||||
- **Monitoring:** Sentry error tracking
|
||||
- **Data Preloading:** SSR data fetching with `preloadQuery` + `usePreloadedQuery`
|
||||
- **Middleware:** Route protection & IP-based security (`src/proxy.ts`)
|
||||
- **Styling:** Tailwind CSS v4 with dark mode (OKLCH-based theme)
|
||||
- **Analytics:** Plausible (privacy-focused, proxied through Next.js)
|
||||
- **Monitoring:** Sentry error tracking & performance
|
||||
|
||||
### Backend
|
||||
|
||||
@@ -244,87 +314,113 @@ convex-monorepo/
|
||||
|
||||
### Developer Experience
|
||||
|
||||
- **Monorepo:** Turborepo for efficient builds
|
||||
- **Monorepo:** Turborepo for efficient builds and caching
|
||||
- **Type Safety:** Strict TypeScript throughout
|
||||
- **Code Quality:** ESLint + Prettier with auto-fix
|
||||
- **Hot Reload:** Fast refresh for all packages
|
||||
- **Catalog Deps:** Centralized version management
|
||||
- **Catalog Deps:** Centralized dependency version management
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker (Recommended)
|
||||
### Production Deployment (Docker)
|
||||
|
||||
Build and deploy with Docker Compose:
|
||||
Once the Convex containers are running (they only need to be started once), deploying
|
||||
a new version of the Next.js app is a two-command workflow:
|
||||
|
||||
```bash
|
||||
# SSH onto your server, then:
|
||||
cd docker/
|
||||
|
||||
# Build the new image
|
||||
sudo docker compose build next-app
|
||||
|
||||
# Deploy it
|
||||
sudo docker compose up -d next-app
|
||||
```
|
||||
|
||||
To start all services from scratch:
|
||||
|
||||
```bash
|
||||
cd docker/
|
||||
|
||||
# Start all services
|
||||
docker compose up -d
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Stop services
|
||||
docker compose down
|
||||
sudo docker compose up -d convex-backend convex-dashboard
|
||||
# Wait for backend health check to pass, then:
|
||||
sudo docker compose up -d next-app
|
||||
```
|
||||
|
||||
**Services:**
|
||||
|
||||
- `next-app` - Next.js standalone build
|
||||
- `convex-backend` - Convex backend (port 3210)
|
||||
- `convex-dashboard` - Admin dashboard (port 6791)
|
||||
- `next-app` — Next.js standalone build
|
||||
- `convex-backend` — Convex backend (port 3210)
|
||||
- `convex-dashboard` — Admin dashboard (port 6791)
|
||||
|
||||
**Network:** Uses `nginx-bridge` network (configurable in `compose.yml`).
|
||||
**Network:** Uses `nginx-bridge` Docker network (reverse proxy via nginx-proxy-manager).
|
||||
|
||||
### Production Checklist
|
||||
|
||||
- [ ] Update environment variables in `docker/.env`
|
||||
- [ ] Generate `CONVEX_SELF_HOSTED_ADMIN_KEY`
|
||||
- [ ] Configure reverse proxy (Nginx/Traefik)
|
||||
- [ ] Set up SSL certificates
|
||||
- [ ] Sync auth environment variables to Convex
|
||||
- [ ] Configure backup strategy for `docker/data/`
|
||||
- [ ] Test authentication flow
|
||||
- [ ] Enable Sentry error tracking
|
||||
- [ ] Fill out `docker/.env` with your domain names and secrets
|
||||
- [ ] Start `convex-backend` and `convex-dashboard` containers
|
||||
- [ ] Generate and set `CONVEX_SELF_HOSTED_ADMIN_KEY` via `./generate_convex_admin_key`
|
||||
- [ ] Reverse-proxy both Convex services via nginx-proxy-manager with SSL
|
||||
- [ ] Fill out root `/.env` with all environment variables
|
||||
- [ ] Generate JWT keys and sync all env vars to Convex (`bun with-env npx convex env set ...`)
|
||||
- [ ] Update `CONVEX_SITE_URL` in the Convex Dashboard to your production Next.js URL
|
||||
- [ ] Build and start the `next-app` container
|
||||
- [ ] Back up `docker/data/` regularly (contains all Convex database data)
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[AGENTS.md](./AGENTS.md)** - Comprehensive guide for AI agents & developers
|
||||
- **[Convex Docs](https://docs.convex.dev)** - Official Convex documentation
|
||||
- **[Turborepo Docs](https://turbo.build/repo/docs)** - Turborepo documentation
|
||||
- **[Next.js Docs](https://nextjs.org/docs)** - Next.js documentation
|
||||
- **[AGENTS.md](./AGENTS.md)** — Comprehensive guide for AI agents & developers
|
||||
- **[Convex Docs](https://docs.convex.dev)** — Official Convex documentation
|
||||
- **[Turborepo Docs](https://turbo.build/repo/docs)** — Turborepo documentation
|
||||
- **[Next.js Docs](https://nextjs.org/docs)** — Next.js documentation
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Backend typecheck shows help message
|
||||
### Backend typecheck shows TypeScript help message
|
||||
|
||||
This is expected behavior. The backend package follows Convex's structure with only `convex/tsconfig.json` (no root tsconfig). See [AGENTS.md](./AGENTS.md) for details.
|
||||
This is expected behavior. The backend package follows Convex's structure with only
|
||||
`convex/tsconfig.json` (no root tsconfig). Running `bun typecheck` from the repo root
|
||||
will show TypeScript's help text for `@gib/backend` — this is not an error.
|
||||
|
||||
### Imports from Convex require .js extension
|
||||
### Imports from Convex require `.js` extension
|
||||
|
||||
The project uses ESM (`"type": "module"`), requiring explicit file extensions:
|
||||
The project uses ESM (`"type": "module"`), which requires explicit file extensions:
|
||||
|
||||
```typescript
|
||||
// ✅ Correct
|
||||
|
||||
// ❌ Wrong
|
||||
import type { Id } from '@gib/backend/convex/_generated/dataModel.js';
|
||||
// ❌ Wrong — will fail at runtime
|
||||
import { api } from '@gib/backend/convex/_generated/api';
|
||||
import { api } from '@gib/backend/convex/_generated/api.js';
|
||||
```
|
||||
|
||||
### Docker containers won't start
|
||||
|
||||
1. Check Docker logs: `docker compose logs`
|
||||
1. Check Docker logs: `sudo docker compose logs`
|
||||
2. Verify environment variables in `docker/.env`
|
||||
3. Ensure ports 3210 and 6791 are available
|
||||
4. Check network configuration (`nginx-bridge`)
|
||||
3. Ensure the `nginx-bridge` network exists: `sudo docker network create nginx-bridge`
|
||||
4. Check that the required ports (3210, 6791) are not already in use
|
||||
|
||||
### Auth doesn't work in production
|
||||
|
||||
Make sure `CONVEX_SITE_URL` is set to your production Next.js URL in the **Convex
|
||||
Dashboard** (not just in the root `.env` file). The root `.env` should always contain
|
||||
`http://localhost:3000`; the Dashboard must have your production URL.
|
||||
|
||||
### Catalog updates break workspace
|
||||
|
||||
After updating dependencies, if you see `sherif` errors on `bun install`:
|
||||
|
||||
1. Never use `bun update` inside individual package directories
|
||||
2. Edit the version in root `package.json` catalog section instead
|
||||
3. Run `bun install` from the root
|
||||
4. Verify with `bun lint:ws`
|
||||
|
||||
---
|
||||
|
||||
@@ -337,6 +433,7 @@ This is a personal monorepo template. Feel free to fork and adapt for your needs
|
||||
- Single quotes, trailing commas
|
||||
- 80 character line width
|
||||
- ESLint + Prettier enforced
|
||||
- `const fn = () => {}` over `function fn()` (strong preference)
|
||||
- Import order: Types → React → Next → Third-party → @gib → Local
|
||||
|
||||
Run `bun lint:fix` and `bun format:fix` before committing.
|
||||
|
||||
@@ -1 +1 @@
|
||||
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21"],{"key":"22","value":"23"},{"key":"24","value":"25"},{"key":"26","value":"27"},{"key":"28","value":"29"},{"key":"30","value":"31"},{"key":"32","value":"33"},{"key":"34","value":"35"},{"key":"36","value":"37"},{"key":"38","value":"39"},{"key":"40","value":"41"},{"key":"42","value":"43"},{"key":"44","value":"45"},{"key":"46","value":"47"},{"key":"48","value":"49"},{"key":"50","value":"51"},{"key":"52","value":"53"},{"key":"54","value":"55"},{"key":"56","value":"57"},{"key":"58","value":"59"},{"key":"60","value":"61"},{"key":"62","value":"63"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/package.json",{"size":2249,"mtime":1766222924000,"hash":"64","data":"65"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/index.ts",{"size":28,"mtime":1768155639000,"hash":"66","data":"67"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/metro.config.js",{"size":511,"mtime":1768155639000,"hash":"68","data":"69"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/index.tsx",{"size":5019,"mtime":1768372346938,"hash":"70","data":"71"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/turbo.json",{"size":163,"mtime":1766222924000,"hash":"72","data":"73"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/postcss.config.js",{"size":66,"mtime":1768155639000,"hash":"74","data":"75"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/eas.json",{"size":567,"mtime":1766222924000,"hash":"76","data":"77"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/.expo-shared/assets.json",{"size":155,"mtime":1766222924000,"hash":"78","data":"79"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/_layout.tsx",{"size":927,"mtime":1768155639000,"hash":"80","data":"81"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/nativewind-env.d.ts",{"size":246,"mtime":1766222924000,"hash":"82","data":"83"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/auth.ts",{"size":398,"mtime":1768155639000,"hash":"84","data":"85"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/post/[id].tsx",{"size":757,"mtime":1768372346967,"hash":"86","data":"87"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/styles.css",{"size":90,"mtime":1768155639000,"hash":"88","data":"89"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/session-store.ts",{"size":272,"mtime":1768155639000,"hash":"90","data":"91"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/assets/icon-dark.png",{"size":19633,"mtime":1766222924000,"hash":"92"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/eslint.config.mts",{"size":275,"mtime":1768155639000,"hash":"93","data":"94"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/api.tsx",{"size":1326,"mtime":1768155639000,"hash":"95","data":"96"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/base-url.ts",{"size":880,"mtime":1768155639000,"hash":"97","data":"98"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/app.config.ts",{"size":1333,"mtime":1768155639000,"hash":"99","data":"100"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/assets/icon-light.png",{"size":19133,"mtime":1766222924000,"hash":"101"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/tsconfig.json",{"size":387,"mtime":1766228480000,"hash":"102","data":"103"},"d8763702c14cdc382dcfb84f6f9a068f",{"hashOfOptions":"104"},"11cdbef6afa001cd39bc187041ca6865",{"hashOfOptions":"105"},"dbe97bcde588a81538bbcd6a9befdddd",{"hashOfOptions":"106"},"73c235a66242df70b69394cce29d1ed3",{"hashOfOptions":"107"},"c7d4dcf839dfeaa02e0407adfd5e47a6",{"hashOfOptions":"108"},"b7edffce093c4c84092cc93f3dc208ef",{"hashOfOptions":"109"},"a3c1487f8318513ae7c156acc857fde2",{"hashOfOptions":"110"},"0f7f54c7161b8403d3bc42d91f59cd91",{"hashOfOptions":"111"},"8e407b4b1b0c0bd9c862a00243344be3",{"hashOfOptions":"112"},"d4d589c153ac8b5e7bf0fb130a5b5a7d",{"hashOfOptions":"113"},"cecbed1604a530a7cc099fecddddd76c",{"hashOfOptions":"114"},"ead19d73283f9d8e08b55c896c9fd570",{"hashOfOptions":"115"},"52a1d72379b952dd802f47e1865bd0da",{"hashOfOptions":"116"},"1bc3e15a40c117eecc51294886ea9b38",{"hashOfOptions":"117"},"1e8ac0d261e95efb19d290ffcf70ce36","1c1710ce3de3ce02e8054cc3787c8579",{"hashOfOptions":"118"},"5ff899a601102659dcbd2900e415ce8b",{"hashOfOptions":"119"},"dd2007a211e323deabb3f7fa7d16313f",{"hashOfOptions":"120"},"4f49c6df7733f874fbe72b4e20b3092b",{"hashOfOptions":"121"},"863da15dbd856008b7c24077ca746d91","6937fb7370f1e17491df649888d6ecc9",{"hashOfOptions":"122"},"1820601142","1684748001","3531839294","2748941218","956511134","132171752","3925902565","1550174236","2506462393","526883382","4111358426","2953691686","2383171816","2740949298","3787272667","3740930138","4230803759","3315245788","3164486579"]
|
||||
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22"],{"key":"23","value":"24"},{"key":"25","value":"26"},{"key":"27","value":"28"},{"key":"29","value":"30"},{"key":"31","value":"32"},{"key":"33","value":"34"},{"key":"35","value":"36"},{"key":"37","value":"38"},{"key":"39","value":"40"},{"key":"41","value":"42"},{"key":"43","value":"44"},{"key":"45","value":"46"},{"key":"47","value":"48"},{"key":"49","value":"50"},{"key":"51","value":"52"},{"key":"53","value":"54"},{"key":"55","value":"56"},{"key":"57","value":"58"},{"key":"59","value":"60"},{"key":"61","value":"62"},{"key":"63","value":"64"},{"key":"65","value":"66"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/index.tsx",{"size":5019,"mtime":1768372346938,"hash":"67","data":"68"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/index.ts",{"size":28,"mtime":1768155639000,"hash":"69","data":"70"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/assets/icon-dark.png",{"size":19633,"mtime":1766222924000,"hash":"71"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/postcss.config.js",{"size":66,"mtime":1768155639000,"hash":"72","data":"73"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/auth.ts",{"size":398,"mtime":1768155639000,"hash":"74","data":"75"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/post/[id].tsx",{"size":757,"mtime":1768372346967,"hash":"76","data":"77"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/api.tsx",{"size":1326,"mtime":1768155639000,"hash":"78","data":"79"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/eas.json",{"size":567,"mtime":1766222924000,"hash":"80","data":"81"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/app/_layout.tsx",{"size":927,"mtime":1768155639000,"hash":"82","data":"83"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/styles.css",{"size":90,"mtime":1768155639000,"hash":"84","data":"85"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/.cache/.prettiercache",{"size":4929,"mtime":1774544485533},"/home/gib/Documents/Code/convex-monorepo/apps/expo/assets/icon-light.png",{"size":19133,"mtime":1766222924000,"hash":"86"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/package.json",{"size":2255,"mtime":1774544484676,"hash":"87","data":"88"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/turbo.json",{"size":171,"mtime":1774031879321,"hash":"89","data":"90"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/eslint.config.mts",{"size":275,"mtime":1768155639000,"hash":"91","data":"92"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/tsconfig.json",{"size":387,"mtime":1766228480000,"hash":"93","data":"94"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/metro.config.js",{"size":511,"mtime":1768155639000,"hash":"95","data":"96"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/nativewind-env.d.ts",{"size":246,"mtime":1766222924000,"hash":"97","data":"98"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/base-url.ts",{"size":880,"mtime":1768155639000,"hash":"99","data":"100"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/.expo-shared/assets.json",{"size":155,"mtime":1766222924000,"hash":"101","data":"102"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/src/utils/session-store.ts",{"size":272,"mtime":1768155639000,"hash":"103","data":"104"},"/home/gib/Documents/Code/convex-monorepo/apps/expo/app.config.ts",{"size":1333,"mtime":1768155639000,"hash":"105","data":"106"},"73c235a66242df70b69394cce29d1ed3",{"hashOfOptions":"107"},"11cdbef6afa001cd39bc187041ca6865",{"hashOfOptions":"108"},"1e8ac0d261e95efb19d290ffcf70ce36","b7edffce093c4c84092cc93f3dc208ef",{"hashOfOptions":"109"},"cecbed1604a530a7cc099fecddddd76c",{"hashOfOptions":"110"},"ead19d73283f9d8e08b55c896c9fd570",{"hashOfOptions":"111"},"5ff899a601102659dcbd2900e415ce8b",{"hashOfOptions":"112"},"a3c1487f8318513ae7c156acc857fde2",{"hashOfOptions":"113"},"8e407b4b1b0c0bd9c862a00243344be3",{"hashOfOptions":"114"},"52a1d72379b952dd802f47e1865bd0da",{"hashOfOptions":"115"},"863da15dbd856008b7c24077ca746d91","d8763702c14cdc382dcfb84f6f9a068f",{"hashOfOptions":"116"},"c7d4dcf839dfeaa02e0407adfd5e47a6",{"hashOfOptions":"117"},"1c1710ce3de3ce02e8054cc3787c8579",{"hashOfOptions":"118"},"6937fb7370f1e17491df649888d6ecc9",{"hashOfOptions":"119"},"dbe97bcde588a81538bbcd6a9befdddd",{"hashOfOptions":"120"},"d4d589c153ac8b5e7bf0fb130a5b5a7d",{"hashOfOptions":"121"},"dd2007a211e323deabb3f7fa7d16313f",{"hashOfOptions":"122"},"0f7f54c7161b8403d3bc42d91f59cd91",{"hashOfOptions":"123"},"1bc3e15a40c117eecc51294886ea9b38",{"hashOfOptions":"124"},"4f49c6df7733f874fbe72b4e20b3092b",{"hashOfOptions":"125"},"3000879843","3103968608","384110377","68329755","141502567","3992868763","1050155876","2025343866","4147067111","4228440757","3451484829","4039211292","3318113268","2585374463","45764855","1418614640","2754339483","1950506033","3468872477"]
|
||||
@@ -65,4 +65,3 @@
|
||||
},
|
||||
"prettier": "@gib/prettier-config"
|
||||
}
|
||||
|
||||
|
||||
1
apps/next/.cache/.eslintcache
Normal file
1
apps/next/.cache/.eslintcache
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
import { createJiti } from 'jiti';
|
||||
import { withSentryConfig } from '@sentry/nextjs';
|
||||
import { createJiti } from 'jiti';
|
||||
import { withPlausibleProxy } from 'next-plausible';
|
||||
|
||||
const jiti = createJiti(import.meta.url);
|
||||
|
||||
@@ -252,27 +252,27 @@ const SignIn = () => {
|
||||
<Tabs
|
||||
defaultValue={flow}
|
||||
onValueChange={(value) => setFlow(value as 'signIn' | 'signUp')}
|
||||
className='items-center flex-col'
|
||||
className='flex-col items-center'
|
||||
>
|
||||
<TabsList>
|
||||
<TabsTrigger
|
||||
value='signIn'
|
||||
className='cursor-pointer py-2 px-6 text-2xl font-bold'
|
||||
className='cursor-pointer px-6 py-2 text-2xl font-bold'
|
||||
>
|
||||
Sign In
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value='signUp'
|
||||
className='cursor-pointer py-2 px-6 text-2xl font-bold'
|
||||
className='cursor-pointer px-6 py-2 text-2xl font-bold'
|
||||
>
|
||||
Sign Up
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent
|
||||
value='signIn'
|
||||
className='min-h-[560px] items-center flex flex-row'
|
||||
className='flex min-h-[560px] flex-row items-center'
|
||||
>
|
||||
<Card className='bg-card/50 min-w-xs sm:min-w-sm py-10'>
|
||||
<Card className='bg-card/50 min-w-xs py-10 sm:min-w-sm'>
|
||||
<CardContent>
|
||||
<Form {...signInForm}>
|
||||
<form
|
||||
|
||||
@@ -10,12 +10,12 @@ import { useEffect } from 'react';
|
||||
import Footer from '@/components/layout/footer';
|
||||
import Header from '@/components/layout/header';
|
||||
import { ConvexClientProvider } from '@/components/providers';
|
||||
import { env } from '@/env';
|
||||
import { generateMetadata } from '@/lib/metadata';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
import PlausibleProvider from 'next-plausible';
|
||||
|
||||
import { Button, ThemeProvider, Toaster } from '@gib/ui';
|
||||
import { env } from '@/env';
|
||||
|
||||
export const metadata: Metadata = generateMetadata();
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export function CTA() {
|
||||
return (
|
||||
export const CTA = () => (
|
||||
<section className='container mx-auto px-4 py-24'>
|
||||
<div className='mx-auto max-w-4xl'>
|
||||
<div className='border-border/40 from-muted/50 to-muted/30 rounded-2xl border bg-linear-to-br p-8 text-center md:p-12'>
|
||||
@@ -29,5 +28,4 @@ export function CTA() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -57,8 +57,7 @@ const features = [
|
||||
},
|
||||
];
|
||||
|
||||
export function Features() {
|
||||
return (
|
||||
export const Features = () => (
|
||||
<section id='features' className='container mx-auto px-4 py-24'>
|
||||
<div className='mx-auto max-w-6xl'>
|
||||
{/* Section Header */}
|
||||
@@ -67,8 +66,8 @@ export function Features() {
|
||||
Everything You Need to Ship Fast
|
||||
</h2>
|
||||
<p className='text-muted-foreground mx-auto max-w-2xl text-lg'>
|
||||
A complete monorepo template with all the tools and patterns you
|
||||
need for production-ready applications.
|
||||
A complete monorepo template with all the tools and patterns you need
|
||||
for production-ready applications.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -88,5 +87,4 @@ export function Features() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -9,8 +9,7 @@ const kanitSans = Kanit({
|
||||
weight: ['400', '500', '600', '700'],
|
||||
});
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
export const Hero = () => (
|
||||
<section className='container mx-auto px-4 py-24 md:py-32 lg:py-40'>
|
||||
<div className='mx-auto flex max-w-5xl flex-col items-center gap-8 text-center'>
|
||||
{/* Badge */}
|
||||
@@ -31,9 +30,9 @@ export function Hero() {
|
||||
|
||||
{/* Description */}
|
||||
<p className='text-muted-foreground max-w-2xl text-lg md:text-xl'>
|
||||
A Turborepo starter with Next.js, Expo, and self-hosted Convex. Ship
|
||||
web and mobile apps faster with shared code, type-safe backend, and
|
||||
complete control over your infrastructure.
|
||||
A Turborepo starter with Next.js, Expo, and self-hosted Convex. Ship web
|
||||
and mobile apps faster with shared code, type-safe backend, and complete
|
||||
control over your infrastructure.
|
||||
</p>
|
||||
|
||||
{/* CTA Buttons */}
|
||||
@@ -124,5 +123,4 @@ export function Hero() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -36,8 +36,7 @@ const techStack = [
|
||||
},
|
||||
];
|
||||
|
||||
export function TechStack() {
|
||||
return (
|
||||
export const TechStack = () => (
|
||||
<section id='tech-stack' className='border-border/40 bg-muted/30 border-t'>
|
||||
<div className='container mx-auto px-4 py-24'>
|
||||
<div className='mx-auto max-w-6xl'>
|
||||
@@ -75,5 +74,4 @@ export function TechStack() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { CardDescription, CardHeader, CardTitle } from '@gib/ui';
|
||||
|
||||
const ProfileHeader = () => {
|
||||
|
||||
@@ -53,7 +53,7 @@ export const UserInfoForm = ({
|
||||
const userProvider = usePreloadedQuery(preloadedProvider);
|
||||
const providerMap: Record<string, string> = {
|
||||
unknown: 'Provider',
|
||||
authentik: 'Gib\'s Auth',
|
||||
authentik: "Gib's Auth",
|
||||
};
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -150,7 +150,8 @@ export const UserInfoForm = ({
|
||||
</FormDescription>
|
||||
) : (
|
||||
<FormDescription>
|
||||
Email is managed through your {providerMap[userProvider ?? 'unknown']} account
|
||||
Email is managed through your{' '}
|
||||
{providerMap[userProvider ?? 'unknown']} account
|
||||
</FormDescription>
|
||||
)}
|
||||
<FormMessage />
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function Header(headerProps: ComponentProps<'header'>) {
|
||||
alt='Convex Monorepo'
|
||||
width={50}
|
||||
height={50}
|
||||
className='invert dark:invert-0 w-15'
|
||||
className='w-15 invert dark:invert-0'
|
||||
/>
|
||||
<span
|
||||
className={`mb-3 hidden font-extrabold lg:inline lg:text-5xl ${kanitSans.className}`}
|
||||
|
||||
@@ -7,10 +7,8 @@ import { ConvexReactClient } from 'convex/react';
|
||||
|
||||
const convex = new ConvexReactClient(env.NEXT_PUBLIC_CONVEX_URL);
|
||||
|
||||
export function ConvexClientProvider({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
export const ConvexClientProvider = ({ children }: { children: ReactNode }) => (
|
||||
<ConvexAuthNextjsProvider client={convex}>
|
||||
{children}
|
||||
</ConvexAuthNextjsProvider>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -38,7 +38,8 @@ export const env = createEnv({
|
||||
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
NEXT_PUBLIC_SENTRY_URL: process.env.NEXT_PUBLIC_SENTRY_URL,
|
||||
NEXT_PUBLIC_SENTRY_ORG: process.env.NEXT_PUBLIC_SENTRY_ORG,
|
||||
NEXT_PUBLIC_SENTRY_PROJECT_NAME: process.env.NEXT_PUBLIC_SENTRY_PROJECT_NAME,
|
||||
NEXT_PUBLIC_SENTRY_PROJECT_NAME:
|
||||
process.env.NEXT_PUBLIC_SENTRY_PROJECT_NAME,
|
||||
},
|
||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||
emptyStringAsUndefined: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
import { env } from '@/env';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
Sentry.init({
|
||||
dsn: env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
import { env } from '@/env';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
Sentry.init({
|
||||
dsn: env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
|
||||
3
bun.lock
3
bun.lock
@@ -181,6 +181,7 @@
|
||||
"@next/eslint-plugin-next": "^16.0.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prefer-arrow-functions": "^3.9.1",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-turbo": "^2.5.8",
|
||||
@@ -1951,6 +1952,8 @@
|
||||
|
||||
"eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="],
|
||||
|
||||
"eslint-plugin-prefer-arrow-functions": ["eslint-plugin-prefer-arrow-functions@3.9.1", "", { "dependencies": { "@typescript-eslint/types": "^8.19.1", "@typescript-eslint/utils": "^8.19.1" }, "peerDependencies": { "eslint": ">=9.17.0" } }, "sha512-Mr9Ia8i5ohfCMcZBRedXXWdDJIo30gdKdPfRQ5DtO62yzogB5ErVGwQWPz+ycRlQPKpCAlBHpJdp1TCeCtt+YA=="],
|
||||
|
||||
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
|
||||
|
||||
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="],
|
||||
|
||||
@@ -18,7 +18,7 @@ ENV NODE_ENV=production
|
||||
RUN bun run build --filter=@gib/next
|
||||
|
||||
# Runner stage
|
||||
FROM node:20-alpine AS runner
|
||||
FROM node:22-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ export default function UseSendProvider(config: EmailUserConfig): EmailConfig {
|
||||
id: 'usesend',
|
||||
type: 'email',
|
||||
name: 'UseSend',
|
||||
from: 'Convex Monorepo <admin@convexmonorepo.gbrown.org>',
|
||||
from: process.env.USESEND_FROM_EMAIL ?? 'noreply@example.com',
|
||||
maxAge: 24 * 60 * 60, // 24 hours
|
||||
|
||||
async generateVerificationToken() {
|
||||
@@ -21,13 +21,14 @@ export default function UseSendProvider(config: EmailUserConfig): EmailConfig {
|
||||
},
|
||||
|
||||
async sendVerificationRequest(params) {
|
||||
const { identifier: to, provider, url, theme, token } = params;
|
||||
//const { host } = new URL(url);
|
||||
const host = 'Convex Monorepo';
|
||||
const { identifier: to, provider, url, token } = params;
|
||||
// Derive a display name from the site URL, fallback to 'App'
|
||||
const siteUrl = process.env.USESEND_FROM_EMAIL ?? '';
|
||||
const appName = siteUrl.split('@')[1]?.split('.')[0] ?? 'App';
|
||||
|
||||
const useSend = new UseSend(
|
||||
process.env.USESEND_API_KEY!,
|
||||
'https://usesend.gbrown.org',
|
||||
process.env.USESEND_URL!,
|
||||
);
|
||||
|
||||
// For password reset, we want to send the code, not the magic link
|
||||
@@ -38,8 +39,8 @@ export default function UseSendProvider(config: EmailUserConfig): EmailConfig {
|
||||
from: provider.from!,
|
||||
to: [to],
|
||||
subject: isPasswordReset
|
||||
? `Reset your password - ${host}`
|
||||
: `Sign in to ${host}`,
|
||||
? `Reset your password - ${appName}`
|
||||
: `Sign in to ${appName}`,
|
||||
text: isPasswordReset
|
||||
? `Your password reset code is ${token}`
|
||||
: `Your sign in code is ${token}`,
|
||||
|
||||
@@ -18,11 +18,9 @@ const applicationTables = {
|
||||
phoneVerificationTime: v.optional(v.number()),
|
||||
isAnonymous: v.optional(v.boolean()),
|
||||
/* Fields below here are custom & not defined in authTables */
|
||||
themePreference: v.optional(v.union(
|
||||
v.literal('light'),
|
||||
v.literal('dark'),
|
||||
v.literal('system'),
|
||||
)),
|
||||
themePreference: v.optional(
|
||||
v.union(v.literal('light'), v.literal('dark'), v.literal('system')),
|
||||
),
|
||||
})
|
||||
.index('email', ['email'])
|
||||
.index('phone', ['phone'])
|
||||
|
||||
1
packages/ui/.cache/.eslintcache
Normal file
1
packages/ui/.cache/.eslintcache
Normal file
File diff suppressed because one or more lines are too long
1
packages/ui/.cache/.prettiercache
Normal file
1
packages/ui/.cache/.prettiercache
Normal file
File diff suppressed because one or more lines are too long
@@ -6,38 +6,33 @@ import { Accordion as AccordionPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Accordion({
|
||||
const Accordion = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Root>) => (
|
||||
<AccordionPrimitive.Root
|
||||
data-slot='accordion'
|
||||
className={cn('flex w-full flex-col', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AccordionItem({
|
||||
const AccordionItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Item>) => (
|
||||
<AccordionPrimitive.Item
|
||||
data-slot='accordion-item'
|
||||
className={cn('not-last:border-b', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AccordionTrigger({
|
||||
const AccordionTrigger = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) => (
|
||||
<AccordionPrimitive.Header className='flex'>
|
||||
<AccordionPrimitive.Trigger
|
||||
data-slot='accordion-trigger'
|
||||
@@ -58,15 +53,13 @@ function AccordionTrigger({
|
||||
/>
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AccordionContent({
|
||||
const AccordionContent = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AccordionPrimitive.Content>) => (
|
||||
<AccordionPrimitive.Content
|
||||
data-slot='accordion-content'
|
||||
className='data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm'
|
||||
@@ -81,7 +74,6 @@ function AccordionContent({
|
||||
{children}
|
||||
</div>
|
||||
</AccordionPrimitive.Content>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
|
||||
@@ -5,33 +5,28 @@ import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
|
||||
|
||||
import { Button, cn } from '@gib/ui';
|
||||
|
||||
function AlertDialog({
|
||||
const AlertDialog = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
||||
return <AlertDialogPrimitive.Root data-slot='alert-dialog' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) => (
|
||||
<AlertDialogPrimitive.Root data-slot='alert-dialog' {...props} />
|
||||
);
|
||||
|
||||
function AlertDialogTrigger({
|
||||
const AlertDialogTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) => (
|
||||
<AlertDialogPrimitive.Trigger data-slot='alert-dialog-trigger' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogPortal({
|
||||
const AlertDialogPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) => (
|
||||
<AlertDialogPrimitive.Portal data-slot='alert-dialog-portal' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogOverlay({
|
||||
const AlertDialogOverlay = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
data-slot='alert-dialog-overlay'
|
||||
className={cn(
|
||||
@@ -40,17 +35,15 @@ function AlertDialogOverlay({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogContent({
|
||||
const AlertDialogContent = ({
|
||||
className,
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
|
||||
size?: 'default' | 'sm';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay />
|
||||
<AlertDialogPrimitive.Content
|
||||
@@ -63,14 +56,12 @@ function AlertDialogContent({
|
||||
{...props}
|
||||
/>
|
||||
</AlertDialogPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogHeader({
|
||||
const AlertDialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-dialog-header'
|
||||
className={cn(
|
||||
@@ -79,14 +70,12 @@ function AlertDialogHeader({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogFooter({
|
||||
const AlertDialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-dialog-footer'
|
||||
className={cn(
|
||||
@@ -95,14 +84,12 @@ function AlertDialogFooter({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogMedia({
|
||||
const AlertDialogMedia = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-dialog-media'
|
||||
className={cn(
|
||||
@@ -111,14 +98,12 @@ function AlertDialogMedia({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogTitle({
|
||||
const AlertDialogTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
data-slot='alert-dialog-title'
|
||||
className={cn(
|
||||
@@ -127,14 +112,12 @@ function AlertDialogTitle({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogDescription({
|
||||
const AlertDialogDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
data-slot='alert-dialog-description'
|
||||
className={cn(
|
||||
@@ -143,17 +126,15 @@ function AlertDialogDescription({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogAction({
|
||||
const AlertDialogAction = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
|
||||
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
|
||||
return (
|
||||
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) => (
|
||||
<Button variant={variant} size={size} asChild>
|
||||
<AlertDialogPrimitive.Action
|
||||
data-slot='alert-dialog-action'
|
||||
@@ -161,17 +142,15 @@ function AlertDialogAction({
|
||||
{...props}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDialogCancel({
|
||||
const AlertDialogCancel = ({
|
||||
className,
|
||||
variant = 'outline',
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
|
||||
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
|
||||
return (
|
||||
Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) => (
|
||||
<Button variant={variant} size={size} asChild>
|
||||
<AlertDialogPrimitive.Cancel
|
||||
data-slot='alert-dialog-cancel'
|
||||
@@ -179,8 +158,7 @@ function AlertDialogCancel({
|
||||
{...props}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
|
||||
@@ -20,23 +20,20 @@ const alertVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function Alert({
|
||||
const Alert = ({
|
||||
className,
|
||||
variant,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) => (
|
||||
<div
|
||||
data-slot='alert'
|
||||
role='alert'
|
||||
className={cn(alertVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const AlertTitle = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-title'
|
||||
className={cn(
|
||||
@@ -45,14 +42,12 @@ function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertDescription({
|
||||
const AlertDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-description'
|
||||
className={cn(
|
||||
@@ -61,17 +56,14 @@ function AlertDescription({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AlertAction({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const AlertAction = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='alert-action'
|
||||
className={cn('absolute top-2 right-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription, AlertAction };
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import { AspectRatio as AspectRatioPrimitive } from 'radix-ui';
|
||||
|
||||
function AspectRatio({
|
||||
const AspectRatio = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
|
||||
return <AspectRatioPrimitive.Root data-slot='aspect-ratio' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) => (
|
||||
<AspectRatioPrimitive.Root data-slot='aspect-ratio' {...props} />
|
||||
);
|
||||
export { AspectRatio };
|
||||
|
||||
@@ -5,14 +5,13 @@ import { Avatar as AvatarPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Avatar({
|
||||
const Avatar = ({
|
||||
className,
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
|
||||
size?: 'default' | 'sm' | 'lg';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<AvatarPrimitive.Root
|
||||
data-slot='avatar'
|
||||
data-size={size}
|
||||
@@ -22,27 +21,23 @@ function Avatar({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AvatarImage({
|
||||
const AvatarImage = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) => (
|
||||
<AvatarPrimitive.Image
|
||||
data-slot='avatar-image'
|
||||
className={cn('aspect-square size-full', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AvatarFallback({
|
||||
const AvatarFallback = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) => (
|
||||
<AvatarPrimitive.Fallback
|
||||
data-slot='avatar-fallback'
|
||||
className={cn(
|
||||
@@ -51,11 +46,9 @@ function AvatarFallback({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
const AvatarBadge = ({ className, ...props }: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='avatar-badge'
|
||||
className={cn(
|
||||
@@ -67,11 +60,9 @@ function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const AvatarGroup = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='avatar-group'
|
||||
className={cn(
|
||||
@@ -80,14 +71,12 @@ function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function AvatarGroupCount({
|
||||
const AvatarGroupCount = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='avatar-group-count'
|
||||
className={cn(
|
||||
@@ -96,8 +85,7 @@ function AvatarGroupCount({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Avatar,
|
||||
|
||||
@@ -27,13 +27,13 @@ const badgeVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function Badge({
|
||||
const Badge = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'span'> &
|
||||
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
||||
VariantProps<typeof badgeVariants> & { asChild?: boolean }) => {
|
||||
const Comp = asChild ? Slot.Root : 'span';
|
||||
|
||||
return (
|
||||
@@ -44,6 +44,6 @@ function Badge({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export { Badge, badgeVariants };
|
||||
|
||||
@@ -4,12 +4,14 @@ import { Slot } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
|
||||
return <nav aria-label='breadcrumb' data-slot='breadcrumb' {...props} />;
|
||||
}
|
||||
const Breadcrumb = ({ ...props }: React.ComponentProps<'nav'>) => (
|
||||
<nav aria-label='breadcrumb' data-slot='breadcrumb' {...props} />
|
||||
);
|
||||
|
||||
function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
|
||||
return (
|
||||
const BreadcrumbList = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'ol'>) => (
|
||||
<ol
|
||||
data-slot='breadcrumb-list'
|
||||
className={cn(
|
||||
@@ -18,26 +20,26 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
|
||||
return (
|
||||
const BreadcrumbItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'li'>) => (
|
||||
<li
|
||||
data-slot='breadcrumb-item'
|
||||
className={cn('inline-flex items-center gap-1.5', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function BreadcrumbLink({
|
||||
const BreadcrumbLink = ({
|
||||
asChild,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'a'> & {
|
||||
asChild?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
const Comp = asChild ? Slot.Root : 'a';
|
||||
|
||||
return (
|
||||
@@ -47,10 +49,12 @@ function BreadcrumbLink({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
const BreadcrumbPage = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='breadcrumb-page'
|
||||
role='link'
|
||||
@@ -59,15 +63,13 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
className={cn('text-foreground font-normal', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function BreadcrumbSeparator({
|
||||
const BreadcrumbSeparator = ({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'li'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'li'>) => (
|
||||
<li
|
||||
data-slot='breadcrumb-separator'
|
||||
role='presentation'
|
||||
@@ -77,14 +79,12 @@ function BreadcrumbSeparator({
|
||||
>
|
||||
{children ?? <ChevronRight />}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function BreadcrumbEllipsis({
|
||||
const BreadcrumbEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='breadcrumb-ellipsis'
|
||||
role='presentation'
|
||||
@@ -95,8 +95,7 @@ function BreadcrumbEllipsis({
|
||||
<MoreHorizontal className='size-4' />
|
||||
<span className='sr-only'>More</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Breadcrumb,
|
||||
|
||||
@@ -21,12 +21,11 @@ const buttonGroupVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function ButtonGroup({
|
||||
const ButtonGroup = ({
|
||||
className,
|
||||
orientation,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof buttonGroupVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof buttonGroupVariants>) => (
|
||||
<div
|
||||
role='group'
|
||||
data-slot='button-group'
|
||||
@@ -34,16 +33,15 @@ function ButtonGroup({
|
||||
className={cn(buttonGroupVariants({ orientation }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ButtonGroupText({
|
||||
const ButtonGroupText = ({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
asChild?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
const Comp = asChild ? Slot.Root : 'div';
|
||||
|
||||
return (
|
||||
@@ -55,14 +53,13 @@ function ButtonGroupText({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function ButtonGroupSeparator({
|
||||
const ButtonGroupSeparator = ({
|
||||
className,
|
||||
orientation = 'vertical',
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof Separator>) => (
|
||||
<Separator
|
||||
data-slot='button-group-separator'
|
||||
orientation={orientation}
|
||||
@@ -72,8 +69,7 @@ function ButtonGroupSeparator({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
ButtonGroup,
|
||||
|
||||
@@ -42,7 +42,7 @@ const buttonVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function Button({
|
||||
const Button = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
@@ -51,7 +51,7 @@ function Button({
|
||||
}: React.ComponentProps<'button'> &
|
||||
VariantProps<typeof buttonVariants> & {
|
||||
asChild?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
const Comp = asChild ? Slot.Root : 'button';
|
||||
|
||||
return (
|
||||
@@ -63,6 +63,6 @@ function Button({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export { Button, buttonVariants };
|
||||
|
||||
@@ -11,7 +11,7 @@ import { DayPicker, getDefaultClassNames } from 'react-day-picker';
|
||||
|
||||
import { Button, buttonVariants, cn } from '@gib/ui';
|
||||
|
||||
function Calendar({
|
||||
const Calendar = ({
|
||||
className,
|
||||
classNames,
|
||||
showOutsideDays = true,
|
||||
@@ -23,7 +23,7 @@ function Calendar({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DayPicker> & {
|
||||
buttonVariant?: React.ComponentProps<typeof Button>['variant'];
|
||||
}) {
|
||||
}) => {
|
||||
const defaultClassNames = getDefaultClassNames();
|
||||
|
||||
return (
|
||||
@@ -183,15 +183,15 @@ function Calendar({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function CalendarDayButton({
|
||||
const CalendarDayButton = ({
|
||||
className,
|
||||
day,
|
||||
modifiers,
|
||||
locale,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
|
||||
}: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) => {
|
||||
const defaultClassNames = getDefaultClassNames();
|
||||
|
||||
const ref = React.useRef<HTMLButtonElement>(null);
|
||||
@@ -222,6 +222,6 @@ function CalendarDayButton({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export { Calendar, CalendarDayButton };
|
||||
|
||||
@@ -2,12 +2,11 @@ import type * as React from 'react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Card({
|
||||
const Card = ({
|
||||
className,
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) => (
|
||||
<div
|
||||
data-slot='card'
|
||||
data-size={size}
|
||||
@@ -17,11 +16,9 @@ function Card({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-header'
|
||||
className={cn(
|
||||
@@ -30,11 +27,9 @@ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardTitle = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-title'
|
||||
className={cn(
|
||||
@@ -43,21 +38,20 @@ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-description'
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardAction = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-action'
|
||||
className={cn(
|
||||
@@ -66,21 +60,17 @@ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardContent = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-content'
|
||||
className={cn('px-4 group-data-[size=sm]/card:px-3', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const CardFooter = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='card-footer'
|
||||
className={cn(
|
||||
@@ -89,8 +79,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Card,
|
||||
|
||||
@@ -12,12 +12,12 @@ type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||
type CarouselOptions = UseCarouselParameters[0];
|
||||
type CarouselPlugin = UseCarouselParameters[1];
|
||||
|
||||
type CarouselProps = {
|
||||
interface CarouselProps {
|
||||
opts?: CarouselOptions;
|
||||
plugins?: CarouselPlugin;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
setApi?: (api: CarouselApi) => void;
|
||||
};
|
||||
}
|
||||
|
||||
type CarouselContextProps = {
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
||||
@@ -30,7 +30,7 @@ type CarouselContextProps = {
|
||||
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
|
||||
|
||||
function useCarousel() {
|
||||
const useCarousel = () => {
|
||||
const context = React.useContext(CarouselContext);
|
||||
|
||||
if (!context) {
|
||||
@@ -38,9 +38,9 @@ function useCarousel() {
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
function Carousel({
|
||||
const Carousel = ({
|
||||
orientation = 'horizontal',
|
||||
opts,
|
||||
setApi,
|
||||
@@ -48,7 +48,7 @@ function Carousel({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & CarouselProps) {
|
||||
}: React.ComponentProps<'div'> & CarouselProps) => {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
@@ -128,9 +128,12 @@ function Carousel({
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
const CarouselContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => {
|
||||
const { carouselRef, orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
@@ -149,9 +152,9 @@ function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
const CarouselItem = ({ className, ...props }: React.ComponentProps<'div'>) => {
|
||||
const { orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
@@ -167,14 +170,14 @@ function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function CarouselPrevious({
|
||||
const CarouselPrevious = ({
|
||||
className,
|
||||
variant = 'outline',
|
||||
size = 'icon-sm',
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
}: React.ComponentProps<typeof Button>) => {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
||||
|
||||
return (
|
||||
@@ -197,14 +200,14 @@ function CarouselPrevious({
|
||||
<span className='sr-only'>Previous slide</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function CarouselNext({
|
||||
const CarouselNext = ({
|
||||
className,
|
||||
variant = 'outline',
|
||||
size = 'icon-sm',
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
}: React.ComponentProps<typeof Button>) => {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
||||
|
||||
return (
|
||||
@@ -227,7 +230,7 @@ function CarouselNext({
|
||||
<span className='sr-only'>Next slide</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
type CarouselApi,
|
||||
|
||||
@@ -8,23 +8,24 @@ import { cn } from '@gib/ui';
|
||||
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||
const THEMES = { light: '', dark: '.dark' } as const;
|
||||
|
||||
export type ChartConfig = {
|
||||
[k in string]: {
|
||||
export type ChartConfig = Record<
|
||||
string,
|
||||
{
|
||||
label?: React.ReactNode;
|
||||
icon?: React.ComponentType;
|
||||
} & (
|
||||
| { color?: string; theme?: never }
|
||||
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
||||
);
|
||||
};
|
||||
)
|
||||
>;
|
||||
|
||||
type ChartContextProps = {
|
||||
interface ChartContextProps {
|
||||
config: ChartConfig;
|
||||
};
|
||||
}
|
||||
|
||||
const ChartContext = React.createContext<ChartContextProps | null>(null);
|
||||
|
||||
function useChart() {
|
||||
const useChart = () => {
|
||||
const context = React.useContext(ChartContext);
|
||||
|
||||
if (!context) {
|
||||
@@ -32,9 +33,9 @@ function useChart() {
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
function ChartContainer({
|
||||
const ChartContainer = ({
|
||||
id,
|
||||
className,
|
||||
children,
|
||||
@@ -45,7 +46,7 @@ function ChartContainer({
|
||||
children: React.ComponentProps<
|
||||
typeof RechartsPrimitive.ResponsiveContainer
|
||||
>['children'];
|
||||
}) {
|
||||
}) => {
|
||||
const uniqueId = React.useId();
|
||||
const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;
|
||||
|
||||
@@ -67,7 +68,7 @@ function ChartContainer({
|
||||
</div>
|
||||
</ChartContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||
const colorConfig = Object.entries(config).filter(
|
||||
@@ -104,7 +105,7 @@ ${colorConfig
|
||||
|
||||
const ChartTooltip = RechartsPrimitive.Tooltip;
|
||||
|
||||
function ChartTooltipContent({
|
||||
const ChartTooltipContent = ({
|
||||
active,
|
||||
payload,
|
||||
className,
|
||||
@@ -125,7 +126,7 @@ function ChartTooltipContent({
|
||||
indicator?: 'line' | 'dot' | 'dashed';
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}) {
|
||||
}) => {
|
||||
const { config } = useChart();
|
||||
|
||||
const tooltipLabel = React.useMemo(() => {
|
||||
@@ -138,7 +139,7 @@ function ChartTooltipContent({
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||
const value =
|
||||
!labelKey && typeof label === 'string'
|
||||
? config[label as keyof typeof config]?.label || label
|
||||
? config[label]?.label || label
|
||||
: itemConfig?.label;
|
||||
|
||||
if (labelFormatter) {
|
||||
@@ -248,11 +249,11 @@ function ChartTooltipContent({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const ChartLegend = RechartsPrimitive.Legend;
|
||||
|
||||
function ChartLegendContent({
|
||||
const ChartLegendContent = ({
|
||||
className,
|
||||
hideIcon = false,
|
||||
payload,
|
||||
@@ -262,7 +263,7 @@ function ChartLegendContent({
|
||||
Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}) {
|
||||
}) => {
|
||||
const { config } = useChart();
|
||||
|
||||
if (!payload?.length) {
|
||||
@@ -306,13 +307,13 @@ function ChartLegendContent({
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function getPayloadConfigFromPayload(
|
||||
const getPayloadConfigFromPayload = (
|
||||
config: ChartConfig,
|
||||
payload: unknown,
|
||||
key: string,
|
||||
) {
|
||||
) => {
|
||||
if (typeof payload !== 'object' || payload === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -341,10 +342,8 @@ function getPayloadConfigFromPayload(
|
||||
] as string;
|
||||
}
|
||||
|
||||
return configLabelKey in config
|
||||
? config[configLabelKey]
|
||||
: config[key as keyof typeof config];
|
||||
}
|
||||
return configLabelKey in config ? config[configLabelKey] : config[key];
|
||||
};
|
||||
|
||||
export {
|
||||
ChartContainer,
|
||||
|
||||
@@ -6,11 +6,10 @@ import { Checkbox as CheckboxPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Checkbox({
|
||||
const Checkbox = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) => (
|
||||
<CheckboxPrimitive.Root
|
||||
data-slot='checkbox'
|
||||
className={cn(
|
||||
@@ -26,7 +25,6 @@ function Checkbox({
|
||||
<CheckIcon />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Checkbox };
|
||||
|
||||
@@ -2,32 +2,28 @@
|
||||
|
||||
import { Collapsible as CollapsiblePrimitive } from 'radix-ui';
|
||||
|
||||
function Collapsible({
|
||||
const Collapsible = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
|
||||
return <CollapsiblePrimitive.Root data-slot='collapsible' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) => (
|
||||
<CollapsiblePrimitive.Root data-slot='collapsible' {...props} />
|
||||
);
|
||||
|
||||
function CollapsibleTrigger({
|
||||
const CollapsibleTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) => (
|
||||
<CollapsiblePrimitive.CollapsibleTrigger
|
||||
data-slot='collapsible-trigger'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CollapsibleContent({
|
||||
const CollapsibleContent = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) => (
|
||||
<CollapsiblePrimitive.CollapsibleContent
|
||||
data-slot='collapsible-content'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
||||
|
||||
@@ -15,16 +15,15 @@ import {
|
||||
|
||||
const Combobox = ComboboxPrimitive.Root;
|
||||
|
||||
function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
|
||||
return <ComboboxPrimitive.Value data-slot='combobox-value' {...props} />;
|
||||
}
|
||||
const ComboboxValue = ({ ...props }: ComboboxPrimitive.Value.Props) => (
|
||||
<ComboboxPrimitive.Value data-slot='combobox-value' {...props} />
|
||||
);
|
||||
|
||||
function ComboboxTrigger({
|
||||
const ComboboxTrigger = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: ComboboxPrimitive.Trigger.Props) {
|
||||
return (
|
||||
}: ComboboxPrimitive.Trigger.Props) => (
|
||||
<ComboboxPrimitive.Trigger
|
||||
data-slot='combobox-trigger'
|
||||
className={cn("[&_svg:not([class*='size-'])]:size-4", className)}
|
||||
@@ -33,11 +32,12 @@ function ComboboxTrigger({
|
||||
{children}
|
||||
<ChevronDownIcon className='text-muted-foreground pointer-events-none size-4' />
|
||||
</ComboboxPrimitive.Trigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
|
||||
return (
|
||||
const ComboboxClear = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.Clear.Props) => (
|
||||
<ComboboxPrimitive.Clear
|
||||
data-slot='combobox-clear'
|
||||
className={cn(className)}
|
||||
@@ -48,10 +48,9 @@ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
|
||||
</InputGroupButton>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxInput({
|
||||
const ComboboxInput = ({
|
||||
className,
|
||||
children,
|
||||
disabled = false,
|
||||
@@ -61,8 +60,7 @@ function ComboboxInput({
|
||||
}: ComboboxPrimitive.Input.Props & {
|
||||
showTrigger?: boolean;
|
||||
showClear?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<InputGroup className={cn('w-auto', className)}>
|
||||
<ComboboxPrimitive.Input
|
||||
render={<InputGroupInput disabled={disabled} />}
|
||||
@@ -83,10 +81,9 @@ function ComboboxInput({
|
||||
</InputGroupAddon>
|
||||
{children}
|
||||
</InputGroup>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxContent({
|
||||
const ComboboxContent = ({
|
||||
className,
|
||||
side = 'bottom',
|
||||
sideOffset = 6,
|
||||
@@ -98,8 +95,7 @@ function ComboboxContent({
|
||||
Pick<
|
||||
ComboboxPrimitive.Positioner.Props,
|
||||
'side' | 'align' | 'sideOffset' | 'alignOffset' | 'anchor'
|
||||
>) {
|
||||
return (
|
||||
>) => (
|
||||
<ComboboxPrimitive.Portal>
|
||||
<ComboboxPrimitive.Positioner
|
||||
side={side}
|
||||
@@ -120,11 +116,12 @@ function ComboboxContent({
|
||||
/>
|
||||
</ComboboxPrimitive.Positioner>
|
||||
</ComboboxPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
|
||||
return (
|
||||
const ComboboxList = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.List.Props) => (
|
||||
<ComboboxPrimitive.List
|
||||
data-slot='combobox-list'
|
||||
className={cn(
|
||||
@@ -133,15 +130,13 @@ function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxItem({
|
||||
const ComboboxItem = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: ComboboxPrimitive.Item.Props) {
|
||||
return (
|
||||
}: ComboboxPrimitive.Item.Props) => (
|
||||
<ComboboxPrimitive.Item
|
||||
data-slot='combobox-item'
|
||||
className={cn(
|
||||
@@ -159,40 +154,40 @@ function ComboboxItem({
|
||||
}
|
||||
/>
|
||||
</ComboboxPrimitive.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
|
||||
return (
|
||||
const ComboboxGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.Group.Props) => (
|
||||
<ComboboxPrimitive.Group
|
||||
data-slot='combobox-group'
|
||||
className={cn(className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxLabel({
|
||||
const ComboboxLabel = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.GroupLabel.Props) {
|
||||
return (
|
||||
}: ComboboxPrimitive.GroupLabel.Props) => (
|
||||
<ComboboxPrimitive.GroupLabel
|
||||
data-slot='combobox-label'
|
||||
className={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
|
||||
return (
|
||||
const ComboboxCollection = ({
|
||||
...props
|
||||
}: ComboboxPrimitive.Collection.Props) => (
|
||||
<ComboboxPrimitive.Collection data-slot='combobox-collection' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
|
||||
return (
|
||||
const ComboboxEmpty = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.Empty.Props) => (
|
||||
<ComboboxPrimitive.Empty
|
||||
data-slot='combobox-empty'
|
||||
className={cn(
|
||||
@@ -201,28 +196,24 @@ function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxSeparator({
|
||||
const ComboboxSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.Separator.Props) {
|
||||
return (
|
||||
}: ComboboxPrimitive.Separator.Props) => (
|
||||
<ComboboxPrimitive.Separator
|
||||
data-slot='combobox-separator'
|
||||
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxChips({
|
||||
const ComboboxChips = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
|
||||
ComboboxPrimitive.Chips.Props) {
|
||||
return (
|
||||
ComboboxPrimitive.Chips.Props) => (
|
||||
<ComboboxPrimitive.Chips
|
||||
data-slot='combobox-chips'
|
||||
className={cn(
|
||||
@@ -231,18 +222,16 @@ function ComboboxChips({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxChip({
|
||||
const ComboboxChip = ({
|
||||
className,
|
||||
children,
|
||||
showRemove = true,
|
||||
...props
|
||||
}: ComboboxPrimitive.Chip.Props & {
|
||||
showRemove?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ComboboxPrimitive.Chip
|
||||
data-slot='combobox-chip'
|
||||
className={cn(
|
||||
@@ -264,25 +253,20 @@ function ComboboxChip({
|
||||
/>
|
||||
)}
|
||||
</ComboboxPrimitive.Chip>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ComboboxChipsInput({
|
||||
const ComboboxChipsInput = ({
|
||||
className,
|
||||
...props
|
||||
}: ComboboxPrimitive.Input.Props) {
|
||||
return (
|
||||
}: ComboboxPrimitive.Input.Props) => (
|
||||
<ComboboxPrimitive.Input
|
||||
data-slot='combobox-chip-input'
|
||||
className={cn('min-w-16 flex-1 outline-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function useComboboxAnchor() {
|
||||
return React.useRef<HTMLDivElement | null>(null);
|
||||
}
|
||||
const useComboboxAnchor = () => React.useRef<HTMLDivElement | null>(null);
|
||||
|
||||
export {
|
||||
Combobox,
|
||||
|
||||
@@ -15,11 +15,10 @@ import {
|
||||
InputGroupAddon,
|
||||
} from '@gib/ui';
|
||||
|
||||
function Command({
|
||||
const Command = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive>) => (
|
||||
<CommandPrimitive
|
||||
data-slot='command'
|
||||
className={cn(
|
||||
@@ -28,10 +27,9 @@ function Command({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandDialog({
|
||||
const CommandDialog = ({
|
||||
title = 'Command Palette',
|
||||
description = 'Search for a command to run...',
|
||||
children,
|
||||
@@ -43,8 +41,7 @@ function CommandDialog({
|
||||
description?: string;
|
||||
className?: string;
|
||||
showCloseButton?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<Dialog {...props}>
|
||||
<DialogHeader className='sr-only'>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
@@ -60,14 +57,12 @@ function CommandDialog({
|
||||
{children}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandInput({
|
||||
const CommandInput = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Input>) => (
|
||||
<div data-slot='command-input-wrapper' className='p-1 pb-0'>
|
||||
<InputGroup className='bg-input/30 border-input/30 h-8! rounded-lg! shadow-none! *:data-[slot=input-group-addon]:pl-2!'>
|
||||
<CommandPrimitive.Input
|
||||
@@ -83,14 +78,12 @@ function CommandInput({
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandList({
|
||||
const CommandList = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.List>) => (
|
||||
<CommandPrimitive.List
|
||||
data-slot='command-list'
|
||||
className={cn(
|
||||
@@ -99,27 +92,23 @@ function CommandList({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandEmpty({
|
||||
const CommandEmpty = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Empty>) => (
|
||||
<CommandPrimitive.Empty
|
||||
data-slot='command-empty'
|
||||
className={cn('py-6 text-center text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandGroup({
|
||||
const CommandGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Group>) => (
|
||||
<CommandPrimitive.Group
|
||||
data-slot='command-group'
|
||||
className={cn(
|
||||
@@ -128,28 +117,24 @@ function CommandGroup({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandSeparator({
|
||||
const CommandSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Separator>) => (
|
||||
<CommandPrimitive.Separator
|
||||
data-slot='command-separator'
|
||||
className={cn('bg-border -mx-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandItem({
|
||||
const CommandItem = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof CommandPrimitive.Item>) => (
|
||||
<CommandPrimitive.Item
|
||||
data-slot='command-item'
|
||||
className={cn(
|
||||
@@ -161,14 +146,12 @@ function CommandItem({
|
||||
{children}
|
||||
<CheckIcon className='ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100' />
|
||||
</CommandPrimitive.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function CommandShortcut({
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='command-shortcut'
|
||||
className={cn(
|
||||
@@ -177,8 +160,7 @@ function CommandShortcut({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Command,
|
||||
|
||||
@@ -6,65 +6,56 @@ import { ContextMenu as ContextMenuPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function ContextMenu({
|
||||
const ContextMenu = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
|
||||
return <ContextMenuPrimitive.Root data-slot='context-menu' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) => (
|
||||
<ContextMenuPrimitive.Root data-slot='context-menu' {...props} />
|
||||
);
|
||||
|
||||
function ContextMenuTrigger({
|
||||
const ContextMenuTrigger = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) => (
|
||||
<ContextMenuPrimitive.Trigger
|
||||
data-slot='context-menu-trigger'
|
||||
className={cn('select-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuGroup({
|
||||
const ContextMenuGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) => (
|
||||
<ContextMenuPrimitive.Group data-slot='context-menu-group' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuPortal({
|
||||
const ContextMenuPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) => (
|
||||
<ContextMenuPrimitive.Portal data-slot='context-menu-portal' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuSub({
|
||||
const ContextMenuSub = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
|
||||
return <ContextMenuPrimitive.Sub data-slot='context-menu-sub' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) => (
|
||||
<ContextMenuPrimitive.Sub data-slot='context-menu-sub' {...props} />
|
||||
);
|
||||
|
||||
function ContextMenuRadioGroup({
|
||||
const ContextMenuRadioGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) => (
|
||||
<ContextMenuPrimitive.RadioGroup
|
||||
data-slot='context-menu-radio-group'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuContent({
|
||||
const ContextMenuContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Content> & {
|
||||
side?: 'top' | 'right' | 'bottom' | 'left';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.Portal>
|
||||
<ContextMenuPrimitive.Content
|
||||
data-slot='context-menu-content'
|
||||
@@ -75,10 +66,9 @@ function ContextMenuContent({
|
||||
{...props}
|
||||
/>
|
||||
</ContextMenuPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuItem({
|
||||
const ContextMenuItem = ({
|
||||
className,
|
||||
inset,
|
||||
variant = 'default',
|
||||
@@ -86,8 +76,7 @@ function ContextMenuItem({
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
variant?: 'default' | 'destructive';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.Item
|
||||
data-slot='context-menu-item'
|
||||
data-inset={inset}
|
||||
@@ -98,18 +87,16 @@ function ContextMenuItem({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuSubTrigger({
|
||||
const ContextMenuSubTrigger = ({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.SubTrigger
|
||||
data-slot='context-menu-sub-trigger'
|
||||
data-inset={inset}
|
||||
@@ -122,14 +109,12 @@ function ContextMenuSubTrigger({
|
||||
{children}
|
||||
<ChevronRightIcon className='cn-rtl-flip ml-auto' />
|
||||
</ContextMenuPrimitive.SubTrigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuSubContent({
|
||||
const ContextMenuSubContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) => (
|
||||
<ContextMenuPrimitive.SubContent
|
||||
data-slot='context-menu-sub-content'
|
||||
className={cn(
|
||||
@@ -138,10 +123,9 @@ function ContextMenuSubContent({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuCheckboxItem({
|
||||
const ContextMenuCheckboxItem = ({
|
||||
className,
|
||||
children,
|
||||
checked,
|
||||
@@ -149,8 +133,7 @@ function ContextMenuCheckboxItem({
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.CheckboxItem
|
||||
data-slot='context-menu-checkbox-item'
|
||||
data-inset={inset}
|
||||
@@ -168,18 +151,16 @@ function ContextMenuCheckboxItem({
|
||||
</span>
|
||||
{children}
|
||||
</ContextMenuPrimitive.CheckboxItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuRadioItem({
|
||||
const ContextMenuRadioItem = ({
|
||||
className,
|
||||
children,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.RadioItem
|
||||
data-slot='context-menu-radio-item'
|
||||
data-inset={inset}
|
||||
@@ -196,17 +177,15 @@ function ContextMenuRadioItem({
|
||||
</span>
|
||||
{children}
|
||||
</ContextMenuPrimitive.RadioItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuLabel({
|
||||
const ContextMenuLabel = ({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ContextMenuPrimitive.Label
|
||||
data-slot='context-menu-label'
|
||||
data-inset={inset}
|
||||
@@ -216,27 +195,23 @@ function ContextMenuLabel({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuSeparator({
|
||||
const ContextMenuSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) => (
|
||||
<ContextMenuPrimitive.Separator
|
||||
data-slot='context-menu-separator'
|
||||
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ContextMenuShortcut({
|
||||
const ContextMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='context-menu-shortcut'
|
||||
className={cn(
|
||||
@@ -245,8 +220,7 @@ function ContextMenuShortcut({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
ContextMenu,
|
||||
|
||||
@@ -6,35 +6,34 @@ import { Dialog as DialogPrimitive } from 'radix-ui';
|
||||
|
||||
import { Button, cn } from '@gib/ui';
|
||||
|
||||
function Dialog({
|
||||
const Dialog = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
||||
return <DialogPrimitive.Root data-slot='dialog' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Root>) => (
|
||||
<DialogPrimitive.Root data-slot='dialog' {...props} />
|
||||
);
|
||||
|
||||
function DialogTrigger({
|
||||
const DialogTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
||||
return <DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) => (
|
||||
<DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />
|
||||
);
|
||||
|
||||
function DialogPortal({
|
||||
const DialogPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
||||
return <DialogPrimitive.Portal data-slot='dialog-portal' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Portal>) => (
|
||||
<DialogPrimitive.Portal data-slot='dialog-portal' {...props} />
|
||||
);
|
||||
|
||||
function DialogClose({
|
||||
const DialogClose = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
||||
return <DialogPrimitive.Close data-slot='dialog-close' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Close>) => (
|
||||
<DialogPrimitive.Close data-slot='dialog-close' {...props} />
|
||||
);
|
||||
|
||||
function DialogOverlay({
|
||||
const DialogOverlay = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) => (
|
||||
<DialogPrimitive.Overlay
|
||||
data-slot='dialog-overlay'
|
||||
className={cn(
|
||||
@@ -43,18 +42,16 @@ function DialogOverlay({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DialogContent({
|
||||
const DialogContent = ({
|
||||
className,
|
||||
children,
|
||||
showCloseButton = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
||||
showCloseButton?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
@@ -80,28 +77,24 @@ function DialogContent({
|
||||
)}
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const DialogHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='dialog-header'
|
||||
className={cn('flex flex-col gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DialogFooter({
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
showCloseButton = false,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
showCloseButton?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<div
|
||||
data-slot='dialog-footer'
|
||||
className={cn(
|
||||
@@ -117,27 +110,23 @@ function DialogFooter({
|
||||
</DialogPrimitive.Close>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DialogTitle({
|
||||
const DialogTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Title>) => (
|
||||
<DialogPrimitive.Title
|
||||
data-slot='dialog-title'
|
||||
className={cn('text-base leading-none font-medium', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DialogDescription({
|
||||
const DialogDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DialogPrimitive.Description>) => (
|
||||
<DialogPrimitive.Description
|
||||
data-slot='dialog-description'
|
||||
className={cn(
|
||||
@@ -146,8 +135,7 @@ function DialogDescription({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
|
||||
@@ -5,35 +5,34 @@ import { Drawer as DrawerPrimitive } from 'vaul';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Drawer({
|
||||
const Drawer = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Root>) {
|
||||
return <DrawerPrimitive.Root data-slot='drawer' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
||||
<DrawerPrimitive.Root data-slot='drawer' {...props} />
|
||||
);
|
||||
|
||||
function DrawerTrigger({
|
||||
const DrawerTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
|
||||
return <DrawerPrimitive.Trigger data-slot='drawer-trigger' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) => (
|
||||
<DrawerPrimitive.Trigger data-slot='drawer-trigger' {...props} />
|
||||
);
|
||||
|
||||
function DrawerPortal({
|
||||
const DrawerPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
|
||||
return <DrawerPrimitive.Portal data-slot='drawer-portal' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Portal>) => (
|
||||
<DrawerPrimitive.Portal data-slot='drawer-portal' {...props} />
|
||||
);
|
||||
|
||||
function DrawerClose({
|
||||
const DrawerClose = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Close>) {
|
||||
return <DrawerPrimitive.Close data-slot='drawer-close' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Close>) => (
|
||||
<DrawerPrimitive.Close data-slot='drawer-close' {...props} />
|
||||
);
|
||||
|
||||
function DrawerOverlay({
|
||||
const DrawerOverlay = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) => (
|
||||
<DrawerPrimitive.Overlay
|
||||
data-slot='drawer-overlay'
|
||||
className={cn(
|
||||
@@ -42,15 +41,13 @@ function DrawerOverlay({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DrawerContent({
|
||||
const DrawerContent = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Content>) => (
|
||||
<DrawerPortal data-slot='drawer-portal'>
|
||||
<DrawerOverlay />
|
||||
<DrawerPrimitive.Content
|
||||
@@ -65,11 +62,9 @@ function DrawerContent({
|
||||
{children}
|
||||
</DrawerPrimitive.Content>
|
||||
</DrawerPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DrawerHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const DrawerHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='drawer-header'
|
||||
className={cn(
|
||||
@@ -78,44 +73,37 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DrawerFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const DrawerFooter = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='drawer-footer'
|
||||
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DrawerTitle({
|
||||
const DrawerTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Title>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Title>) => (
|
||||
<DrawerPrimitive.Title
|
||||
data-slot='drawer-title'
|
||||
className={cn('text-foreground text-base font-medium', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DrawerDescription({
|
||||
const DrawerDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Description>) => (
|
||||
<DrawerPrimitive.Description
|
||||
data-slot='drawer-description'
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Drawer,
|
||||
|
||||
@@ -6,38 +6,30 @@ import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function DropdownMenu({
|
||||
const DropdownMenu = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
||||
return <DropdownMenuPrimitive.Root data-slot='dropdown-menu' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) => (
|
||||
<DropdownMenuPrimitive.Root data-slot='dropdown-menu' {...props} />
|
||||
);
|
||||
|
||||
function DropdownMenuPortal({
|
||||
const DropdownMenuPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) => (
|
||||
<DropdownMenuPrimitive.Portal data-slot='dropdown-menu-portal' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuTrigger({
|
||||
const DropdownMenuTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Trigger
|
||||
data-slot='dropdown-menu-trigger'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) => (
|
||||
<DropdownMenuPrimitive.Trigger data-slot='dropdown-menu-trigger' {...props} />
|
||||
);
|
||||
|
||||
function DropdownMenuContent({
|
||||
const DropdownMenuContent = ({
|
||||
className,
|
||||
align = 'start',
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
data-slot='dropdown-menu-content'
|
||||
@@ -50,18 +42,15 @@ function DropdownMenuContent({
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuGroup({
|
||||
const DropdownMenuGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) => (
|
||||
<DropdownMenuPrimitive.Group data-slot='dropdown-menu-group' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuItem({
|
||||
const DropdownMenuItem = ({
|
||||
className,
|
||||
inset,
|
||||
variant = 'default',
|
||||
@@ -69,8 +58,7 @@ function DropdownMenuItem({
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
variant?: 'default' | 'destructive';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
data-slot='dropdown-menu-item'
|
||||
data-inset={inset}
|
||||
@@ -81,10 +69,9 @@ function DropdownMenuItem({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuCheckboxItem({
|
||||
const DropdownMenuCheckboxItem = ({
|
||||
className,
|
||||
children,
|
||||
checked,
|
||||
@@ -92,8 +79,7 @@ function DropdownMenuCheckboxItem({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
data-slot='dropdown-menu-checkbox-item'
|
||||
data-inset={inset}
|
||||
@@ -114,29 +100,25 @@ function DropdownMenuCheckboxItem({
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuRadioGroup({
|
||||
const DropdownMenuRadioGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) => (
|
||||
<DropdownMenuPrimitive.RadioGroup
|
||||
data-slot='dropdown-menu-radio-group'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuRadioItem({
|
||||
const DropdownMenuRadioItem = ({
|
||||
className,
|
||||
children,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
data-slot='dropdown-menu-radio-item'
|
||||
data-inset={inset}
|
||||
@@ -156,17 +138,15 @@ function DropdownMenuRadioItem({
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuLabel({
|
||||
const DropdownMenuLabel = ({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
data-slot='dropdown-menu-label'
|
||||
data-inset={inset}
|
||||
@@ -176,27 +156,23 @@ function DropdownMenuLabel({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuSeparator({
|
||||
const DropdownMenuSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
data-slot='dropdown-menu-separator'
|
||||
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuShortcut({
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='dropdown-menu-shortcut'
|
||||
className={cn(
|
||||
@@ -205,24 +181,22 @@ function DropdownMenuShortcut({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuSub({
|
||||
const DropdownMenuSub = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
||||
return <DropdownMenuPrimitive.Sub data-slot='dropdown-menu-sub' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) => (
|
||||
<DropdownMenuPrimitive.Sub data-slot='dropdown-menu-sub' {...props} />
|
||||
);
|
||||
|
||||
function DropdownMenuSubTrigger({
|
||||
const DropdownMenuSubTrigger = ({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
data-slot='dropdown-menu-sub-trigger'
|
||||
data-inset={inset}
|
||||
@@ -235,14 +209,12 @@ function DropdownMenuSubTrigger({
|
||||
{children}
|
||||
<ChevronRightIcon className='cn-rtl-flip ml-auto' />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function DropdownMenuSubContent({
|
||||
const DropdownMenuSubContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
data-slot='dropdown-menu-sub-content'
|
||||
className={cn(
|
||||
@@ -251,8 +223,7 @@ function DropdownMenuSubContent({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
|
||||
@@ -3,8 +3,7 @@ import { cva } from 'class-variance-authority';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Empty({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const Empty = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='empty'
|
||||
className={cn(
|
||||
@@ -13,18 +12,15 @@ function Empty({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const EmptyHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='empty-header'
|
||||
className={cn('flex max-w-sm flex-col items-center gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const emptyMediaVariants = cva(
|
||||
'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
||||
@@ -41,33 +37,31 @@ const emptyMediaVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function EmptyMedia({
|
||||
const EmptyMedia = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) => (
|
||||
<div
|
||||
data-slot='empty-icon'
|
||||
data-variant={variant}
|
||||
className={cn(emptyMediaVariants({ variant, className }))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const EmptyTitle = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='empty-title'
|
||||
className={cn('text-sm font-medium tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
const EmptyDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'p'>) => (
|
||||
<div
|
||||
data-slot='empty-description'
|
||||
className={cn(
|
||||
@@ -76,11 +70,9 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const EmptyContent = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='empty-content'
|
||||
className={cn(
|
||||
@@ -89,8 +81,7 @@ function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Empty,
|
||||
|
||||
@@ -6,11 +6,10 @@ import { cva } from 'class-variance-authority';
|
||||
|
||||
import { cn, Label, Separator } from '@gib/ui';
|
||||
|
||||
export function FieldSet({
|
||||
export const FieldSet = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'fieldset'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'fieldset'>) => (
|
||||
<fieldset
|
||||
data-slot='field-set'
|
||||
className={cn(
|
||||
@@ -20,15 +19,13 @@ export function FieldSet({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldLegend({
|
||||
export const FieldLegend = ({
|
||||
className,
|
||||
variant = 'legend',
|
||||
...props
|
||||
}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {
|
||||
return (
|
||||
}: React.ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) => (
|
||||
<legend
|
||||
data-slot='field-legend'
|
||||
data-variant={variant}
|
||||
@@ -40,14 +37,12 @@ export function FieldLegend({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldGroup({
|
||||
export const FieldGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='field-group'
|
||||
className={cn(
|
||||
@@ -56,8 +51,7 @@ export function FieldGroup({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const fieldVariants = cva(
|
||||
'group/field data-[invalid=true]:text-destructive flex w-full gap-3',
|
||||
@@ -83,12 +77,11 @@ const fieldVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
export function Field({
|
||||
export const Field = ({
|
||||
className,
|
||||
orientation = 'vertical',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof fieldVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof fieldVariants>) => (
|
||||
<div
|
||||
role='group'
|
||||
data-slot='field'
|
||||
@@ -96,14 +89,12 @@ export function Field({
|
||||
className={cn(fieldVariants({ orientation }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldContent({
|
||||
export const FieldContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='field-content'
|
||||
className={cn(
|
||||
@@ -112,14 +103,12 @@ export function FieldContent({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldLabel({
|
||||
export const FieldLabel = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Label>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof Label>) => (
|
||||
<Label
|
||||
data-slot='field-label'
|
||||
className={cn(
|
||||
@@ -130,14 +119,12 @@ export function FieldLabel({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldTitle({
|
||||
export const FieldTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='field-label'
|
||||
className={cn(
|
||||
@@ -146,14 +133,12 @@ export function FieldTitle({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldDescription({
|
||||
export const FieldDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'p'>) => (
|
||||
<p
|
||||
data-slot='field-description'
|
||||
className={cn(
|
||||
@@ -164,17 +149,15 @@ export function FieldDescription({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldSeparator({
|
||||
export const FieldSeparator = ({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<div
|
||||
data-slot='field-separator'
|
||||
data-content={!!children}
|
||||
@@ -194,17 +177,16 @@ export function FieldSeparator({
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function FieldError({
|
||||
export const FieldError = ({
|
||||
className,
|
||||
children,
|
||||
errors: maybeErrors,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
errors?: ({ message?: string } | undefined)[];
|
||||
}) {
|
||||
}) => {
|
||||
const content = useMemo(() => {
|
||||
if (children) {
|
||||
return children;
|
||||
@@ -244,4 +226,4 @@ export function FieldError({
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,12 +15,12 @@ import { cn, Label } from '@gib/ui';
|
||||
|
||||
const Form = FormProvider;
|
||||
|
||||
type FormFieldContextValue<
|
||||
interface FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
> = {
|
||||
> {
|
||||
name: TName;
|
||||
};
|
||||
}
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue,
|
||||
@@ -62,15 +62,15 @@ const useFormField = () => {
|
||||
};
|
||||
};
|
||||
|
||||
type FormItemContextValue = {
|
||||
interface FormItemContextValue {
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue,
|
||||
);
|
||||
|
||||
function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
const FormItem = ({ className, ...props }: React.ComponentProps<'div'>) => {
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
@@ -82,12 +82,12 @@ function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
/>
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function FormLabel({
|
||||
const FormLabel = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) => {
|
||||
const { error, formItemId } = useFormField();
|
||||
|
||||
return (
|
||||
@@ -99,9 +99,9 @@ function FormLabel({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
|
||||
const FormControl = ({ ...props }: React.ComponentProps<typeof Slot>) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||
useFormField();
|
||||
|
||||
@@ -118,9 +118,12 @@ function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
const FormDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'p'>) => {
|
||||
const { formDescriptionId } = useFormField();
|
||||
|
||||
return (
|
||||
@@ -131,9 +134,9 @@ function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
const FormMessage = ({ className, ...props }: React.ComponentProps<'p'>) => {
|
||||
const { error, formMessageId } = useFormField();
|
||||
const body = error ? String(error?.message ?? '') : props.children;
|
||||
|
||||
@@ -151,7 +154,7 @@ function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
{body}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
|
||||
const MOBILE_BREAKPOINT = 768;
|
||||
|
||||
export function useIsMobile() {
|
||||
export const useIsMobile = () => {
|
||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
||||
undefined,
|
||||
);
|
||||
@@ -18,4 +18,4 @@ export function useIsMobile() {
|
||||
}, []);
|
||||
|
||||
return !!isMobile;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,12 +9,12 @@ type EventType =
|
||||
| 'focusin'
|
||||
| 'focusout';
|
||||
|
||||
export function useOnClickOutside<T extends HTMLElement = HTMLElement>(
|
||||
export const useOnClickOutside = <T,>(
|
||||
ref: React.RefObject<T | null> | React.RefObject<T | null>[],
|
||||
handler: (event: MouseEvent | TouchEvent | FocusEvent) => void,
|
||||
eventType: EventType = 'mousedown',
|
||||
eventListenerOptions: AddEventListenerOptions = {},
|
||||
): void {
|
||||
): void => {
|
||||
const savedHandler = React.useRef(handler);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
@@ -55,6 +55,6 @@ export function useOnClickOutside<T extends HTMLElement = HTMLElement>(
|
||||
);
|
||||
};
|
||||
}, [ref, eventType, eventListenerOptions]);
|
||||
}
|
||||
};
|
||||
|
||||
export type { EventType };
|
||||
|
||||
@@ -5,27 +5,24 @@ import { HoverCard as HoverCardPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function HoverCard({
|
||||
const HoverCard = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
||||
return <HoverCardPrimitive.Root data-slot='hover-card' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) => (
|
||||
<HoverCardPrimitive.Root data-slot='hover-card' {...props} />
|
||||
);
|
||||
|
||||
function HoverCardTrigger({
|
||||
const HoverCardTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) => (
|
||||
<HoverCardPrimitive.Trigger data-slot='hover-card-trigger' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function HoverCardContent({
|
||||
const HoverCardContent = ({
|
||||
className,
|
||||
align = 'center',
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) => (
|
||||
<HoverCardPrimitive.Portal data-slot='hover-card-portal'>
|
||||
<HoverCardPrimitive.Content
|
||||
data-slot='hover-card-content'
|
||||
@@ -38,7 +35,6 @@ function HoverCardContent({
|
||||
{...props}
|
||||
/>
|
||||
</HoverCardPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
||||
|
||||
@@ -378,7 +378,7 @@ export const Cropper = ({
|
||||
</ImageCrop>
|
||||
);
|
||||
|
||||
export function Demo() {
|
||||
export const Demo = () => {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [croppedImage, setCroppedImage] = useState<string | null>(null);
|
||||
|
||||
@@ -432,4 +432,4 @@ export function Demo() {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,8 +6,7 @@ import { cva } from 'class-variance-authority';
|
||||
|
||||
import { Button, cn, Input, Textarea } from '@gib/ui';
|
||||
|
||||
function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const InputGroup = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='input-group'
|
||||
role='group'
|
||||
@@ -17,8 +16,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const inputGroupAddonVariants = cva(
|
||||
"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
|
||||
@@ -41,12 +39,12 @@ const inputGroupAddonVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function InputGroupAddon({
|
||||
const InputGroupAddon = ({
|
||||
className,
|
||||
align = 'inline-start',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> &
|
||||
VariantProps<typeof inputGroupAddonVariants>) => (
|
||||
<div
|
||||
role='group'
|
||||
data-slot='input-group-addon'
|
||||
@@ -60,8 +58,7 @@ function InputGroupAddon({
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const inputGroupButtonVariants = cva(
|
||||
'flex items-center gap-2 text-sm shadow-none',
|
||||
@@ -81,15 +78,14 @@ const inputGroupButtonVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function InputGroupButton({
|
||||
const InputGroupButton = ({
|
||||
className,
|
||||
type = 'button',
|
||||
variant = 'ghost',
|
||||
size = 'xs',
|
||||
...props
|
||||
}: Omit<React.ComponentProps<typeof Button>, 'size'> &
|
||||
VariantProps<typeof inputGroupButtonVariants>) {
|
||||
return (
|
||||
VariantProps<typeof inputGroupButtonVariants>) => (
|
||||
<Button
|
||||
type={type}
|
||||
data-size={size}
|
||||
@@ -97,11 +93,12 @@ function InputGroupButton({
|
||||
className={cn(inputGroupButtonVariants({ size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
const InputGroupText = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
className={cn(
|
||||
"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
||||
@@ -109,14 +106,12 @@ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function InputGroupInput({
|
||||
const InputGroupInput = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'input'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'input'>) => (
|
||||
<Input
|
||||
data-slot='input-group-control'
|
||||
className={cn(
|
||||
@@ -125,14 +120,12 @@ function InputGroupInput({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function InputGroupTextarea({
|
||||
const InputGroupTextarea = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'textarea'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'textarea'>) => (
|
||||
<Textarea
|
||||
data-slot='input-group-control'
|
||||
className={cn(
|
||||
@@ -141,8 +134,7 @@ function InputGroupTextarea({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
InputGroup,
|
||||
|
||||
@@ -6,14 +6,13 @@ import { MinusIcon } from 'lucide-react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function InputOTP({
|
||||
const InputOTP = ({
|
||||
className,
|
||||
containerClassName,
|
||||
...props
|
||||
}: React.ComponentProps<typeof OTPInput> & {
|
||||
containerClassName?: string;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<OTPInput
|
||||
data-slot='input-otp'
|
||||
containerClassName={cn(
|
||||
@@ -24,11 +23,12 @@ function InputOTP({
|
||||
className={cn('disabled:cursor-not-allowed', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const InputOTPGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='input-otp-group'
|
||||
className={cn(
|
||||
@@ -37,16 +37,15 @@ function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function InputOTPSlot({
|
||||
const InputOTPSlot = ({
|
||||
index,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
index: number;
|
||||
}) {
|
||||
}) => {
|
||||
const inputOTPContext = React.useContext(OTPInputContext);
|
||||
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
|
||||
|
||||
@@ -68,10 +67,9 @@ function InputOTPSlot({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const InputOTPSeparator = ({ ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='input-otp-separator'
|
||||
className="flex items-center [&_svg:not([class*='size-'])]:size-4"
|
||||
@@ -80,7 +78,6 @@ function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
|
||||
>
|
||||
<MinusIcon />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
|
||||
|
||||
@@ -2,8 +2,11 @@ import type * as React from 'react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
return (
|
||||
const Input = ({
|
||||
className,
|
||||
type,
|
||||
...props
|
||||
}: React.ComponentProps<'input'>) => (
|
||||
<input
|
||||
type={type}
|
||||
data-slot='input'
|
||||
@@ -13,7 +16,6 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Input };
|
||||
|
||||
@@ -5,8 +5,7 @@ import { Slot } from 'radix-ui';
|
||||
|
||||
import { cn, Separator } from '@gib/ui';
|
||||
|
||||
function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemGroup = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
role='list'
|
||||
data-slot='item-group'
|
||||
@@ -16,22 +15,19 @@ function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemSeparator({
|
||||
const ItemSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof Separator>) => (
|
||||
<Separator
|
||||
data-slot='item-separator'
|
||||
orientation='horizontal'
|
||||
className={cn('my-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const itemVariants = cva(
|
||||
'[a]:hover:bg-muted group/item focus-visible:border-ring focus-visible:ring-ring/50 flex w-full flex-wrap items-center rounded-lg border text-sm transition-colors duration-100 outline-none focus-visible:ring-[3px] [a]:transition-colors',
|
||||
@@ -55,14 +51,14 @@ const itemVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function Item({
|
||||
const Item = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
size = 'default',
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> &
|
||||
VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
||||
VariantProps<typeof itemVariants> & { asChild?: boolean }) => {
|
||||
const Comp = asChild ? Slot.Root : 'div';
|
||||
return (
|
||||
<Comp
|
||||
@@ -73,7 +69,7 @@ function Item({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const itemMediaVariants = cva(
|
||||
'flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none',
|
||||
@@ -92,23 +88,20 @@ const itemMediaVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function ItemMedia({
|
||||
const ItemMedia = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>) => (
|
||||
<div
|
||||
data-slot='item-media'
|
||||
data-variant={variant}
|
||||
className={cn(itemMediaVariants({ variant, className }))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemContent = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='item-content'
|
||||
className={cn(
|
||||
@@ -117,11 +110,9 @@ function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemTitle = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='item-title'
|
||||
className={cn(
|
||||
@@ -130,11 +121,12 @@ function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
const ItemDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'p'>) => (
|
||||
<p
|
||||
data-slot='item-description'
|
||||
className={cn(
|
||||
@@ -143,21 +135,17 @@ function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemActions({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemActions = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='item-actions'
|
||||
className={cn('flex items-center gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='item-header'
|
||||
className={cn(
|
||||
@@ -166,11 +154,9 @@ function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const ItemFooter = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='item-footer'
|
||||
className={cn(
|
||||
@@ -179,8 +165,7 @@ function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Item,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
|
||||
return (
|
||||
const Kbd = ({ className, ...props }: React.ComponentProps<'kbd'>) => (
|
||||
<kbd
|
||||
data-slot='kbd'
|
||||
className={cn(
|
||||
@@ -10,17 +9,14 @@ function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function KbdGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const KbdGroup = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<kbd
|
||||
data-slot='kbd-group'
|
||||
className={cn('inline-flex items-center gap-1', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Kbd, KbdGroup };
|
||||
|
||||
@@ -5,11 +5,10 @@ import { Label as LabelPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Label({
|
||||
const Label = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) => (
|
||||
<LabelPrimitive.Root
|
||||
data-slot='label'
|
||||
className={cn(
|
||||
@@ -18,6 +17,5 @@ function Label({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
export { Label };
|
||||
|
||||
@@ -6,11 +6,10 @@ import { Menubar as MenubarPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Menubar({
|
||||
const Menubar = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Root>) => (
|
||||
<MenubarPrimitive.Root
|
||||
data-slot='menubar'
|
||||
className={cn(
|
||||
@@ -19,40 +18,36 @@ function Menubar({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarMenu({
|
||||
const MenubarMenu = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
|
||||
return <MenubarPrimitive.Menu data-slot='menubar-menu' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Menu>) => (
|
||||
<MenubarPrimitive.Menu data-slot='menubar-menu' {...props} />
|
||||
);
|
||||
|
||||
function MenubarGroup({
|
||||
const MenubarGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Group>) {
|
||||
return <MenubarPrimitive.Group data-slot='menubar-group' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Group>) => (
|
||||
<MenubarPrimitive.Group data-slot='menubar-group' {...props} />
|
||||
);
|
||||
|
||||
function MenubarPortal({
|
||||
const MenubarPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
|
||||
return <MenubarPrimitive.Portal data-slot='menubar-portal' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Portal>) => (
|
||||
<MenubarPrimitive.Portal data-slot='menubar-portal' {...props} />
|
||||
);
|
||||
|
||||
function MenubarRadioGroup({
|
||||
const MenubarRadioGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) => (
|
||||
<MenubarPrimitive.RadioGroup data-slot='menubar-radio-group' {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarTrigger({
|
||||
const MenubarTrigger = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) => (
|
||||
<MenubarPrimitive.Trigger
|
||||
data-slot='menubar-trigger'
|
||||
className={cn(
|
||||
@@ -61,17 +56,15 @@ function MenubarTrigger({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarContent({
|
||||
const MenubarContent = ({
|
||||
className,
|
||||
align = 'start',
|
||||
alignOffset = -4,
|
||||
sideOffset = 8,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Content>) => (
|
||||
<MenubarPortal>
|
||||
<MenubarPrimitive.Content
|
||||
data-slot='menubar-content'
|
||||
@@ -85,10 +78,9 @@ function MenubarContent({
|
||||
{...props}
|
||||
/>
|
||||
</MenubarPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarItem({
|
||||
const MenubarItem = ({
|
||||
className,
|
||||
inset,
|
||||
variant = 'default',
|
||||
@@ -96,8 +88,7 @@ function MenubarItem({
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
variant?: 'default' | 'destructive';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<MenubarPrimitive.Item
|
||||
data-slot='menubar-item'
|
||||
data-inset={inset}
|
||||
@@ -108,16 +99,14 @@ function MenubarItem({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarCheckboxItem({
|
||||
const MenubarCheckboxItem = ({
|
||||
className,
|
||||
children,
|
||||
checked,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) => (
|
||||
<MenubarPrimitive.CheckboxItem
|
||||
data-slot='menubar-checkbox-item'
|
||||
className={cn(
|
||||
@@ -134,15 +123,13 @@ function MenubarCheckboxItem({
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.CheckboxItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarRadioItem({
|
||||
const MenubarRadioItem = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) => (
|
||||
<MenubarPrimitive.RadioItem
|
||||
data-slot='menubar-radio-item'
|
||||
className={cn(
|
||||
@@ -158,17 +145,15 @@ function MenubarRadioItem({
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.RadioItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarLabel({
|
||||
const MenubarLabel = ({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<MenubarPrimitive.Label
|
||||
data-slot='menubar-label'
|
||||
data-inset={inset}
|
||||
@@ -178,27 +163,23 @@ function MenubarLabel({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarSeparator({
|
||||
const MenubarSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Separator>) => (
|
||||
<MenubarPrimitive.Separator
|
||||
data-slot='menubar-separator'
|
||||
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarShortcut({
|
||||
const MenubarShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
data-slot='menubar-shortcut'
|
||||
className={cn(
|
||||
@@ -207,24 +188,22 @@ function MenubarShortcut({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarSub({
|
||||
const MenubarSub = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
|
||||
return <MenubarPrimitive.Sub data-slot='menubar-sub' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Sub>) => (
|
||||
<MenubarPrimitive.Sub data-slot='menubar-sub' {...props} />
|
||||
);
|
||||
|
||||
function MenubarSubTrigger({
|
||||
const MenubarSubTrigger = ({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<MenubarPrimitive.SubTrigger
|
||||
data-slot='menubar-sub-trigger'
|
||||
data-inset={inset}
|
||||
@@ -237,14 +216,12 @@ function MenubarSubTrigger({
|
||||
{children}
|
||||
<ChevronRightIcon className='ml-auto h-4 w-4' />
|
||||
</MenubarPrimitive.SubTrigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function MenubarSubContent({
|
||||
const MenubarSubContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) => (
|
||||
<MenubarPrimitive.SubContent
|
||||
data-slot='menubar-sub-content'
|
||||
className={cn(
|
||||
@@ -253,8 +230,7 @@ function MenubarSubContent({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Menubar,
|
||||
|
||||
@@ -3,12 +3,13 @@ import { ChevronDownIcon } from 'lucide-react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function NativeSelect({
|
||||
const NativeSelect = ({
|
||||
className,
|
||||
size = 'default',
|
||||
...props
|
||||
}: Omit<React.ComponentProps<'select'>, 'size'> & { size?: 'sm' | 'default' }) {
|
||||
return (
|
||||
}: Omit<React.ComponentProps<'select'>, 'size'> & {
|
||||
size?: 'sm' | 'default';
|
||||
}) => (
|
||||
<div
|
||||
className='group/native-select relative w-fit has-[select:disabled]:opacity-50'
|
||||
data-slot='native-select-wrapper'
|
||||
@@ -30,24 +31,21 @@ function NativeSelect({
|
||||
data-slot='native-select-icon'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NativeSelectOption({ ...props }: React.ComponentProps<'option'>) {
|
||||
return <option data-slot='native-select-option' {...props} />;
|
||||
}
|
||||
const NativeSelectOption = ({ ...props }: React.ComponentProps<'option'>) => (
|
||||
<option data-slot='native-select-option' {...props} />
|
||||
);
|
||||
|
||||
function NativeSelectOptGroup({
|
||||
const NativeSelectOptGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'optgroup'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'optgroup'>) => (
|
||||
<optgroup
|
||||
data-slot='native-select-optgroup'
|
||||
className={cn(className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { NativeSelect, NativeSelectOptGroup, NativeSelectOption };
|
||||
|
||||
@@ -5,15 +5,14 @@ import { NavigationMenu as NavigationMenuPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function NavigationMenu({
|
||||
const NavigationMenu = ({
|
||||
className,
|
||||
children,
|
||||
viewport = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
|
||||
viewport?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<NavigationMenuPrimitive.Root
|
||||
data-slot='navigation-menu'
|
||||
data-viewport={viewport}
|
||||
@@ -26,14 +25,12 @@ function NavigationMenu({
|
||||
{children}
|
||||
{viewport && <NavigationMenuViewport />}
|
||||
</NavigationMenuPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuList({
|
||||
const NavigationMenuList = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) => (
|
||||
<NavigationMenuPrimitive.List
|
||||
data-slot='navigation-menu-list'
|
||||
className={cn(
|
||||
@@ -42,32 +39,28 @@ function NavigationMenuList({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuItem({
|
||||
const NavigationMenuItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) => (
|
||||
<NavigationMenuPrimitive.Item
|
||||
data-slot='navigation-menu-item'
|
||||
className={cn('relative', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const navigationMenuTriggerStyle = cva(
|
||||
'group bg-background hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 data-[state=open]:bg-accent/50 data-[state=open]:text-accent-foreground data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50',
|
||||
);
|
||||
|
||||
function NavigationMenuTrigger({
|
||||
const NavigationMenuTrigger = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) => (
|
||||
<NavigationMenuPrimitive.Trigger
|
||||
data-slot='navigation-menu-trigger'
|
||||
className={cn(navigationMenuTriggerStyle(), 'group', className)}
|
||||
@@ -79,14 +72,12 @@ function NavigationMenuTrigger({
|
||||
aria-hidden='true'
|
||||
/>
|
||||
</NavigationMenuPrimitive.Trigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuContent({
|
||||
const NavigationMenuContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) => (
|
||||
<NavigationMenuPrimitive.Content
|
||||
data-slot='navigation-menu-content'
|
||||
className={cn(
|
||||
@@ -96,18 +87,14 @@ function NavigationMenuContent({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuViewport({
|
||||
const NavigationMenuViewport = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) => (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute top-full left-0 isolate z-50 flex justify-center',
|
||||
)}
|
||||
className={cn('absolute top-full left-0 isolate z-50 flex justify-center')}
|
||||
>
|
||||
<NavigationMenuPrimitive.Viewport
|
||||
data-slot='navigation-menu-viewport'
|
||||
@@ -118,14 +105,12 @@ function NavigationMenuViewport({
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuLink({
|
||||
const NavigationMenuLink = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) => (
|
||||
<NavigationMenuPrimitive.Link
|
||||
data-slot='navigation-menu-link'
|
||||
className={cn(
|
||||
@@ -134,14 +119,12 @@ function NavigationMenuLink({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function NavigationMenuIndicator({
|
||||
const NavigationMenuIndicator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) => (
|
||||
<NavigationMenuPrimitive.Indicator
|
||||
data-slot='navigation-menu-indicator'
|
||||
className={cn(
|
||||
@@ -152,8 +135,7 @@ function NavigationMenuIndicator({
|
||||
>
|
||||
<div className='bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md' />
|
||||
</NavigationMenuPrimitive.Indicator>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
NavigationMenu,
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
|
||||
import { Button, cn } from '@gib/ui';
|
||||
|
||||
function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
|
||||
return (
|
||||
const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
|
||||
<nav
|
||||
role='navigation'
|
||||
aria-label='pagination'
|
||||
@@ -16,38 +15,34 @@ function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
|
||||
className={cn('mx-auto flex w-full justify-center', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PaginationContent({
|
||||
const PaginationContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'ul'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'ul'>) => (
|
||||
<ul
|
||||
data-slot='pagination-content'
|
||||
className={cn('flex items-center gap-0.5', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
|
||||
return <li data-slot='pagination-item' {...props} />;
|
||||
}
|
||||
const PaginationItem = ({ ...props }: React.ComponentProps<'li'>) => (
|
||||
<li data-slot='pagination-item' {...props} />
|
||||
);
|
||||
|
||||
type PaginationLinkProps = {
|
||||
isActive?: boolean;
|
||||
} & Pick<React.ComponentProps<typeof Button>, 'size'> &
|
||||
React.ComponentProps<'a'>;
|
||||
|
||||
function PaginationLink({
|
||||
const PaginationLink = ({
|
||||
className,
|
||||
isActive,
|
||||
size = 'icon',
|
||||
...props
|
||||
}: PaginationLinkProps) {
|
||||
return (
|
||||
}: PaginationLinkProps) => (
|
||||
<Button
|
||||
asChild
|
||||
variant={isActive ? 'outline' : 'ghost'}
|
||||
@@ -61,15 +56,13 @@ function PaginationLink({
|
||||
{...props}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PaginationPrevious({
|
||||
const PaginationPrevious = ({
|
||||
className,
|
||||
text = 'Previous',
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof PaginationLink> & { text?: string }) => (
|
||||
<PaginationLink
|
||||
aria-label='Go to previous page'
|
||||
size='default'
|
||||
@@ -79,15 +72,13 @@ function PaginationPrevious({
|
||||
<ChevronLeftIcon data-icon='inline-start' className='cn-rtl-flip' />
|
||||
<span className='hidden sm:block'>{text}</span>
|
||||
</PaginationLink>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PaginationNext({
|
||||
const PaginationNext = ({
|
||||
className,
|
||||
text = 'Next',
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof PaginationLink> & { text?: string }) => (
|
||||
<PaginationLink
|
||||
aria-label='Go to next page'
|
||||
size='default'
|
||||
@@ -97,14 +88,12 @@ function PaginationNext({
|
||||
<span className='hidden sm:block'>{text}</span>
|
||||
<ChevronRightIcon data-icon='inline-end' className='cn-rtl-flip' />
|
||||
</PaginationLink>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PaginationEllipsis({
|
||||
const PaginationEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'span'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'span'>) => (
|
||||
<span
|
||||
aria-hidden
|
||||
data-slot='pagination-ellipsis'
|
||||
@@ -117,8 +106,7 @@ function PaginationEllipsis({
|
||||
<MoreHorizontalIcon />
|
||||
<span className='sr-only'>More pages</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Pagination,
|
||||
|
||||
@@ -5,25 +5,24 @@ import { Popover as PopoverPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Popover({
|
||||
const Popover = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot='popover' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) => (
|
||||
<PopoverPrimitive.Root data-slot='popover' {...props} />
|
||||
);
|
||||
|
||||
function PopoverTrigger({
|
||||
const PopoverTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot='popover-trigger' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) => (
|
||||
<PopoverPrimitive.Trigger data-slot='popover-trigger' {...props} />
|
||||
);
|
||||
|
||||
function PopoverContent({
|
||||
const PopoverContent = ({
|
||||
className,
|
||||
align = 'center',
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot='popover-content'
|
||||
@@ -36,47 +35,43 @@ function PopoverContent({
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PopoverAnchor({
|
||||
const PopoverAnchor = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot='popover-anchor' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) => (
|
||||
<PopoverPrimitive.Anchor data-slot='popover-anchor' {...props} />
|
||||
);
|
||||
|
||||
function PopoverHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const PopoverHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='popover-header'
|
||||
className={cn('flex flex-col gap-1 text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PopoverTitle({ className, ...props }: React.ComponentProps<'h2'>) {
|
||||
return (
|
||||
const PopoverTitle = ({ className, ...props }: React.ComponentProps<'h2'>) => (
|
||||
<div
|
||||
data-slot='popover-title'
|
||||
className={cn('font-medium', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function PopoverDescription({
|
||||
const PopoverDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'p'>) => (
|
||||
<p
|
||||
data-slot='popover-description'
|
||||
className={cn('text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Popover,
|
||||
|
||||
@@ -5,12 +5,11 @@ import { Progress as ProgressPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Progress({
|
||||
const Progress = ({
|
||||
className,
|
||||
value,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ProgressPrimitive.Root>) => (
|
||||
<ProgressPrimitive.Root
|
||||
data-slot='progress'
|
||||
className={cn(
|
||||
@@ -25,7 +24,6 @@ function Progress({
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Progress };
|
||||
|
||||
@@ -6,24 +6,21 @@ import { RadioGroup as RadioGroupPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function RadioGroup({
|
||||
const RadioGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) => (
|
||||
<RadioGroupPrimitive.Root
|
||||
data-slot='radio-group'
|
||||
className={cn('grid gap-3', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function RadioGroupItem({
|
||||
const RadioGroupItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) => (
|
||||
<RadioGroupPrimitive.Item
|
||||
data-slot='radio-group-item'
|
||||
className={cn(
|
||||
@@ -39,7 +36,6 @@ function RadioGroupItem({
|
||||
<CircleIcon className='fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2' />
|
||||
</RadioGroupPrimitive.Indicator>
|
||||
</RadioGroupPrimitive.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { RadioGroup, RadioGroupItem };
|
||||
|
||||
@@ -5,11 +5,10 @@ import * as ResizablePrimitive from 'react-resizable-panels';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function ResizablePanelGroup({
|
||||
const ResizablePanelGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: ResizablePrimitive.GroupProps) {
|
||||
return (
|
||||
}: ResizablePrimitive.GroupProps) => (
|
||||
<ResizablePrimitive.Group
|
||||
data-slot='resizable-panel-group'
|
||||
className={cn(
|
||||
@@ -18,21 +17,19 @@ function ResizablePanelGroup({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
|
||||
return <ResizablePrimitive.Panel data-slot='resizable-panel' {...props} />;
|
||||
}
|
||||
const ResizablePanel = ({ ...props }: ResizablePrimitive.PanelProps) => (
|
||||
<ResizablePrimitive.Panel data-slot='resizable-panel' {...props} />
|
||||
);
|
||||
|
||||
function ResizableHandle({
|
||||
const ResizableHandle = ({
|
||||
withHandle,
|
||||
className,
|
||||
...props
|
||||
}: ResizablePrimitive.SeparatorProps & {
|
||||
withHandle?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ResizablePrimitive.Separator
|
||||
data-slot='resizable-handle'
|
||||
className={cn(
|
||||
@@ -47,7 +44,6 @@ function ResizableHandle({
|
||||
</div>
|
||||
)}
|
||||
</ResizablePrimitive.Separator>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
|
||||
|
||||
@@ -5,12 +5,11 @@ import { ScrollArea as ScrollAreaPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function ScrollArea({
|
||||
const ScrollArea = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
data-slot='scroll-area'
|
||||
className={cn('relative', className)}
|
||||
@@ -25,15 +24,13 @@ function ScrollArea({
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ScrollBar({
|
||||
const ScrollBar = ({
|
||||
className,
|
||||
orientation = 'vertical',
|
||||
...props
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
data-slot='scroll-area-scrollbar'
|
||||
data-orientation={orientation}
|
||||
@@ -49,7 +46,6 @@ function ScrollBar({
|
||||
className='bg-border relative flex-1 rounded-full'
|
||||
/>
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { ScrollArea, ScrollBar };
|
||||
|
||||
@@ -6,33 +6,32 @@ import { Select as SelectPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Select({
|
||||
const Select = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot='select' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) => (
|
||||
<SelectPrimitive.Root data-slot='select' {...props} />
|
||||
);
|
||||
|
||||
function SelectGroup({
|
||||
const SelectGroup = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot='select-group' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) => (
|
||||
<SelectPrimitive.Group data-slot='select-group' {...props} />
|
||||
);
|
||||
|
||||
function SelectValue({
|
||||
const SelectValue = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot='select-value' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) => (
|
||||
<SelectPrimitive.Value data-slot='select-value' {...props} />
|
||||
);
|
||||
|
||||
function SelectTrigger({
|
||||
const SelectTrigger = ({
|
||||
className,
|
||||
size = 'default',
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: 'sm' | 'default';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot='select-trigger'
|
||||
data-size={size}
|
||||
@@ -47,17 +46,15 @@ function SelectTrigger({
|
||||
<ChevronDownIcon className='size-4 opacity-50' />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectContent({
|
||||
const SelectContent = ({
|
||||
className,
|
||||
children,
|
||||
position = 'item-aligned',
|
||||
align = 'center',
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot='select-content'
|
||||
@@ -84,28 +81,24 @@ function SelectContent({
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectLabel({
|
||||
const SelectLabel = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) => (
|
||||
<SelectPrimitive.Label
|
||||
data-slot='select-label'
|
||||
className={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectItem({
|
||||
const SelectItem = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) => (
|
||||
<SelectPrimitive.Item
|
||||
data-slot='select-item'
|
||||
className={cn(
|
||||
@@ -124,27 +117,23 @@ function SelectItem({
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectSeparator({
|
||||
const SelectSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) => (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot='select-separator'
|
||||
className={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectScrollUpButton({
|
||||
const SelectScrollUpButton = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot='select-scroll-up-button'
|
||||
className={cn(
|
||||
@@ -155,14 +144,12 @@ function SelectScrollUpButton({
|
||||
>
|
||||
<ChevronUpIcon className='size-4' />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SelectScrollDownButton({
|
||||
const SelectScrollDownButton = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot='select-scroll-down-button'
|
||||
className={cn(
|
||||
@@ -173,8 +160,7 @@ function SelectScrollDownButton({
|
||||
>
|
||||
<ChevronDownIcon className='size-4' />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Select,
|
||||
|
||||
@@ -5,13 +5,12 @@ import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Separator({
|
||||
const Separator = ({
|
||||
className,
|
||||
orientation = 'horizontal',
|
||||
decorative = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) => (
|
||||
<SeparatorPrimitive.Root
|
||||
data-slot='separator'
|
||||
decorative={decorative}
|
||||
@@ -22,7 +21,6 @@ function Separator({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Separator };
|
||||
|
||||
@@ -6,33 +6,34 @@ import { Dialog as SheetPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||
return <SheetPrimitive.Root data-slot='sheet' {...props} />;
|
||||
}
|
||||
|
||||
function SheetTrigger({
|
||||
const Sheet = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
||||
return <SheetPrimitive.Trigger data-slot='sheet-trigger' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Root>) => (
|
||||
<SheetPrimitive.Root data-slot='sheet' {...props} />
|
||||
);
|
||||
|
||||
function SheetClose({
|
||||
const SheetTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
||||
return <SheetPrimitive.Close data-slot='sheet-close' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) => (
|
||||
<SheetPrimitive.Trigger data-slot='sheet-trigger' {...props} />
|
||||
);
|
||||
|
||||
function SheetPortal({
|
||||
const SheetClose = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
||||
return <SheetPrimitive.Portal data-slot='sheet-portal' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) => (
|
||||
<SheetPrimitive.Close data-slot='sheet-close' {...props} />
|
||||
);
|
||||
|
||||
function SheetOverlay({
|
||||
const SheetPortal = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Portal>) => (
|
||||
<SheetPrimitive.Portal data-slot='sheet-portal' {...props} />
|
||||
);
|
||||
|
||||
const SheetOverlay = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) => (
|
||||
<SheetPrimitive.Overlay
|
||||
data-slot='sheet-overlay'
|
||||
className={cn(
|
||||
@@ -41,10 +42,9 @@ function SheetOverlay({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SheetContent({
|
||||
const SheetContent = ({
|
||||
className,
|
||||
children,
|
||||
side = 'right',
|
||||
@@ -53,8 +53,7 @@ function SheetContent({
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
||||
side?: 'top' | 'right' | 'bottom' | 'left';
|
||||
showCloseButton?: boolean;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
@@ -82,54 +81,45 @@ function SheetContent({
|
||||
)}
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SheetHeader = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sheet-header'
|
||||
className={cn('flex flex-col gap-1.5 p-4', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SheetFooter = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sheet-footer'
|
||||
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SheetTitle({
|
||||
const SheetTitle = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Title>) => (
|
||||
<SheetPrimitive.Title
|
||||
data-slot='sheet-title'
|
||||
className={cn('text-foreground font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SheetDescription({
|
||||
const SheetDescription = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof SheetPrimitive.Description>) => (
|
||||
<SheetPrimitive.Description
|
||||
data-slot='sheet-description'
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
|
||||
@@ -31,7 +31,7 @@ const SIDEBAR_WIDTH_MOBILE = '18rem';
|
||||
const SIDEBAR_WIDTH_ICON = '3rem';
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
|
||||
|
||||
type SidebarContextProps = {
|
||||
interface SidebarContextProps {
|
||||
state: 'expanded' | 'collapsed';
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
@@ -39,20 +39,20 @@ type SidebarContextProps = {
|
||||
setOpenMobile: (open: boolean) => void;
|
||||
isMobile: boolean;
|
||||
toggleSidebar: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const SidebarContext = React.createContext<SidebarContextProps | null>(null);
|
||||
|
||||
function useSidebar() {
|
||||
const useSidebar = () => {
|
||||
const context = React.useContext(SidebarContext);
|
||||
if (!context) {
|
||||
throw new Error('useSidebar must be used within a SidebarProvider.');
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarProvider({
|
||||
const SidebarProvider = ({
|
||||
defaultOpen = true,
|
||||
open: openProp,
|
||||
onOpenChange: setOpenProp,
|
||||
@@ -64,7 +64,7 @@ function SidebarProvider({
|
||||
defaultOpen?: boolean;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}) {
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const [openMobile, setOpenMobile] = React.useState(false);
|
||||
|
||||
@@ -148,9 +148,9 @@ function SidebarProvider({
|
||||
</TooltipProvider>
|
||||
</SidebarContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function Sidebar({
|
||||
const Sidebar = ({
|
||||
side = 'left',
|
||||
variant = 'sidebar',
|
||||
collapsible = 'offcanvas',
|
||||
@@ -161,7 +161,7 @@ function Sidebar({
|
||||
side?: 'left' | 'right';
|
||||
variant?: 'sidebar' | 'floating' | 'inset';
|
||||
collapsible?: 'offcanvas' | 'icon' | 'none';
|
||||
}) {
|
||||
}) => {
|
||||
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
||||
|
||||
if (collapsible === 'none') {
|
||||
@@ -250,13 +250,13 @@ function Sidebar({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarTrigger({
|
||||
const SidebarTrigger = ({
|
||||
className,
|
||||
onClick,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
}: React.ComponentProps<typeof Button>) => {
|
||||
const { toggleSidebar } = useSidebar();
|
||||
|
||||
return (
|
||||
@@ -276,9 +276,12 @@ function SidebarTrigger({
|
||||
<span className='sr-only'>Toggle Sidebar</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarRail({ className, ...props }: React.ComponentProps<'button'>) {
|
||||
const SidebarRail = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'button'>) => {
|
||||
const { toggleSidebar } = useSidebar();
|
||||
|
||||
return (
|
||||
@@ -301,10 +304,12 @@ function SidebarRail({ className, ...props }: React.ComponentProps<'button'>) {
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarInset({ className, ...props }: React.ComponentProps<'main'>) {
|
||||
return (
|
||||
const SidebarInset = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'main'>) => (
|
||||
<main
|
||||
data-slot='sidebar-inset'
|
||||
className={cn(
|
||||
@@ -314,61 +319,60 @@ function SidebarInset({ className, ...props }: React.ComponentProps<'main'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarInput({
|
||||
const SidebarInput = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Input>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof Input>) => (
|
||||
<Input
|
||||
data-slot='sidebar-input'
|
||||
data-sidebar='input'
|
||||
className={cn('bg-background h-8 w-full shadow-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SidebarHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-header'
|
||||
data-sidebar='header'
|
||||
className={cn('flex flex-col gap-2 p-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SidebarFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-footer'
|
||||
data-sidebar='footer'
|
||||
className={cn('flex flex-col gap-2 p-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarSeparator({
|
||||
const SidebarSeparator = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof Separator>) => (
|
||||
<Separator
|
||||
data-slot='sidebar-separator'
|
||||
data-sidebar='separator'
|
||||
className={cn('bg-sidebar-border mx-2 w-auto', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SidebarContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-content'
|
||||
data-sidebar='content'
|
||||
@@ -378,25 +382,22 @@ function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const SidebarGroup = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-group'
|
||||
data-sidebar='group'
|
||||
className={cn('relative flex w-full min-w-0 flex-col p-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarGroupLabel({
|
||||
const SidebarGroupLabel = ({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & { asChild?: boolean }) {
|
||||
}: React.ComponentProps<'div'> & { asChild?: boolean }) => {
|
||||
const Comp = asChild ? Slot.Root : 'div';
|
||||
|
||||
return (
|
||||
@@ -411,13 +412,13 @@ function SidebarGroupLabel({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarGroupAction({
|
||||
const SidebarGroupAction = ({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'button'> & { asChild?: boolean }) {
|
||||
}: React.ComponentProps<'button'> & { asChild?: boolean }) => {
|
||||
const Comp = asChild ? Slot.Root : 'button';
|
||||
|
||||
return (
|
||||
@@ -434,43 +435,40 @@ function SidebarGroupAction({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarGroupContent({
|
||||
const SidebarGroupContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-group-content'
|
||||
data-sidebar='group-content'
|
||||
className={cn('w-full text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {
|
||||
return (
|
||||
const SidebarMenu = ({ className, ...props }: React.ComponentProps<'ul'>) => (
|
||||
<ul
|
||||
data-slot='sidebar-menu'
|
||||
data-sidebar='menu'
|
||||
className={cn('flex w-full min-w-0 flex-col gap-1', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {
|
||||
return (
|
||||
const SidebarMenuItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'li'>) => (
|
||||
<li
|
||||
data-slot='sidebar-menu-item'
|
||||
data-sidebar='menu-item'
|
||||
className={cn('group/menu-item relative', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
'peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
@@ -494,7 +492,7 @@ const sidebarMenuButtonVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function SidebarMenuButton({
|
||||
const SidebarMenuButton = ({
|
||||
asChild = false,
|
||||
isActive = false,
|
||||
variant = 'default',
|
||||
@@ -506,7 +504,7 @@ function SidebarMenuButton({
|
||||
asChild?: boolean;
|
||||
isActive?: boolean;
|
||||
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
|
||||
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
||||
} & VariantProps<typeof sidebarMenuButtonVariants>) => {
|
||||
const Comp = asChild ? Slot.Root : 'button';
|
||||
const { isMobile, state } = useSidebar();
|
||||
|
||||
@@ -542,9 +540,9 @@ function SidebarMenuButton({
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarMenuAction({
|
||||
const SidebarMenuAction = ({
|
||||
className,
|
||||
asChild = false,
|
||||
showOnHover = false,
|
||||
@@ -552,7 +550,7 @@ function SidebarMenuAction({
|
||||
}: React.ComponentProps<'button'> & {
|
||||
asChild?: boolean;
|
||||
showOnHover?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
const Comp = asChild ? Slot.Root : 'button';
|
||||
|
||||
return (
|
||||
@@ -574,13 +572,12 @@ function SidebarMenuAction({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarMenuBadge({
|
||||
const SidebarMenuBadge = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='sidebar-menu-badge'
|
||||
data-sidebar='menu-badge'
|
||||
@@ -595,16 +592,15 @@ function SidebarMenuBadge({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarMenuSkeleton({
|
||||
const SidebarMenuSkeleton = ({
|
||||
className,
|
||||
showIcon = false,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
showIcon?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
// Random width between 50 to 90%.
|
||||
const width = React.useMemo(() => {
|
||||
return `${Math.floor(Math.random() * 40) + 50}%`;
|
||||
@@ -634,10 +630,12 @@ function SidebarMenuSkeleton({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarMenuSub({ className, ...props }: React.ComponentProps<'ul'>) {
|
||||
return (
|
||||
const SidebarMenuSub = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'ul'>) => (
|
||||
<ul
|
||||
data-slot='sidebar-menu-sub'
|
||||
data-sidebar='menu-sub'
|
||||
@@ -648,24 +646,21 @@ function SidebarMenuSub({ className, ...props }: React.ComponentProps<'ul'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarMenuSubItem({
|
||||
const SidebarMenuSubItem = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'li'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'li'>) => (
|
||||
<li
|
||||
data-slot='sidebar-menu-sub-item'
|
||||
data-sidebar='menu-sub-item'
|
||||
className={cn('group/menu-sub-item relative', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function SidebarMenuSubButton({
|
||||
const SidebarMenuSubButton = ({
|
||||
asChild = false,
|
||||
size = 'md',
|
||||
isActive = false,
|
||||
@@ -675,7 +670,7 @@ function SidebarMenuSubButton({
|
||||
asChild?: boolean;
|
||||
size?: 'sm' | 'md';
|
||||
isActive?: boolean;
|
||||
}) {
|
||||
}) => {
|
||||
const Comp = asChild ? Slot.Root : 'a';
|
||||
|
||||
return (
|
||||
@@ -695,7 +690,7 @@ function SidebarMenuSubButton({
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
Sidebar,
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
const Skeleton = ({ className, ...props }: React.ComponentProps<'div'>) => (
|
||||
<div
|
||||
data-slot='skeleton'
|
||||
className={cn('bg-accent animate-pulse rounded-md', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Skeleton };
|
||||
|
||||
@@ -5,14 +5,14 @@ import { Slider as SliderPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Slider({
|
||||
const Slider = ({
|
||||
className,
|
||||
defaultValue,
|
||||
value,
|
||||
min = 0,
|
||||
max = 100,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SliderPrimitive.Root>) {
|
||||
}: React.ComponentProps<typeof SliderPrimitive.Root>) => {
|
||||
const _values = React.useMemo(
|
||||
() =>
|
||||
Array.isArray(value)
|
||||
@@ -58,6 +58,6 @@ function Slider({
|
||||
))}
|
||||
</SliderPrimitive.Root>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export { Slider };
|
||||
|
||||
@@ -2,15 +2,13 @@ import { Loader2Icon } from 'lucide-react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Spinner({ className, ...props }: React.ComponentProps<'svg'>) {
|
||||
return (
|
||||
const Spinner = ({ className, ...props }: React.ComponentProps<'svg'>) => (
|
||||
<Loader2Icon
|
||||
role='status'
|
||||
aria-label='Loading'
|
||||
className={cn('size-4 animate-spin', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Spinner };
|
||||
|
||||
@@ -5,14 +5,13 @@ import { Switch as SwitchPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Switch({
|
||||
const Switch = ({
|
||||
className,
|
||||
size = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
||||
size?: 'sm' | 'default';
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<SwitchPrimitive.Root
|
||||
data-slot='switch'
|
||||
data-size={size}
|
||||
@@ -27,7 +26,6 @@ function Switch({
|
||||
className='bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0'
|
||||
/>
|
||||
</SwitchPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Switch };
|
||||
|
||||
@@ -4,43 +4,39 @@ import type * as React from 'react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Table({ className, ...props }: React.ComponentProps<'table'>) {
|
||||
return (
|
||||
<div
|
||||
data-slot='table-container'
|
||||
className='relative w-full overflow-x-auto'
|
||||
>
|
||||
const Table = ({ className, ...props }: React.ComponentProps<'table'>) => (
|
||||
<div data-slot='table-container' className='relative w-full overflow-x-auto'>
|
||||
<table
|
||||
data-slot='table'
|
||||
className={cn('w-full caption-bottom text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {
|
||||
return (
|
||||
const TableHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'thead'>) => (
|
||||
<thead
|
||||
data-slot='table-header'
|
||||
className={cn('[&_tr]:border-b', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {
|
||||
return (
|
||||
const TableBody = ({ className, ...props }: React.ComponentProps<'tbody'>) => (
|
||||
<tbody
|
||||
data-slot='table-body'
|
||||
className={cn('[&_tr:last-child]:border-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {
|
||||
return (
|
||||
const TableFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'tfoot'>) => (
|
||||
<tfoot
|
||||
data-slot='table-footer'
|
||||
className={cn(
|
||||
@@ -49,11 +45,9 @@ function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableRow({ className, ...props }: React.ComponentProps<'tr'>) {
|
||||
return (
|
||||
const TableRow = ({ className, ...props }: React.ComponentProps<'tr'>) => (
|
||||
<tr
|
||||
data-slot='table-row'
|
||||
className={cn(
|
||||
@@ -62,11 +56,9 @@ function TableRow({ className, ...props }: React.ComponentProps<'tr'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
|
||||
return (
|
||||
const TableHead = ({ className, ...props }: React.ComponentProps<'th'>) => (
|
||||
<th
|
||||
data-slot='table-head'
|
||||
className={cn(
|
||||
@@ -75,11 +67,9 @@ function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
|
||||
return (
|
||||
const TableCell = ({ className, ...props }: React.ComponentProps<'td'>) => (
|
||||
<td
|
||||
data-slot='table-cell'
|
||||
className={cn(
|
||||
@@ -88,21 +78,18 @@ function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TableCaption({
|
||||
const TableCaption = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'caption'>) {
|
||||
return (
|
||||
}: React.ComponentProps<'caption'>) => (
|
||||
<caption
|
||||
data-slot='table-caption'
|
||||
className={cn('text-muted-foreground mt-4 text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
Table,
|
||||
|
||||
@@ -7,23 +7,18 @@ import { Tabs as TabsPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Tabs({
|
||||
const Tabs = ({
|
||||
className,
|
||||
orientation = 'horizontal',
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) => (
|
||||
<TabsPrimitive.Root
|
||||
data-slot='tabs'
|
||||
data-orientation={orientation}
|
||||
className={cn(
|
||||
'group/tabs flex gap-2 data-horizontal:flex-col',
|
||||
className,
|
||||
)}
|
||||
className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const tabsListVariants = cva(
|
||||
'group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center rounded-lg p-[3px] group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none',
|
||||
@@ -40,27 +35,24 @@ const tabsListVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function TabsList({
|
||||
const TabsList = ({
|
||||
className,
|
||||
variant = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
||||
VariantProps<typeof tabsListVariants>) {
|
||||
return (
|
||||
VariantProps<typeof tabsListVariants>) => (
|
||||
<TabsPrimitive.List
|
||||
data-slot='tabs-list'
|
||||
data-variant={variant}
|
||||
className={cn(tabsListVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TabsTrigger({
|
||||
const TabsTrigger = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) => (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot='tabs-trigger'
|
||||
className={cn(
|
||||
@@ -72,20 +64,17 @@ function TabsTrigger({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function TabsContent({
|
||||
const TabsContent = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) => (
|
||||
<TabsPrimitive.Content
|
||||
data-slot='tabs-content'
|
||||
className={cn('flex-1 text-sm outline-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
||||
|
||||
@@ -2,8 +2,10 @@ import * as React from 'react';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
||||
return (
|
||||
const Textarea = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'textarea'>) => (
|
||||
<textarea
|
||||
data-slot='textarea'
|
||||
className={cn(
|
||||
@@ -12,7 +14,6 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Textarea };
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
'use client';
|
||||
|
||||
import type { ComponentProps } from 'react';
|
||||
import { ThemeProvider as NextThemesProvider, useTheme } from 'next-themes';
|
||||
import { Moon, Sun } from 'lucide-react';
|
||||
import { Button, cn } from '@gib/ui';
|
||||
import { ThemeProvider as NextThemesProvider, useTheme } from 'next-themes';
|
||||
|
||||
import { Button, cn } from '@gib/ui';
|
||||
|
||||
const ThemeProvider = ({
|
||||
children,
|
||||
...props
|
||||
}: ComponentProps<typeof NextThemesProvider>) => {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
};
|
||||
|
||||
interface ThemeToggleProps {
|
||||
@@ -22,23 +22,21 @@ const ThemeToggle = ({ size = 1, buttonProps }: ThemeToggleProps) => {
|
||||
const { setTheme, resolvedTheme } = useTheme();
|
||||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
variant='outline'
|
||||
size='icon'
|
||||
onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
|
||||
{...buttonProps}
|
||||
className={cn('cursor-pointer', buttonProps?.className)}
|
||||
>
|
||||
<Sun
|
||||
style={{ height: `${size}rem`, width: `${size}rem` }}
|
||||
className='scale-100 rotate-0 transition-all
|
||||
dark:scale-0 dark:-rotate-90'
|
||||
className='scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90'
|
||||
/>
|
||||
<Moon
|
||||
style={{ height: `${size}rem`, width: `${size}rem` }}
|
||||
className='absolute scale-0 rotate-90 transition-all
|
||||
dark:scale-100 dark:rotate-0'
|
||||
className='absolute scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0'
|
||||
/>
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
<span className='sr-only'>Toggle theme</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ const ToggleGroupContext = React.createContext<
|
||||
spacing: 0,
|
||||
});
|
||||
|
||||
function ToggleGroup({
|
||||
const ToggleGroup = ({
|
||||
className,
|
||||
variant,
|
||||
size,
|
||||
@@ -26,8 +26,7 @@ function ToggleGroup({
|
||||
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants> & {
|
||||
spacing?: number;
|
||||
}) {
|
||||
return (
|
||||
}) => (
|
||||
<ToggleGroupPrimitive.Root
|
||||
data-slot='toggle-group'
|
||||
data-variant={variant}
|
||||
@@ -44,17 +43,16 @@ function ToggleGroup({
|
||||
{children}
|
||||
</ToggleGroupContext.Provider>
|
||||
</ToggleGroupPrimitive.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function ToggleGroupItem({
|
||||
const ToggleGroupItem = ({
|
||||
className,
|
||||
children,
|
||||
variant,
|
||||
size,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
|
||||
VariantProps<typeof toggleVariants>) {
|
||||
VariantProps<typeof toggleVariants>) => {
|
||||
const context = React.useContext(ToggleGroupContext);
|
||||
|
||||
return (
|
||||
@@ -77,6 +75,6 @@ function ToggleGroupItem({
|
||||
{children}
|
||||
</ToggleGroupPrimitive.Item>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export { ToggleGroup, ToggleGroupItem };
|
||||
|
||||
@@ -29,20 +29,18 @@ const toggleVariants = cva(
|
||||
},
|
||||
);
|
||||
|
||||
function Toggle({
|
||||
const Toggle = ({
|
||||
className,
|
||||
variant,
|
||||
size,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TogglePrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants>) {
|
||||
return (
|
||||
VariantProps<typeof toggleVariants>) => (
|
||||
<TogglePrimitive.Root
|
||||
data-slot='toggle'
|
||||
className={cn(toggleVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Toggle, toggleVariants };
|
||||
|
||||
@@ -5,38 +5,35 @@ import { Tooltip as TooltipPrimitive } from 'radix-ui';
|
||||
|
||||
import { cn } from '@gib/ui';
|
||||
|
||||
function TooltipProvider({
|
||||
const TooltipProvider = ({
|
||||
delayDuration = 0,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) => (
|
||||
<TooltipPrimitive.Provider
|
||||
data-slot='tooltip-provider'
|
||||
delayDuration={delayDuration}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function Tooltip({
|
||||
const Tooltip = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||||
return <TooltipPrimitive.Root data-slot='tooltip' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) => (
|
||||
<TooltipPrimitive.Root data-slot='tooltip' {...props} />
|
||||
);
|
||||
|
||||
function TooltipTrigger({
|
||||
const TooltipTrigger = ({
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||||
return <TooltipPrimitive.Trigger data-slot='tooltip-trigger' {...props} />;
|
||||
}
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) => (
|
||||
<TooltipPrimitive.Trigger data-slot='tooltip-trigger' {...props} />
|
||||
);
|
||||
|
||||
function TooltipContent({
|
||||
const TooltipContent = ({
|
||||
className,
|
||||
sideOffset = 0,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||||
return (
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) => (
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
data-slot='tooltip-content'
|
||||
@@ -51,7 +48,6 @@ function TooltipContent({
|
||||
<TooltipPrimitive.Arrow className='bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]' />
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
|
||||
@@ -1 +1 @@
|
||||
[["1","2","3","4","5"],{"key":"6","value":"7"},{"key":"8","value":"9"},{"key":"10","value":"11"},{"key":"12","value":"13"},{"key":"14","value":"15"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/package.json",{"size":979,"mtime":1768166330000,"hash":"16","data":"17"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/nextjs.ts",{"size":440,"mtime":1768155639000,"hash":"18","data":"19"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/react.ts",{"size":592,"mtime":1768155639000,"hash":"20","data":"21"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/base.ts",{"size":2508,"mtime":1768320541000,"hash":"22","data":"23"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"24","data":"25"},"a5326aca75246da261fd2e354257b45a",{"hashOfOptions":"26"},"25c52c46972131dcc296288599ff108d",{"hashOfOptions":"27"},"2292935ede6baf909f6a0c61486e15da",{"hashOfOptions":"28"},"6a779439826cf31b5561a21273d134a9",{"hashOfOptions":"29"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"30"},"1249441784","4234667885","3945480854","3486090744","681484145"]
|
||||
[["1","2","3","4","5","6"],{"key":"7","value":"8"},{"key":"9","value":"10"},{"key":"11","value":"12"},{"key":"13","value":"14"},{"key":"15","value":"16"},{"key":"17","value":"18"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/base.ts",{"size":2963,"mtime":1774544629518,"hash":"19","data":"20"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/nextjs.ts",{"size":440,"mtime":1768155639000,"hash":"21","data":"22"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/.cache/.prettiercache",{"size":1278,"mtime":1774544484642},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/package.json",{"size":1033,"mtime":1774544387169,"hash":"23","data":"24"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/react.ts",{"size":592,"mtime":1768155639000,"hash":"25","data":"26"},"/home/gib/Documents/Code/convex-monorepo/tools/eslint/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"27","data":"28"},"6a779439826cf31b5561a21273d134a9",{"hashOfOptions":"29"},"25c52c46972131dcc296288599ff108d",{"hashOfOptions":"30"},"a5326aca75246da261fd2e354257b45a",{"hashOfOptions":"31"},"2292935ede6baf909f6a0c61486e15da",{"hashOfOptions":"32"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"33"},"1686097143","2347540204","302976953","3406150487","1582266352"]
|
||||
@@ -2,10 +2,15 @@ import * as path from 'node:path';
|
||||
import { includeIgnoreFile } from '@eslint/compat';
|
||||
import eslint from '@eslint/js';
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
// eslint-plugin-prefer-arrow-functions doesn't ship flat config types — cast needed
|
||||
import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
|
||||
import turboPlugin from 'eslint-plugin-turbo';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const preferArrowPlugin = preferArrowFunctions as any;
|
||||
|
||||
/**
|
||||
* All packages that leverage t3-env should use this rule
|
||||
*/
|
||||
@@ -45,6 +50,7 @@ export const baseConfig = defineConfig(
|
||||
plugins: {
|
||||
import: importPlugin,
|
||||
turbo: turboPlugin,
|
||||
'prefer-arrow-functions': preferArrowPlugin,
|
||||
},
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
@@ -58,10 +64,6 @@ export const baseConfig = defineConfig(
|
||||
'warn',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
||||
],
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'warn',
|
||||
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
|
||||
],
|
||||
'@typescript-eslint/no-misused-promises': [
|
||||
2,
|
||||
{ checksVoidReturn: { attributes: false } },
|
||||
@@ -73,7 +75,17 @@ export const baseConfig = defineConfig(
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||
'@typescript-eslint/consistent-type-definitions': 'off',
|
||||
'prefer-arrow-functions/prefer-arrow-functions': [
|
||||
'warn',
|
||||
{
|
||||
allowNamedFunctions: false,
|
||||
classPropertiesAllowed: false,
|
||||
disallowPrototype: false,
|
||||
returnStyle: 'unchanged',
|
||||
singleReturnOnly: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@next/eslint-plugin-next": "^16.0.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prefer-arrow-functions": "^3.9.1",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-turbo": "^2.5.8",
|
||||
|
||||
@@ -1 +1 @@
|
||||
[["1","2","3"],{"key":"4","value":"5"},{"key":"6","value":"7"},{"key":"8","value":"9"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"10","data":"11"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/package.json",{"size":607,"mtime":1766222924000,"hash":"12","data":"13"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/index.js",{"size":1194,"mtime":1768372320442,"hash":"14","data":"15"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"16"},"11b634ce56ac720ac9a2860d77fbd2cc",{"hashOfOptions":"17"},"ecbaa91166a940dfcec8117059f52402",{"hashOfOptions":"18"},"67859251","550572982","1674623979"]
|
||||
[["1","2","3","4"],{"key":"5","value":"6"},{"key":"7","value":"8"},{"key":"9","value":"10"},{"key":"11","value":"12"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/.cache/.prettiercache",{"size":832,"mtime":1774544484482},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/index.js",{"size":1194,"mtime":1768372320442,"hash":"13","data":"14"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/package.json",{"size":607,"mtime":1774032385569,"hash":"15","data":"16"},"/home/gib/Documents/Code/convex-monorepo/tools/prettier/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"17","data":"18"},"ecbaa91166a940dfcec8117059f52402",{"hashOfOptions":"19"},"11b634ce56ac720ac9a2860d77fbd2cc",{"hashOfOptions":"20"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"21"},"1828250668","802511607","4250532914"]
|
||||
1
tools/tailwind/.cache/.eslintcache
Normal file
1
tools/tailwind/.cache/.eslintcache
Normal file
@@ -0,0 +1 @@
|
||||
[{"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/postcss-config.js":"1"},{"size":70,"mtime":1768155639000,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","suppressedMessages":"6","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"z9il2c","/home/gib/Documents/Code/convex-monorepo/tools/tailwind/postcss-config.js",[],[]]
|
||||
@@ -1 +1 @@
|
||||
[["1","2","3","4","5"],{"key":"6","value":"7"},{"key":"8","value":"9"},{"key":"10","value":"11"},{"key":"12","value":"13"},{"key":"14","value":"15"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/package.json",{"size":851,"mtime":1766222924000,"hash":"16","data":"17"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/postcss-config.js",{"size":70,"mtime":1768155639000,"hash":"18","data":"19"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/eslint.config.ts",{"size":143,"mtime":1768155639000,"hash":"20","data":"21"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/theme.css",{"size":7273,"mtime":1768320378000,"hash":"22","data":"23"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"24","data":"25"},"0d22e47f57739db9de04c6f8420d6fb5",{"hashOfOptions":"26"},"9a944fbda06979be39571bd9bd00b0d9",{"hashOfOptions":"27"},"b8fec960cb32340eea62ca1485093e68",{"hashOfOptions":"28"},"e40c2569ef375a9c828c80c0f9ce1bf2",{"hashOfOptions":"29"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"30"},"34296497","1053475182","4101125807","919761249","2958815992"]
|
||||
[["1","2","3","4","5","6","7"],{"key":"8","value":"9"},{"key":"10","value":"11"},{"key":"12","value":"13"},{"key":"14","value":"15"},{"key":"16","value":"17"},{"key":"18","value":"19"},{"key":"20","value":"21"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/.cache/.eslintcache",{"size":396,"mtime":1774544641255},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/.cache/.prettiercache",{"size":1450,"mtime":1774544484418},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/package.json",{"size":851,"mtime":1774032407411,"hash":"22","data":"23"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/tsconfig.json",{"size":94,"mtime":1766222924000,"hash":"24","data":"25"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/eslint.config.ts",{"size":143,"mtime":1768155639000,"hash":"26","data":"27"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/theme.css",{"size":7273,"mtime":1768320378000,"hash":"28","data":"29"},"/home/gib/Documents/Code/convex-monorepo/tools/tailwind/postcss-config.js",{"size":70,"mtime":1768155639000,"hash":"30","data":"31"},"0d22e47f57739db9de04c6f8420d6fb5",{"hashOfOptions":"32"},"b3c77d33a30318d89c9c2cafcbe00bbe",{"hashOfOptions":"33"},"b8fec960cb32340eea62ca1485093e68",{"hashOfOptions":"34"},"e40c2569ef375a9c828c80c0f9ce1bf2",{"hashOfOptions":"35"},"9a944fbda06979be39571bd9bd00b0d9",{"hashOfOptions":"36"},"286235122","2846522359","1288936688","2683656544","1694755693"]
|
||||
@@ -15,13 +15,13 @@
|
||||
"CONVEX_SELF_HOSTED_ADMIN_KEY",
|
||||
"CONVEX_SITE_URL",
|
||||
"USESEND_API_KEY",
|
||||
"USESEND_URL",
|
||||
"USESEND_FROM_EMAIL",
|
||||
"AUTH_AUTHENTIK_ID",
|
||||
"AUTH_AUTHENTIK_SECRET",
|
||||
"AUTH_AUTHENTIK_ISSUER"
|
||||
],
|
||||
"globalPassThroughEnv": [
|
||||
"NODE_ENV"
|
||||
],
|
||||
"globalPassThroughEnv": ["NODE_ENV"],
|
||||
"ui": "tui",
|
||||
"tasks": {
|
||||
"topo": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import type { PlopTypes } from "@turbo/gen";
|
||||
import { execSync } from 'node:child_process';
|
||||
import type { PlopTypes } from '@turbo/gen';
|
||||
|
||||
interface PackageJson {
|
||||
name: string;
|
||||
@@ -9,58 +9,58 @@ interface PackageJson {
|
||||
}
|
||||
|
||||
export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
||||
plop.setGenerator("init", {
|
||||
description: "Generate a new package for the Acme Monorepo",
|
||||
plop.setGenerator('init', {
|
||||
description: 'Generate a new package for the Monorepo',
|
||||
prompts: [
|
||||
{
|
||||
type: "input",
|
||||
name: "name",
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message:
|
||||
"What is the name of the package? (You can skip the `@gib/` prefix)",
|
||||
'What is the name of the package? (You can skip the `@gib/` prefix)',
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "deps",
|
||||
type: 'input',
|
||||
name: 'deps',
|
||||
message:
|
||||
"Enter a space separated list of dependencies you would like to install",
|
||||
'Enter a space separated list of dependencies you would like to install',
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
(answers) => {
|
||||
if ("name" in answers && typeof answers.name === "string") {
|
||||
if (answers.name.startsWith("@gib/")) {
|
||||
answers.name = answers.name.replace("@gib/", "");
|
||||
if ('name' in answers && typeof answers.name === 'string') {
|
||||
if (answers.name.startsWith('@gib/')) {
|
||||
answers.name = answers.name.replace('@gib/', '');
|
||||
}
|
||||
}
|
||||
return "Config sanitized";
|
||||
return 'Config sanitized';
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "packages/{{ name }}/eslint.config.ts",
|
||||
templateFile: "templates/eslint.config.ts.hbs",
|
||||
type: 'add',
|
||||
path: 'packages/{{ name }}/eslint.config.ts',
|
||||
templateFile: 'templates/eslint.config.ts.hbs',
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "packages/{{ name }}/package.json",
|
||||
templateFile: "templates/package.json.hbs",
|
||||
type: 'add',
|
||||
path: 'packages/{{ name }}/package.json',
|
||||
templateFile: 'templates/package.json.hbs',
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "packages/{{ name }}/tsconfig.json",
|
||||
templateFile: "templates/tsconfig.json.hbs",
|
||||
type: 'add',
|
||||
path: 'packages/{{ name }}/tsconfig.json',
|
||||
templateFile: 'templates/tsconfig.json.hbs',
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "packages/{{ name }}/src/index.ts",
|
||||
type: 'add',
|
||||
path: 'packages/{{ name }}/src/index.ts',
|
||||
template: "export const name = '{{ name }}';",
|
||||
},
|
||||
{
|
||||
type: "modify",
|
||||
path: "packages/{{ name }}/package.json",
|
||||
type: 'modify',
|
||||
path: 'packages/{{ name }}/package.json',
|
||||
async transform(content, answers) {
|
||||
if ("deps" in answers && typeof answers.deps === "string") {
|
||||
if ('deps' in answers && typeof answers.deps === 'string') {
|
||||
const pkg = JSON.parse(content) as PackageJson;
|
||||
for (const dep of answers.deps.split(" ").filter(Boolean)) {
|
||||
for (const dep of answers.deps.split(' ').filter(Boolean)) {
|
||||
const version = await fetch(
|
||||
`https://registry.npmjs.org/-/package/${dep}/dist-tags`,
|
||||
)
|
||||
@@ -78,17 +78,15 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
||||
/**
|
||||
* Install deps and format everything
|
||||
*/
|
||||
if ("name" in answers && typeof answers.name === "string") {
|
||||
// execSync("pnpm dlx sherif@latest --fix", {
|
||||
// stdio: "inherit",
|
||||
// });
|
||||
execSync("pnpm i", { stdio: "inherit" });
|
||||
if ('name' in answers && typeof answers.name === 'string') {
|
||||
execSync('bun install', { stdio: 'inherit' });
|
||||
execSync(
|
||||
`pnpm prettier --write packages/${answers.name}/** --list-different`,
|
||||
`bun prettier --write packages/${answers.name}/** --list-different`,
|
||||
{ stdio: 'inherit' },
|
||||
);
|
||||
return "Package scaffolded";
|
||||
return 'Package scaffolded';
|
||||
}
|
||||
return "Package not scaffolded";
|
||||
return 'Package not scaffolded';
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user