format all files
This commit is contained in:
parent
8500dd770b
commit
afdf7d22cf
|
|
@ -6,7 +6,7 @@ alwaysApply: true
|
|||
|
||||
# Project Context
|
||||
|
||||
Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Biome's lightning-fast formatter and linter.
|
||||
Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Prettier's formatter.
|
||||
|
||||
## Key Principles
|
||||
|
||||
|
|
|
|||
|
|
@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
|
|||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
title: '[BUG] '
|
||||
title: "[BUG] "
|
||||
labels: bug
|
||||
body:
|
||||
- type: input
|
||||
|
|
@ -15,7 +15,7 @@ body:
|
|||
id: Browser
|
||||
attributes:
|
||||
label: Browser
|
||||
description: Please enter the browser on which you encountered the bug.
|
||||
description: Please enter the browser on which you encountered the bug.
|
||||
placeholder: e.g. Chrome 137, Firefox 137, Safari 17
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -67,4 +67,4 @@ body:
|
|||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
required: false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name: Feature request
|
||||
description: Suggest an idea for OpenCut
|
||||
title: '[FEATURE] '
|
||||
title: "[FEATURE] "
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
|
|
@ -39,4 +39,4 @@ body:
|
|||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
required: false
|
||||
|
|
|
|||
|
|
@ -25,4 +25,4 @@ Please do not report security vulnerabilities through public GitHub issues.
|
|||
- We will provide a detailed response within 5 business days
|
||||
- We will keep you updated on our progress
|
||||
|
||||
Thank you for helping keep OpenCut secure!
|
||||
Thank you for helping keep OpenCut secure!
|
||||
|
|
|
|||
|
|
@ -3,21 +3,25 @@
|
|||
Thanks for using OpenCut! If you need help, here are your options:
|
||||
|
||||
## Documentation
|
||||
|
||||
- Check our [README](../README.md) for basic setup instructions
|
||||
- Review the [Contributing Guidelines](CONTRIBUTING.md) for development setup
|
||||
|
||||
## Issues
|
||||
|
||||
- **Bug reports**: Use the bug report template
|
||||
- **Feature requests**: Use the feature request template
|
||||
- **Questions**: Use GitHub Discussions for general questions
|
||||
|
||||
## Community
|
||||
|
||||
- Join our discussions on GitHub
|
||||
- Follow the [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
|
||||
## Response Times
|
||||
|
||||
- Issues are typically triaged within 2-3 business days
|
||||
- Feature requests may take longer to evaluate
|
||||
- Security issues are handled with priority
|
||||
|
||||
We appreciate your patience and contributions to making OpenCut better!
|
||||
We appreciate your patience and contributions to making OpenCut better!
|
||||
|
|
|
|||
|
|
@ -3,15 +3,18 @@ applyTo: "**/*.{ts,tsx,js,jsx}"
|
|||
---
|
||||
|
||||
# Project Context
|
||||
|
||||
Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Biome's lightning-fast formatter and linter.
|
||||
|
||||
## Key Principles
|
||||
|
||||
- Zero configuration required
|
||||
- Subsecond performance
|
||||
- Maximum type safety
|
||||
- AI-friendly code generation
|
||||
|
||||
## Before Writing Code
|
||||
|
||||
1. Analyze existing patterns in the codebase
|
||||
2. Consider edge cases and error scenarios
|
||||
3. Follow the rules below strictly
|
||||
|
|
@ -20,6 +23,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
## Rules
|
||||
|
||||
### Accessibility (a11y)
|
||||
|
||||
- Don't use `accessKey` attribute on any HTML element.
|
||||
- Don't set `aria-hidden="true"` on focusable elements.
|
||||
- Don't add ARIA roles, states, and properties to elements that don't support them.
|
||||
|
|
@ -56,6 +60,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Use correct ISO language/country codes for the `lang` attribute.
|
||||
|
||||
### Code Complexity and Quality
|
||||
|
||||
- Don't use consecutive spaces in regular expression literals.
|
||||
- Don't use the `arguments` object.
|
||||
- Don't use primitive type aliases or misleading types.
|
||||
|
|
@ -111,6 +116,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Don't use literal numbers that lose precision.
|
||||
|
||||
### React and JSX Best Practices
|
||||
|
||||
- Don't use the return value of React.render.
|
||||
- Make sure all dependencies are correctly specified in React hooks.
|
||||
- Make sure all React hooks are called from the top level of component functions.
|
||||
|
|
@ -129,6 +135,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Watch out for possible "wrong" semicolons inside JSX elements.
|
||||
|
||||
### Correctness and Safety
|
||||
|
||||
- Don't assign a value to itself.
|
||||
- Don't return a value from a setter.
|
||||
- Don't compare expressions that modify string case with non-compliant values.
|
||||
|
|
@ -153,7 +160,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Don't use bitwise operators.
|
||||
- Don't use expressions where the operation doesn't change the value.
|
||||
- Make sure Promise-like statements are handled appropriately.
|
||||
- Don't use __dirname and __filename in the global scope.
|
||||
- Don't use **dirname and **filename in the global scope.
|
||||
- Prevent import cycles.
|
||||
- Don't use configured elements.
|
||||
- Don't hardcode sensitive data like API keys and tokens.
|
||||
|
|
@ -184,6 +191,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Don't use `target="_blank"` without `rel="noopener"`.
|
||||
|
||||
### TypeScript Best Practices
|
||||
|
||||
- Don't use TypeScript enums.
|
||||
- Don't export imported variables.
|
||||
- Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions.
|
||||
|
|
@ -208,6 +216,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
|
||||
|
||||
### Style and Consistency
|
||||
|
||||
- Don't use global `eval()`.
|
||||
- Don't use callbacks in asynchronous tests and hooks.
|
||||
- Don't use negation in `if` statements that have `else` clauses.
|
||||
|
|
@ -295,30 +304,34 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c
|
|||
- Make sure to use the "use strict" directive in script files.
|
||||
|
||||
### Next.js Specific Rules
|
||||
|
||||
- Don't use `<img>` elements in Next.js projects.
|
||||
- Don't use `<head>` elements in Next.js projects.
|
||||
- Don't import next/document outside of pages/_document.jsx in Next.js projects.
|
||||
- Don't use the next/head module in pages/_document.js on Next.js projects.
|
||||
- Don't import next/document outside of pages/\_document.jsx in Next.js projects.
|
||||
- Don't use the next/head module in pages/\_document.js on Next.js projects.
|
||||
|
||||
### Testing Best Practices
|
||||
|
||||
- Don't use export or module.exports in test files.
|
||||
- Don't use focused tests.
|
||||
- Make sure the assertion function, like expect, is placed inside an it() function call.
|
||||
- Don't use disabled tests.
|
||||
|
||||
## Common Tasks
|
||||
|
||||
- `npx ultracite init` - Initialize Ultracite in your project
|
||||
- `npx ultracite format` - Format and fix code automatically
|
||||
- `npx ultracite lint` - Check for issues without fixing
|
||||
|
||||
## Example: Error Handling
|
||||
|
||||
```typescript
|
||||
// ✅ Good: Comprehensive error handling
|
||||
try {
|
||||
const result = await fetchData();
|
||||
return { success: true, data: result };
|
||||
} catch (error) {
|
||||
console.error('API call failed:', error);
|
||||
console.error("API call failed:", error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
|
|
@ -328,4 +341,4 @@ try {
|
|||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ Please describe the tests that you ran to verify your changes. Provide instructi
|
|||
- [ ] Test B
|
||||
|
||||
**Test Configuration**:
|
||||
* Node version:
|
||||
* Browser (if applicable):
|
||||
* Operating System:
|
||||
|
||||
- Node version:
|
||||
- Browser (if applicable):
|
||||
- Operating System:
|
||||
|
||||
## Screenshots (if applicable)
|
||||
|
||||
|
|
@ -46,4 +47,4 @@ Add screenshots to help explain your changes.
|
|||
|
||||
## Additional context
|
||||
|
||||
Add any other context about the pull request here.
|
||||
Add any other context about the pull request here.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.git
|
||||
apps/web/.next/
|
||||
apps/web/public/
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[javascript][typescript][javascriptreact][typescriptreact][json][jsonc][css][graphql]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"emmet.showExpandedAbbreviation": "never",
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
}
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[javascript][typescript][javascriptreact][typescriptreact][json][jsonc][css][graphql]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"emmet.showExpandedAbbreviation": "never",
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
24
AGENTS.md
24
AGENTS.md
|
|
@ -32,16 +32,17 @@ import { useEditor } from '@/hooks/use-editor';
|
|||
function MyComponent() {
|
||||
const editor = useEditor();
|
||||
const tracks = editor.timeline.getTracks();
|
||||
|
||||
|
||||
// Call methods
|
||||
editor.timeline.addTrack({ type: 'media' });
|
||||
|
||||
|
||||
// Display data (auto re-renders on changes)
|
||||
return <div>{tracks.length} tracks</div>;
|
||||
}
|
||||
```
|
||||
|
||||
The hook:
|
||||
|
||||
- Returns the singleton instance
|
||||
- Subscribes to all manager changes
|
||||
- Automatically re-renders when state changes
|
||||
|
|
@ -52,10 +53,10 @@ The hook:
|
|||
|
||||
```typescript
|
||||
// In utilities, event handlers, or non-React code
|
||||
import { EditorCore } from '@/core';
|
||||
import { EditorCore } from "@/core";
|
||||
|
||||
const editor = EditorCore.getInstance();
|
||||
await editor.export({ format: 'mp4', quality: 'high' });
|
||||
await editor.export({ format: "mp4", quality: "high" });
|
||||
```
|
||||
|
||||
## Actions System
|
||||
|
|
@ -65,6 +66,7 @@ Actions are the trigger layer for user-initiated operations. The single source o
|
|||
**To add a new action:**
|
||||
|
||||
1. Add it to `ACTIONS` in `@/lib/actions/definitions.ts`:
|
||||
|
||||
```typescript
|
||||
export const ACTIONS = {
|
||||
"my-action": {
|
||||
|
|
@ -73,14 +75,19 @@ export const ACTIONS = {
|
|||
defaultShortcuts: ["ctrl+m"],
|
||||
},
|
||||
// ...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
2. Add handler in `@/hooks/use-editor-actions.ts`:
|
||||
|
||||
```typescript
|
||||
useActionHandler("my-action", () => {
|
||||
// implementation
|
||||
}, undefined);
|
||||
useActionHandler(
|
||||
"my-action",
|
||||
() => {
|
||||
// implementation
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
```
|
||||
|
||||
**In components, use `invokeAction()` for user-triggered operations:**
|
||||
|
|
@ -102,6 +109,7 @@ Direct `editor.xxx()` calls are for internal use (commands, tests, complex multi
|
|||
Commands handle undo/redo. They live in `@/lib/commands/` organized by domain (timeline, media, scene).
|
||||
|
||||
Each command extends `Command` from `@/lib/commands/base-command` and implements:
|
||||
|
||||
- `execute()` - saves current state, then does the mutation
|
||||
- `undo()` - restores the saved state
|
||||
|
||||
|
|
|
|||
6
TODO.md
6
TODO.md
|
|
@ -1,6 +0,0 @@
|
|||
[x] Delete all stores we can
|
||||
[x] Create commands for each action
|
||||
[x] Finish timeline store
|
||||
[x] Migrate final timeline store to manager
|
||||
[x] Delete timeline store
|
||||
[ ] Update usage of all stores to use the new managers
|
||||
|
|
@ -96,7 +96,7 @@ function buildSortParameter({ query, sort }: { query?: string; sort: string }) {
|
|||
function applyEffectsFilters({
|
||||
params,
|
||||
min_rating,
|
||||
commercial_only
|
||||
commercial_only,
|
||||
}: {
|
||||
params: URLSearchParams;
|
||||
min_rating: number;
|
||||
|
|
@ -108,17 +108,19 @@ function applyEffectsFilters({
|
|||
if (commercial_only) {
|
||||
params.append(
|
||||
"filter",
|
||||
'license:("Attribution" OR "Creative Commons 0" OR "Attribution Noncommercial" OR "Attribution Commercial")'
|
||||
'license:("Attribution" OR "Creative Commons 0" OR "Attribution Noncommercial" OR "Attribution Commercial")',
|
||||
);
|
||||
}
|
||||
|
||||
params.append(
|
||||
"filter",
|
||||
"tag:sound-effect OR tag:sfx OR tag:foley OR tag:ambient OR tag:nature OR tag:mechanical OR tag:electronic OR tag:impact OR tag:whoosh OR tag:explosion"
|
||||
"tag:sound-effect OR tag:sfx OR tag:foley OR tag:ambient OR tag:nature OR tag:mechanical OR tag:electronic OR tag:impact OR tag:whoosh OR tag:explosion",
|
||||
);
|
||||
}
|
||||
|
||||
function transformFreesoundResult(result: z.infer<typeof freesoundResultSchema>) {
|
||||
function transformFreesoundResult(
|
||||
result: z.infer<typeof freesoundResultSchema>,
|
||||
) {
|
||||
return {
|
||||
id: result.id,
|
||||
name: result.name,
|
||||
|
|
@ -169,7 +171,7 @@ export async function GET(request: NextRequest) {
|
|||
error: "Invalid parameters",
|
||||
details: validationResult.error.flatten().fieldErrors,
|
||||
},
|
||||
{ status: 400 }
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +192,7 @@ export async function GET(request: NextRequest) {
|
|||
message:
|
||||
"Song search functionality is coming soon. Try searching for sound effects instead.",
|
||||
},
|
||||
{ status: 501 }
|
||||
{ status: 501 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +222,7 @@ export async function GET(request: NextRequest) {
|
|||
console.error("Freesound API error:", response.status, errorText);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to search sounds" },
|
||||
{ status: response.status }
|
||||
{ status: response.status },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -230,11 +232,11 @@ export async function GET(request: NextRequest) {
|
|||
if (!freesoundValidation.success) {
|
||||
console.error(
|
||||
"Invalid Freesound API response:",
|
||||
freesoundValidation.error
|
||||
freesoundValidation.error,
|
||||
);
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid response from Freesound API" },
|
||||
{ status: 502 }
|
||||
{ status: 502 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -259,11 +261,11 @@ export async function GET(request: NextRequest) {
|
|||
if (!responseValidation.success) {
|
||||
console.error(
|
||||
"Invalid API response structure:",
|
||||
responseValidation.error
|
||||
responseValidation.error,
|
||||
);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal response formatting error" },
|
||||
{ status: 500 }
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -272,7 +274,7 @@ export async function GET(request: NextRequest) {
|
|||
console.error("Error searching sounds:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export function BasePage({
|
|||
<Header />
|
||||
<main
|
||||
className={cn(
|
||||
"container relative mx-auto flex flex-col gap-12 px-6 pb-24 pt-12 md:pt-24",
|
||||
"relative container mx-auto flex flex-col gap-12 px-6 pt-12 pb-24 md:pt-24",
|
||||
maxWidthClass,
|
||||
mainClassName,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default async function BlogPage() {
|
|||
function BlogPostItem({ post }: { post: Post }) {
|
||||
return (
|
||||
<Link href={`/blog/${post.slug}`}>
|
||||
<div className="h-auto w-full opacity-100 transition-opacity hover:opacity-75 flex items-center justify-between py-6">
|
||||
<div className="flex h-auto w-full items-center justify-between py-6 opacity-100 transition-opacity hover:opacity-75">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="text-xl font-semibold">{post.title}</h2>
|
||||
<p className="text-muted-foreground">{post.description}</p>
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ export default function ProjectsPage() {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
<main className="mx-auto max-w-6xl px-6 pb-6 pt-6">
|
||||
<main className="mx-auto max-w-6xl px-6 pt-6 pb-6">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
<div className="flex flex-col gap-3">
|
||||
<h1 className="text-2xl font-bold tracking-tight md:text-3xl">
|
||||
|
|
@ -419,16 +419,18 @@ function ProjectCard({
|
|||
|
||||
const cardContent = (
|
||||
<Card
|
||||
className={`bg-background overflow-hidden border-none p-0 transition-all ${isSelectionMode && isSelected ? "ring-primary ring-2" : ""
|
||||
}`}
|
||||
className={`bg-background overflow-hidden border-none p-0 transition-all ${
|
||||
isSelectionMode && isSelected ? "ring-primary ring-2" : ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`bg-muted relative aspect-square transition-opacity ${isDropdownOpen ? "opacity-65" : "opacity-100 group-hover:opacity-65"
|
||||
}`}
|
||||
className={`bg-muted relative aspect-square transition-opacity ${
|
||||
isDropdownOpen ? "opacity-65" : "opacity-100 group-hover:opacity-65"
|
||||
}`}
|
||||
>
|
||||
{isSelectionMode && (
|
||||
<div className="absolute left-3 top-3 z-10">
|
||||
<div className="bg-background/80 backdrop-blur-xs flex size-5 items-center justify-center rounded-full border">
|
||||
<div className="absolute top-3 left-3 z-10">
|
||||
<div className="bg-background/80 flex size-5 items-center justify-center rounded-full border backdrop-blur-xs">
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onCheckedChange={(checked) =>
|
||||
|
|
@ -462,7 +464,7 @@ function ProjectCard({
|
|||
|
||||
<CardContent className="flex flex-col gap-1 px-0 pt-5">
|
||||
<div className="flex items-start justify-between">
|
||||
<h3 className="group-hover:text-foreground/90 line-clamp-2 text-sm font-medium leading-snug transition-colors">
|
||||
<h3 className="group-hover:text-foreground/90 line-clamp-2 text-sm leading-snug font-medium transition-colors">
|
||||
{project.name}
|
||||
</h3>
|
||||
{!isSelectionMode && (
|
||||
|
|
@ -475,10 +477,11 @@ function ProjectCard({
|
|||
aria-label="project options"
|
||||
variant="text"
|
||||
size="sm"
|
||||
className={`ml-2 size-6 shrink-0 p-0 transition-all ${isDropdownOpen
|
||||
? "opacity-100"
|
||||
: "opacity-0 group-hover:opacity-100"
|
||||
}`}
|
||||
className={`ml-2 size-6 shrink-0 p-0 transition-all ${
|
||||
isDropdownOpen
|
||||
? "opacity-100"
|
||||
: "opacity-0 group-hover:opacity-100"
|
||||
}`}
|
||||
onClick={(event) => event.preventDefault()}
|
||||
>
|
||||
<MoreHorizontal aria-hidden="true" />
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ function RoadmapItem({ item, index }: { item: RoadmapItem; index: number }) {
|
|||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center gap-2 text-lg font-medium">
|
||||
<span className="select-none leading-normal">{index + 1}</span>
|
||||
<span className="leading-normal select-none">{index + 1}</span>
|
||||
<h3>{item.title}</h3>
|
||||
<StatusBadge status={item.status} className="ml-1" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ export async function GET() {
|
|||
language: "en",
|
||||
image: `${SITE_INFO.openGraphImage}`,
|
||||
favicon: `${SITE_INFO.favicon}`,
|
||||
copyright: `All rights reserved ${new Date().getFullYear()}, ${SITE_INFO.title
|
||||
}`,
|
||||
copyright: `All rights reserved ${new Date().getFullYear()}, ${
|
||||
SITE_INFO.title
|
||||
}`,
|
||||
});
|
||||
|
||||
for (const post of posts) {
|
||||
|
|
|
|||
|
|
@ -27,15 +27,15 @@ export function MediaDragOverlay({
|
|||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col items-center justify-center gap-4 h-full text-center rounded-lg bg-foreground/5 hover:bg-foreground/10 transition-all duration-200 p-8"
|
||||
className="bg-foreground/5 hover:bg-foreground/10 flex h-full flex-col items-center justify-center gap-4 rounded-lg p-8 text-center transition-all duration-200"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
<Upload className="h-10 w-10 text-foreground" />
|
||||
<Upload className="text-foreground h-10 w-10" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-muted-foreground max-w-sm">
|
||||
<p className="text-muted-foreground max-w-sm text-xs">
|
||||
{isProcessing
|
||||
? `Processing your files (${progress}%)`
|
||||
: "Drag and drop videos, photos, and audio files here"}
|
||||
|
|
@ -44,7 +44,7 @@ export function MediaDragOverlay({
|
|||
|
||||
{isProcessing && (
|
||||
<div className="w-full max-w-xs">
|
||||
<div className="w-full bg-muted/50 rounded-full h-2">
|
||||
<div className="bg-muted/50 h-2 w-full rounded-full">
|
||||
<div
|
||||
className="bg-primary h-2 rounded-full transition-all duration-300"
|
||||
style={{ width: `${progress}%` }}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export function TabBar() {
|
|||
variant="sidebar"
|
||||
sideOffset={8}
|
||||
>
|
||||
<div className="text-foreground text-sm font-medium leading-none">
|
||||
<div className="text-foreground text-sm leading-none font-medium">
|
||||
{tab.label}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
|
|
@ -99,7 +99,7 @@ function FadeOverlay({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute left-0 right-0 h-6 transition-opacity duration-200",
|
||||
"pointer-events-none absolute right-0 left-0 h-6 transition-opacity duration-200",
|
||||
direction === "top" && show
|
||||
? "from-panel top-0 bg-gradient-to-b to-transparent"
|
||||
: "from-panel bottom-0 bg-gradient-to-t to-transparent",
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ export function Captions() {
|
|||
|
||||
const handleProgress = (progress: TranscriptionProgress) => {
|
||||
if (progress.status === "loading-model") {
|
||||
setProcessingStep(
|
||||
`Loading model ${Math.round(progress.progress)}%`,
|
||||
);
|
||||
setProcessingStep(`Loading model ${Math.round(progress.progress)}%`);
|
||||
} else if (progress.status === "transcribing") {
|
||||
setProcessingStep("Transcribing...");
|
||||
}
|
||||
|
|
@ -48,7 +46,8 @@ export function Captions() {
|
|||
|
||||
const result = await transcriptionService.transcribe({
|
||||
audioData: samples,
|
||||
language: selectedLanguage === "auto" ? "auto" : selectedLanguage.toLowerCase(),
|
||||
language:
|
||||
selectedLanguage === "auto" ? "auto" : selectedLanguage.toLowerCase(),
|
||||
onProgress: handleProgress,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ export function MediaView() {
|
|||
const mediaFiles = editor.media.getAssets();
|
||||
const activeProject = editor.project.getActive();
|
||||
|
||||
const { mediaViewMode, setMediaViewMode, highlightMediaId, clearHighlight } = useAssetsPanelStore();
|
||||
const { mediaViewMode, setMediaViewMode, highlightMediaId, clearHighlight } =
|
||||
useAssetsPanelStore();
|
||||
const { highlightedId, registerElement } = useRevealItem(
|
||||
highlightMediaId,
|
||||
clearHighlight,
|
||||
|
|
@ -509,7 +510,7 @@ function MediaDurationBadge({ duration }: { duration?: number }) {
|
|||
if (!duration) return null;
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-1 right-1 rounded bg-black/70 px-1 text-xs text-white">
|
||||
<div className="absolute right-1 bottom-1 rounded bg-black/70 px-1 text-xs text-white">
|
||||
{formatDuration({ duration })}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -551,7 +552,6 @@ function MediaTypePlaceholder({
|
|||
}
|
||||
|
||||
function MediaPreview({ item }: { item: MediaAsset }) {
|
||||
|
||||
if (item.type === "image") {
|
||||
return (
|
||||
<div className="flex size-full items-center justify-center">
|
||||
|
|
@ -604,13 +604,7 @@ function MediaPreview({ item }: { item: MediaAsset }) {
|
|||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MediaTypePlaceholder
|
||||
icon={Image}
|
||||
label="Unknown"
|
||||
variant="muted"
|
||||
/>
|
||||
);
|
||||
return <MediaTypePlaceholder icon={Image} label="Unknown" variant="muted" />;
|
||||
}
|
||||
|
||||
function SortMenuItem({
|
||||
|
|
|
|||
|
|
@ -82,11 +82,7 @@ function ProjectSettingsTabs() {
|
|||
);
|
||||
}
|
||||
|
||||
function getCurrentCanvasSize({
|
||||
activeProject,
|
||||
}: {
|
||||
activeProject: TProject;
|
||||
}) {
|
||||
function getCurrentCanvasSize({ activeProject }: { activeProject: TProject }) {
|
||||
const { canvasSize } = activeProject.settings;
|
||||
|
||||
return {
|
||||
|
|
@ -155,9 +151,7 @@ function ProjectInfoView() {
|
|||
<div className="flex flex-col gap-4">
|
||||
<PropertyItem direction="column">
|
||||
<PropertyItemLabel>Name</PropertyItemLabel>
|
||||
<PropertyItemValue>
|
||||
{activeProject.metadata.name}
|
||||
</PropertyItemValue>
|
||||
<PropertyItemValue>{activeProject.metadata.name}</PropertyItemValue>
|
||||
</PropertyItem>
|
||||
|
||||
<PropertyItem direction="column">
|
||||
|
|
@ -237,7 +231,7 @@ const BlurPreview = memo(
|
|||
style={{ filter: `blur(${blur.value}px)` }}
|
||||
loading="eager"
|
||||
/>
|
||||
<div className="absolute bottom-1 left-1 right-1 text-center">
|
||||
<div className="absolute right-1 bottom-1 left-1 text-center">
|
||||
<span className="rounded bg-black/50 px-1 text-xs text-white">
|
||||
{blur.label}
|
||||
</span>
|
||||
|
|
@ -270,18 +264,18 @@ const BackgroundPreviews = memo(
|
|||
className={cn(
|
||||
"border-foreground/15 hover:border-primary aspect-square w-full cursor-pointer rounded-sm border",
|
||||
isColorBackground &&
|
||||
bg === currentBackgroundColor &&
|
||||
"border-primary border-2",
|
||||
bg === currentBackgroundColor &&
|
||||
"border-primary border-2",
|
||||
)}
|
||||
style={
|
||||
useBackgroundColor
|
||||
? { backgroundColor: bg }
|
||||
: {
|
||||
background: bg,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
}
|
||||
background: bg,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
}
|
||||
}
|
||||
onClick={() => handleColorSelect({ bg })}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import { useInfiniteScroll } from "@/hooks/use-infinite-scroll";
|
|||
|
||||
export function SoundsView() {
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
<Tabs defaultValue="sound-effects" className="flex flex-col h-full">
|
||||
<div className="flex h-full flex-col">
|
||||
<Tabs defaultValue="sound-effects" className="flex h-full flex-col">
|
||||
<div className="px-3 pt-4 pb-0">
|
||||
<TabsList>
|
||||
<TabsTrigger value="sound-effects">Sound effects</TabsTrigger>
|
||||
|
|
@ -48,19 +48,19 @@ export function SoundsView() {
|
|||
<Separator className="my-4" />
|
||||
<TabsContent
|
||||
value="sound-effects"
|
||||
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0"
|
||||
className="mt-0 flex min-h-0 flex-1 flex-col p-5 pt-0"
|
||||
>
|
||||
<SoundEffectsView />
|
||||
</TabsContent>
|
||||
<TabsContent
|
||||
value="saved"
|
||||
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0"
|
||||
className="mt-0 flex min-h-0 flex-1 flex-col p-5 pt-0"
|
||||
>
|
||||
<SavedSoundsView />
|
||||
</TabsContent>
|
||||
<TabsContent
|
||||
value="songs"
|
||||
className="p-5 pt-0 mt-0 flex-1 flex flex-col min-h-0"
|
||||
className="mt-0 flex min-h-0 flex-1 flex-col p-5 pt-0"
|
||||
>
|
||||
<SongsView />
|
||||
</TabsContent>
|
||||
|
|
@ -97,12 +97,15 @@ function SoundEffectsView() {
|
|||
loadMore,
|
||||
hasNextPage,
|
||||
isLoadingMore,
|
||||
} = useSoundSearch({ query: searchQuery, commercialOnly: showCommercialOnly });
|
||||
} = useSoundSearch({
|
||||
query: searchQuery,
|
||||
commercialOnly: showCommercialOnly,
|
||||
});
|
||||
|
||||
// Audio playback state
|
||||
const [playingId, setPlayingId] = useState<number | null>(null);
|
||||
const [audioElement, setAudioElement] = useState<HTMLAudioElement | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
|
||||
const { scrollAreaRef, handleScroll } = useInfiniteScroll({
|
||||
|
|
@ -125,7 +128,7 @@ function SoundEffectsView() {
|
|||
}
|
||||
|
||||
const response = await fetch(
|
||||
"/api/sounds/search?page_size=50&sort=downloads"
|
||||
"/api/sounds/search?page_size=50&sort=downloads",
|
||||
);
|
||||
|
||||
if (!ignore) {
|
||||
|
|
@ -146,7 +149,9 @@ function SoundEffectsView() {
|
|||
console.error("Failed to fetch top sounds:", error);
|
||||
setError({
|
||||
error:
|
||||
error instanceof Error ? error.message : "Failed to load sounds",
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to load sounds",
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -221,7 +226,7 @@ function SoundEffectsView() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5 mt-1 h-full">
|
||||
<div className="mt-1 flex h-full flex-col gap-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<Input
|
||||
placeholder="Search sound effects"
|
||||
|
|
@ -249,7 +254,7 @@ function SoundEffectsView() {
|
|||
>
|
||||
Show only commercially licensed
|
||||
</DropdownMenuCheckboxItem>
|
||||
<div className="px-2 py-1.5 text-xs text-muted-foreground">
|
||||
<div className="text-muted-foreground px-2 py-1.5 text-xs">
|
||||
{showCommercialOnly
|
||||
? "Only showing sounds licensed for commercial use"
|
||||
: "Showing all sounds regardless of license"}
|
||||
|
|
@ -260,7 +265,7 @@ function SoundEffectsView() {
|
|||
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<ScrollArea
|
||||
className="flex-1 h-full"
|
||||
className="h-full flex-1"
|
||||
ref={scrollAreaRef}
|
||||
onScrollCapture={handleScrollWithPosition}
|
||||
>
|
||||
|
|
@ -289,7 +294,7 @@ function SoundEffectsView() {
|
|||
</div>
|
||||
)}
|
||||
{isLoadingMore && (
|
||||
<div className="text-muted-foreground text-sm text-center py-4">
|
||||
<div className="text-muted-foreground py-4 text-center text-sm">
|
||||
Loading more sounds...
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -314,7 +319,7 @@ function SavedSoundsView() {
|
|||
// Audio playback state
|
||||
const [playingId, setPlayingId] = useState<number | null>(null);
|
||||
const [audioElement, setAudioElement] = useState<HTMLAudioElement | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
|
||||
// Clear confirmation dialog state
|
||||
|
|
@ -378,7 +383,7 @@ function SavedSoundsView() {
|
|||
|
||||
if (isLoadingSavedSounds) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="text-muted-foreground text-sm">
|
||||
Loading saved sounds...
|
||||
</div>
|
||||
|
|
@ -388,7 +393,7 @@ function SavedSoundsView() {
|
|||
|
||||
if (savedSoundsError) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="text-destructive text-sm">
|
||||
Error: {savedSoundsError}
|
||||
</div>
|
||||
|
|
@ -398,14 +403,14 @@ function SavedSoundsView() {
|
|||
|
||||
if (savedSounds.length === 0) {
|
||||
return (
|
||||
<div className="bg-panel h-full p-4 flex flex-col items-center justify-center gap-3">
|
||||
<div className="bg-panel flex h-full flex-col items-center justify-center gap-3 p-4">
|
||||
<HeartIcon
|
||||
className="w-10 h-10 text-muted-foreground"
|
||||
className="text-muted-foreground h-10 w-10"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
<div className="flex flex-col gap-2 text-center">
|
||||
<p className="text-lg font-medium">No saved sounds</p>
|
||||
<p className="text-sm text-muted-foreground text-balance">
|
||||
<p className="text-muted-foreground text-sm text-balance">
|
||||
Click the heart icon on any sound to save it here
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -414,9 +419,9 @@ function SavedSoundsView() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5 mt-1 h-full">
|
||||
<div className="mt-1 flex h-full flex-col gap-5">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{savedSounds.length} saved{" "}
|
||||
{savedSounds.length === 1 ? "sound" : "sounds"}
|
||||
</p>
|
||||
|
|
@ -425,7 +430,7 @@ function SavedSoundsView() {
|
|||
<Button
|
||||
variant="text"
|
||||
size="sm"
|
||||
className="h-auto text-muted-foreground hover:text-destructive !opacity-100"
|
||||
className="text-muted-foreground hover:text-destructive h-auto !opacity-100"
|
||||
>
|
||||
Clear all
|
||||
</Button>
|
||||
|
|
@ -457,7 +462,7 @@ function SavedSoundsView() {
|
|||
</div>
|
||||
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<ScrollArea className="flex-1 h-full">
|
||||
<ScrollArea className="h-full flex-1">
|
||||
<div className="flex flex-col gap-4">
|
||||
{savedSounds.map((sound) => (
|
||||
<AudioItem
|
||||
|
|
@ -515,11 +520,11 @@ function AudioItem({
|
|||
|
||||
return (
|
||||
<div
|
||||
className="group flex items-center gap-3 opacity-100 hover:opacity-75 transition-opacity cursor-pointer"
|
||||
className="group flex cursor-pointer items-center gap-3 opacity-100 transition-opacity hover:opacity-75"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="relative w-12 h-12 bg-accent rounded-md flex items-center justify-center overflow-hidden shrink-0">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/20 to-transparent" />
|
||||
<div className="bg-accent relative flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-md">
|
||||
<div className="from-primary/20 absolute inset-0 bg-gradient-to-br to-transparent" />
|
||||
{isPlaying ? (
|
||||
<PauseIcon className="size-5" />
|
||||
) : (
|
||||
|
|
@ -527,9 +532,9 @@ function AudioItem({
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-w-0 overflow-hidden">
|
||||
<p className="font-medium truncate text-sm">{sound.name}</p>
|
||||
<span className="text-xs text-muted-foreground truncate block">
|
||||
<div className="min-w-0 flex-1 overflow-hidden">
|
||||
<p className="truncate text-sm font-medium">{sound.name}</p>
|
||||
<span className="text-muted-foreground block truncate text-xs">
|
||||
{sound.username}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -538,7 +543,7 @@ function AudioItem({
|
|||
<Button
|
||||
variant="text"
|
||||
size="icon"
|
||||
className="text-muted-foreground hover:text-foreground !opacity-100 w-auto"
|
||||
className="text-muted-foreground hover:text-foreground w-auto !opacity-100"
|
||||
onClick={handleAddToTimeline}
|
||||
title="Add to timeline"
|
||||
>
|
||||
|
|
@ -547,10 +552,11 @@ function AudioItem({
|
|||
<Button
|
||||
variant="text"
|
||||
size="icon"
|
||||
className={`hover:text-foreground !opacity-100 w-auto ${isSaved
|
||||
? "text-red-500 hover:text-red-600"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
className={`hover:text-foreground w-auto !opacity-100 ${
|
||||
isSaved
|
||||
? "text-red-500 hover:text-red-600"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
onClick={handleSaveClick}
|
||||
title={isSaved ? "Remove from saved" : "Save sound"}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -108,10 +108,7 @@ function StickerGrid({
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="grid gap-2"
|
||||
style={gridStyle}
|
||||
>
|
||||
<div className="grid gap-2" style={gridStyle}>
|
||||
{icons.map((iconName) => (
|
||||
<StickerItem
|
||||
key={iconName}
|
||||
|
|
@ -160,7 +157,7 @@ function EmptyView({ message }: { message: string }) {
|
|||
/>
|
||||
<div className="flex flex-col gap-2 text-center">
|
||||
<p className="text-lg font-medium">No stickers found</p>
|
||||
<p className="text-muted-foreground text-balance text-sm">{message}</p>
|
||||
<p className="text-muted-foreground text-sm text-balance">{message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -211,17 +208,17 @@ function StickersContentView({ category }: { category: StickerCategory }) {
|
|||
const collection = collections[c.prefix];
|
||||
return collection
|
||||
? {
|
||||
prefix: c.prefix,
|
||||
name: c.name,
|
||||
total: collection.total,
|
||||
}
|
||||
prefix: c.prefix,
|
||||
name: c.name,
|
||||
total: collection.total,
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.filter(Boolean) as Array<{
|
||||
prefix: string;
|
||||
name: string;
|
||||
total: number;
|
||||
}>;
|
||||
prefix: string;
|
||||
name: string;
|
||||
total: number;
|
||||
}>;
|
||||
}, [collections, category]);
|
||||
|
||||
const { scrollAreaRef, handleScroll } = useInfiniteScroll({
|
||||
|
|
@ -485,7 +482,7 @@ function CollectionItem({ title, subtitle, onClick }: CollectionItemProps) {
|
|||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-auto justify-between py-2 rounded-md"
|
||||
className="h-auto justify-between rounded-md py-2"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="text-left">
|
||||
|
|
@ -523,7 +520,7 @@ function StickerItem({
|
|||
|
||||
const preview = imageError ? (
|
||||
<div className="flex h-full w-full items-center justify-center p-2">
|
||||
<span className="text-muted-foreground break-all text-center text-xs">
|
||||
<span className="text-muted-foreground text-center text-xs break-all">
|
||||
{displayName}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -534,10 +531,10 @@ function StickerItem({
|
|||
hostIndex === 0
|
||||
? getIconSvgUrl(iconName, { width: 64, height: 64 })
|
||||
: buildIconSvgUrl(
|
||||
ICONIFY_HOSTS[Math.min(hostIndex, ICONIFY_HOSTS.length - 1)],
|
||||
iconName,
|
||||
{ width: 64, height: 64 },
|
||||
)
|
||||
ICONIFY_HOSTS[Math.min(hostIndex, ICONIFY_HOSTS.length - 1)],
|
||||
iconName,
|
||||
{ width: 64, height: 64 },
|
||||
)
|
||||
}
|
||||
alt={displayName}
|
||||
width={64}
|
||||
|
|
@ -546,9 +543,9 @@ function StickerItem({
|
|||
style={
|
||||
capSize
|
||||
? {
|
||||
maxWidth: "var(--sticker-max, 160px)",
|
||||
maxHeight: "var(--sticker-max, 160px)",
|
||||
}
|
||||
maxWidth: "var(--sticker-max, 160px)",
|
||||
maxHeight: "var(--sticker-max, 160px)",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onError={() => {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export function TextView() {
|
|||
name="Default text"
|
||||
preview={
|
||||
<div className="bg-panel-accent flex size-full items-center justify-center rounded">
|
||||
<span className="select-none text-xs">Default text</span>
|
||||
<span className="text-xs select-none">Default text</span>
|
||||
</div>
|
||||
}
|
||||
dragData={{
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ export function ExportButton() {
|
|||
}
|
||||
}}
|
||||
>
|
||||
<div className="bg-linear-270 relative flex items-center gap-1.5 rounded-[0.8rem] from-[#2567EC] to-[#37B6F7] px-4 py-1 shadow-[0_1px_3px_0px_rgba(0,0,0,0.65)]">
|
||||
<div className="relative flex items-center gap-1.5 rounded-[0.8rem] bg-linear-270 from-[#2567EC] to-[#37B6F7] px-4 py-1 shadow-[0_1px_3px_0px_rgba(0,0,0,0.65)]">
|
||||
<TransitionUpIcon className="z-50" />
|
||||
<span className="z-50 text-[0.875rem]">Export</span>
|
||||
<div className="bg-linear-to-t absolute left-0 top-0 z-10 flex h-full w-full items-center justify-center rounded-[0.8rem] from-white/0 to-white/50">
|
||||
<div className="bg-linear-270 absolute top-[0.08rem] z-50 h-[calc(100%-2px)] w-[calc(100%-2px)] rounded-[0.8rem] from-[#2567EC] to-[#37B6F7]"></div>
|
||||
<div className="absolute top-0 left-0 z-10 flex h-full w-full items-center justify-center rounded-[0.8rem] bg-linear-to-t from-white/0 to-white/50">
|
||||
<div className="absolute top-[0.08rem] z-50 h-[calc(100%-2px)] w-[calc(100%-2px)] rounded-[0.8rem] bg-linear-270 from-[#2567EC] to-[#37B6F7]"></div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
|
@ -263,7 +263,7 @@ function ExportPopover({
|
|||
<Button
|
||||
variant="outline"
|
||||
className="w-full rounded-md"
|
||||
onClick={() => { }}
|
||||
onClick={() => {}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import Image from "next/image";
|
|||
|
||||
function TikTokGuide() {
|
||||
return (
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<Image
|
||||
src="/platform-guides/tiktok-blueprint.png"
|
||||
alt="TikTok layout guide"
|
||||
className="absolute inset-0 w-full h-full object-contain"
|
||||
className="absolute inset-0 h-full w-full object-contain"
|
||||
draggable={false}
|
||||
fill
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function PanelBaseView({
|
|||
ref,
|
||||
}: PanelBaseViewProps) {
|
||||
return (
|
||||
<div className={cn("h-full flex flex-col", className)} ref={ref}>
|
||||
<div className={cn("flex h-full flex-col", className)} ref={ref}>
|
||||
{!tabs || tabs.length === 0 ? (
|
||||
<ViewContent className={className}>{children}</ViewContent>
|
||||
) : (
|
||||
|
|
@ -50,15 +50,15 @@ export function PanelBaseView({
|
|||
defaultValue={defaultTab}
|
||||
value={value}
|
||||
onValueChange={onValueChange}
|
||||
className="flex flex-col h-full"
|
||||
className="flex h-full flex-col"
|
||||
>
|
||||
<div className="sticky top-0 z-10 bg-panel">
|
||||
<div className="bg-panel sticky top-0 z-10">
|
||||
<div className="px-3 pt-3 pb-0">
|
||||
<TabsList>
|
||||
{tabs.map((tab) => (
|
||||
<TabsTrigger key={tab.value} value={tab.value}>
|
||||
{tab.icon ? (
|
||||
<span className="inline-flex items-center mr-1">
|
||||
<span className="mr-1 inline-flex items-center">
|
||||
{tab.icon}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -73,7 +73,7 @@ export function PanelBaseView({
|
|||
<TabsContent
|
||||
key={tab.value}
|
||||
value={tab.value}
|
||||
className="mt-0 flex-1 flex flex-col min-h-0"
|
||||
className="mt-0 flex min-h-0 flex-1 flex-col"
|
||||
>
|
||||
<ViewContent className={className}>{tab.content}</ViewContent>
|
||||
</TabsContent>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { useEditor } from "@/hooks/use-editor";
|
|||
import { useElementSelection } from "@/hooks/timeline/element/use-element-selection";
|
||||
|
||||
export function PropertiesPanel() {
|
||||
const editor = useEditor();
|
||||
const editor = useEditor();
|
||||
const { selectedElements } = useElementSelection();
|
||||
|
||||
const elementsWithTracks = editor.timeline.getElementsWithTracks({
|
||||
|
|
@ -57,7 +57,7 @@ function EmptyView() {
|
|||
/>
|
||||
<div className="flex flex-col gap-2 text-center">
|
||||
<p className="text-lg font-medium">It’s empty here</p>
|
||||
<p className="text-muted-foreground text-balance text-sm">
|
||||
<p className="text-muted-foreground text-sm text-balance">
|
||||
Click an element on the timeline to edit its properties
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export function PropertyItem({
|
|||
direction === "row"
|
||||
? "items-center justify-between gap-6"
|
||||
: "flex-col gap-1.5",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
|
@ -36,7 +36,7 @@ export function PropertyItemLabel({
|
|||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<label className={cn("text-xs text-muted-foreground", className)}>
|
||||
<label className={cn("text-muted-foreground text-xs", className)}>
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
|
|
@ -72,7 +72,7 @@ export function PropertyGroup({
|
|||
return (
|
||||
<PropertyItem direction="column" className={cn("gap-3", className)}>
|
||||
<div
|
||||
className="flex items-center gap-1.5 cursor-pointer"
|
||||
className="flex cursor-pointer items-center gap-1.5"
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
>
|
||||
<PropertyItemLabel className={cn("cursor-pointer", titleClassName)}>
|
||||
|
|
|
|||
|
|
@ -118,7 +118,11 @@ export function TextProperties({
|
|||
});
|
||||
};
|
||||
|
||||
const handleTransparentToggle = ({ isTransparent }: { isTransparent: boolean }) => {
|
||||
const handleTransparentToggle = ({
|
||||
isTransparent,
|
||||
}: {
|
||||
isTransparent: boolean;
|
||||
}) => {
|
||||
const newColor = isTransparent ? "transparent" : lastSelectedColor.current;
|
||||
editor.timeline.updateTextElement({
|
||||
trackId,
|
||||
|
|
@ -146,7 +150,7 @@ export function TextProperties({
|
|||
<Textarea
|
||||
placeholder="Name"
|
||||
defaultValue={element.content}
|
||||
className="min-h-18 bg-panel-accent resize-none"
|
||||
className="bg-panel-accent min-h-18 resize-none"
|
||||
onChange={(e) =>
|
||||
editor.timeline.updateTextElement({
|
||||
trackId,
|
||||
|
|
@ -287,9 +291,11 @@ export function TextProperties({
|
|||
value={fontSizeInput}
|
||||
min={8}
|
||||
max={300}
|
||||
onChange={(e) => handleFontSizeChange({ value: e.target.value })}
|
||||
onChange={(e) =>
|
||||
handleFontSizeChange({ value: e.target.value })
|
||||
}
|
||||
onBlur={handleFontSizeBlur}
|
||||
className="bg-panel-accent h-7 w-12 rounded-sm px-2 text-center !text-xs [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
className="bg-panel-accent h-7 w-12 [appearance:textfield] rounded-sm px-2 text-center !text-xs [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
/>
|
||||
</div>
|
||||
</PropertyItemValue>
|
||||
|
|
@ -299,8 +305,7 @@ export function TextProperties({
|
|||
<PropertyItemValue>
|
||||
<ColorPicker
|
||||
value={uppercase({
|
||||
string:
|
||||
(element.color || "FFFFFF").replace("#", "")
|
||||
string: (element.color || "FFFFFF").replace("#", ""),
|
||||
})}
|
||||
onChange={(color) => {
|
||||
editor.timeline.updateTextElement({
|
||||
|
|
@ -337,9 +342,11 @@ export function TextProperties({
|
|||
value={opacityInput}
|
||||
min={0}
|
||||
max={100}
|
||||
onChange={(e) => handleOpacityChange({ value: e.target.value })}
|
||||
onChange={(e) =>
|
||||
handleOpacityChange({ value: e.target.value })
|
||||
}
|
||||
onBlur={handleOpacityBlur}
|
||||
className="bg-panel-accent h-7 w-12 rounded-sm text-center !text-xs [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
className="bg-panel-accent h-7 w-12 [appearance:textfield] rounded-sm text-center !text-xs [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
/>
|
||||
</div>
|
||||
</PropertyItemValue>
|
||||
|
|
@ -353,12 +360,11 @@ export function TextProperties({
|
|||
string:
|
||||
element.backgroundColor === "transparent"
|
||||
? lastSelectedColor.current.replace("#", "")
|
||||
: (element.backgroundColor).replace(
|
||||
"#",
|
||||
"",
|
||||
),
|
||||
: element.backgroundColor.replace("#", ""),
|
||||
})}
|
||||
onChange={(color) => handleColorChange({ color: `#${color}` })}
|
||||
onChange={(color) =>
|
||||
handleColorChange({ color: `#${color}` })
|
||||
}
|
||||
containerRef={containerRef}
|
||||
className={
|
||||
element.backgroundColor === "transparent"
|
||||
|
|
@ -374,7 +380,8 @@ export function TextProperties({
|
|||
size="icon"
|
||||
onClick={() =>
|
||||
handleTransparentToggle({
|
||||
isTransparent: element.backgroundColor !== "transparent",
|
||||
isTransparent:
|
||||
element.backgroundColor !== "transparent",
|
||||
})
|
||||
}
|
||||
className="bg-panel-accent size-9 overflow-hidden rounded-full p-0"
|
||||
|
|
@ -383,7 +390,7 @@ export function TextProperties({
|
|||
className={cn(
|
||||
"text-foreground",
|
||||
element.backgroundColor === "transparent" &&
|
||||
"text-primary",
|
||||
"text-primary",
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -147,11 +147,11 @@ export function ScenesView({ children }: { children: React.ReactNode }) {
|
|||
className={cn(
|
||||
"w-full justify-between font-normal",
|
||||
currentScene?.id === scene.id &&
|
||||
!isSelectMode &&
|
||||
"border-primary !text-primary",
|
||||
!isSelectMode &&
|
||||
"border-primary !text-primary",
|
||||
isSelectMode &&
|
||||
selectedScenes.has(scene.id) &&
|
||||
"bg-accent border-foreground/30",
|
||||
selectedScenes.has(scene.id) &&
|
||||
"bg-accent border-foreground/30",
|
||||
)}
|
||||
onClick={() => handleSceneSwitch(scene.id)}
|
||||
>
|
||||
|
|
@ -159,8 +159,8 @@ export function ScenesView({ children }: { children: React.ReactNode }) {
|
|||
<div className="flex items-center gap-2">
|
||||
{((isSelectMode && selectedScenes.has(scene.id)) ||
|
||||
(!isSelectMode && currentScene?.id === scene.id)) && (
|
||||
<Check className="h-4 w-4" />
|
||||
)}
|
||||
<Check className="h-4 w-4" />
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -79,8 +79,7 @@ export function AudioWaveform({
|
|||
} else {
|
||||
try {
|
||||
newWaveSurfer.destroy();
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -121,8 +120,7 @@ export function AudioWaveform({
|
|||
requestAnimationFrame(() => {
|
||||
try {
|
||||
wsToDestroy.destroy();
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
if (mounted) {
|
||||
initWaveSurfer();
|
||||
}
|
||||
|
|
@ -142,8 +140,7 @@ export function AudioWaveform({
|
|||
requestAnimationFrame(() => {
|
||||
try {
|
||||
wsToDestroy.destroy();
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -155,7 +152,7 @@ export function AudioWaveform({
|
|||
className={`flex items-center justify-center ${className}`}
|
||||
style={{ height }}
|
||||
>
|
||||
<span className="text-xs text-foreground/60">Audio unavailable</span>
|
||||
<span className="text-foreground/60 text-xs">Audio unavailable</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -164,7 +161,7 @@ export function AudioWaveform({
|
|||
<div className={`relative ${className}`}>
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<span className="text-xs text-foreground/60">Loading...</span>
|
||||
<span className="text-foreground/60 text-xs">Loading...</span>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export function TimelineBookmark({
|
|||
}}
|
||||
onClick={(event) => handleBookmarkClick({ event })}
|
||||
>
|
||||
<div className="text-primary absolute left-[-5px] top-[-1px]">
|
||||
<div className="text-primary absolute top-[-1px] left-[-5px]">
|
||||
<Bookmark className="fill-primary size-3" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function DragLine({ dropTarget, tracks, isVisible }: DragLineProps) {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="bg-primary pointer-events-none absolute left-0 right-0 z-50 h-0.5"
|
||||
className="bg-primary pointer-events-none absolute right-0 left-0 z-50 h-0.5"
|
||||
style={{ top: `${y}px` }}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
"use client";
|
||||
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Eye, EyeOff, VolumeOff, Volume2, LucideIcon, EyeIcon, Trash2 } from "lucide-react";
|
||||
import {
|
||||
Eye,
|
||||
EyeOff,
|
||||
VolumeOff,
|
||||
Volume2,
|
||||
LucideIcon,
|
||||
EyeIcon,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
|
|
@ -249,7 +257,7 @@ export function Timeline() {
|
|||
{tracks.length > 0 && (
|
||||
<div
|
||||
ref={trackLabelsRef}
|
||||
className="z-100 bg-panel w-28 shrink-0 overflow-y-auto border-r"
|
||||
className="bg-panel z-100 w-28 shrink-0 overflow-y-auto border-r"
|
||||
style={{ paddingTop: TIMELINE_CONSTANTS.PADDING_TOP }}
|
||||
>
|
||||
<ScrollArea className="h-full w-full" ref={trackLabelsScrollRef}>
|
||||
|
|
@ -378,7 +386,7 @@ export function Timeline() {
|
|||
<ContextMenu key={track.id}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<div
|
||||
className="absolute left-0 right-0"
|
||||
className="absolute right-0 left-0"
|
||||
style={{
|
||||
top: `${getCumulativeHeightBefore({
|
||||
tracks,
|
||||
|
|
@ -412,7 +420,6 @@ export function Timeline() {
|
|||
>
|
||||
<Volume2 />
|
||||
<span>
|
||||
|
||||
{canTracktHaveAudio(track) && track.muted
|
||||
? "Unmute track"
|
||||
: "Mute track"}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function SnapIndicator({
|
|||
|
||||
return (
|
||||
<div
|
||||
className="z-90 pointer-events-none absolute"
|
||||
className="pointer-events-none absolute z-90"
|
||||
style={{
|
||||
left: `${leftPosition}px`,
|
||||
top: topPosition,
|
||||
|
|
|
|||
|
|
@ -82,18 +82,14 @@ export function TimelineElement({
|
|||
|
||||
const hasAudio = mediaSupportsAudio({ media: mediaAsset });
|
||||
|
||||
const {
|
||||
handleResizeStart,
|
||||
isResizing,
|
||||
currentStartTime,
|
||||
currentDuration,
|
||||
} = useTimelineElementResize({
|
||||
element,
|
||||
track,
|
||||
zoomLevel,
|
||||
onSnapPointChange,
|
||||
onResizeStateChange,
|
||||
});
|
||||
const { handleResizeStart, isResizing, currentStartTime, currentDuration } =
|
||||
useTimelineElementResize({
|
||||
element,
|
||||
track,
|
||||
zoomLevel,
|
||||
onSnapPointChange,
|
||||
onResizeStateChange,
|
||||
});
|
||||
|
||||
const isCurrentElementSelected = selectedElements.some(
|
||||
(selected) =>
|
||||
|
|
@ -139,8 +135,9 @@ export function TimelineElement({
|
|||
<ContextMenu>
|
||||
<ContextMenuTrigger asChild>
|
||||
<div
|
||||
className={`absolute top-0 h-full select-none ${isBeingDragged ? "z-30" : "z-10"
|
||||
}`}
|
||||
className={`absolute top-0 h-full select-none ${
|
||||
isBeingDragged ? "z-30" : "z-10"
|
||||
}`}
|
||||
style={{
|
||||
left: `${elementLeft}px`,
|
||||
width: `${elementWidth}px`,
|
||||
|
|
@ -299,7 +296,7 @@ function ElementInner({
|
|||
</div>
|
||||
|
||||
{(hasAudio ? isMuted : canElementBeHidden(element) && element.hidden) && (
|
||||
<div className="pointer-events-none absolute inset-0 flex items-center justify-center bg-black bg-opacity-50">
|
||||
<div className="bg-opacity-50 pointer-events-none absolute inset-0 flex items-center justify-center bg-black">
|
||||
{hasAudio ? (
|
||||
<VolumeX className="size-6 text-white" />
|
||||
) : (
|
||||
|
|
@ -342,7 +339,7 @@ function ResizeHandle({
|
|||
const isLeft = side === "left";
|
||||
return (
|
||||
<div
|
||||
className={`bg-primary absolute bottom-0 top-0 z-50 flex w-[0.6rem] items-center justify-center ${isLeft ? "left-0 cursor-w-resize" : "right-0 cursor-e-resize"}`}
|
||||
className={`bg-primary absolute top-0 bottom-0 z-50 flex w-[0.6rem] items-center justify-center ${isLeft ? "left-0 cursor-w-resize" : "right-0 cursor-e-resize"}`}
|
||||
onMouseDown={(e) => handleResizeStart({ e, elementId, side })}
|
||||
>
|
||||
<div className="bg-foreground h-[1.5rem] w-[0.2rem] rounded-full" />
|
||||
|
|
@ -383,7 +380,8 @@ function ElementContent({
|
|||
}
|
||||
|
||||
if (element.type === "audio") {
|
||||
const audioBuffer = element.sourceType === "library" ? element.buffer : undefined;
|
||||
const audioBuffer =
|
||||
element.sourceType === "library" ? element.buffer : undefined;
|
||||
|
||||
const audioUrl =
|
||||
element.sourceType === "library"
|
||||
|
|
@ -436,7 +434,7 @@ function ElementContent({
|
|||
className={`relative size-full ${isSelected ? "bg-primary" : "bg-transparent"}`}
|
||||
>
|
||||
<div
|
||||
className="absolute left-0 right-0"
|
||||
className="absolute right-0 left-0"
|
||||
style={{
|
||||
backgroundImage: imageUrl ? `url(${imageUrl})` : "none",
|
||||
backgroundRepeat: "repeat-x",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ export function TimelinePlayhead({
|
|||
<div className="bg-foreground absolute left-0 h-full w-0.5 cursor-col-resize" />
|
||||
|
||||
<div
|
||||
className={`shadow-xs absolute left-1/2 top-1 size-3 -translate-x-1/2 transform rounded-full border-2 ${isSnappingToPlayhead ? "bg-foreground border-foreground" : "bg-foreground border-foreground/50"}`}
|
||||
className={`absolute top-1 left-1/2 size-3 -translate-x-1/2 transform rounded-full border-2 shadow-xs ${isSnappingToPlayhead ? "bg-foreground border-foreground" : "bg-foreground border-foreground/50"}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -52,13 +52,10 @@ export function TimelineToolbar({
|
|||
const newZoomLevel =
|
||||
direction === "in"
|
||||
? Math.min(
|
||||
TIMELINE_CONSTANTS.ZOOM_MAX,
|
||||
zoomLevel + TIMELINE_CONSTANTS.ZOOM_STEP,
|
||||
)
|
||||
: Math.max(
|
||||
minZoom,
|
||||
zoomLevel - TIMELINE_CONSTANTS.ZOOM_STEP,
|
||||
);
|
||||
TIMELINE_CONSTANTS.ZOOM_MAX,
|
||||
zoomLevel + TIMELINE_CONSTANTS.ZOOM_STEP,
|
||||
)
|
||||
: Math.max(minZoom, zoomLevel - TIMELINE_CONSTANTS.ZOOM_STEP);
|
||||
setZoomLevel({ zoom: newZoomLevel });
|
||||
};
|
||||
|
||||
|
|
@ -146,7 +143,7 @@ function ToolbarLeftSection() {
|
|||
icon={<SplitSquareHorizontal />}
|
||||
tooltip="Coming soon" /* separate audio */
|
||||
disabled={true}
|
||||
onClick={({ event }) => { }}
|
||||
onClick={({ event }) => {}}
|
||||
/>
|
||||
|
||||
<ToolbarButton
|
||||
|
|
@ -161,7 +158,7 @@ function ToolbarLeftSection() {
|
|||
icon={<Snowflake />}
|
||||
tooltip="Coming soon" /* freeze frame */
|
||||
disabled={true}
|
||||
onClick={({ event }) => { }}
|
||||
onClick={({ event }) => {}}
|
||||
/>
|
||||
|
||||
<ToolbarButton
|
||||
|
|
@ -231,10 +228,7 @@ function SceneSelector() {
|
|||
<SplitButtonLeft>{currentScene?.name || "No Scene"}</SplitButtonLeft>
|
||||
<SplitButtonSeparator />
|
||||
<ScenesView>
|
||||
<SplitButtonRight
|
||||
onClick={() => { }}
|
||||
type="button"
|
||||
>
|
||||
<SplitButtonRight onClick={() => {}} type="button">
|
||||
<LayersIcon className="size-4" />
|
||||
</SplitButtonRight>
|
||||
</ScenesView>
|
||||
|
|
@ -254,19 +248,28 @@ function ToolbarRightSection({
|
|||
onZoomChange: (zoom: number) => void;
|
||||
onZoom: (options: { direction: "in" | "out" }) => void;
|
||||
}) {
|
||||
const { snappingEnabled, rippleEditingEnabled, toggleSnapping, toggleRippleEditing } = useTimelineStore();
|
||||
const {
|
||||
snappingEnabled,
|
||||
rippleEditingEnabled,
|
||||
toggleSnapping,
|
||||
toggleRippleEditing,
|
||||
} = useTimelineStore();
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<TooltipProvider delayDuration={500}>
|
||||
<ToolbarButton
|
||||
icon={<Magnet className={cn(snappingEnabled ? "text-primary" : "")} />}
|
||||
icon={
|
||||
<Magnet className={cn(snappingEnabled ? "text-primary" : "")} />
|
||||
}
|
||||
tooltip="Auto snapping"
|
||||
onClick={() => toggleSnapping()}
|
||||
/>
|
||||
|
||||
<ToolbarButton
|
||||
icon={<Link className={cn(rippleEditingEnabled ? "text-primary" : "")} />}
|
||||
icon={
|
||||
<Link className={cn(rippleEditingEnabled ? "text-primary" : "")} />
|
||||
}
|
||||
tooltip="Ripple editing"
|
||||
onClick={() => toggleRippleEditing()}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export function TimelineTrackContent({
|
|||
});
|
||||
|
||||
const hasSelectedElements = track.elements.some((element) =>
|
||||
isElementSelected({ trackId: track.id, elementId: element.id })
|
||||
isElementSelected({ trackId: track.id, elementId: element.id }),
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ export function Header() {
|
|||
))}
|
||||
</nav>
|
||||
<ThemeToggle
|
||||
className="absolute bottom-8 right-8 size-10"
|
||||
className="absolute right-8 bottom-8 size-10"
|
||||
iconClassName="!size-[1.2rem]"
|
||||
onToggle={(e) => {
|
||||
e.preventDefault();
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ export function KeyboardShortcutsHelp() {
|
|||
// Auto-save the new keybinding
|
||||
const conflict = validateKeybinding(
|
||||
keyString,
|
||||
recordingShortcut.action
|
||||
recordingShortcut.action,
|
||||
);
|
||||
if (conflict) {
|
||||
toast.error(
|
||||
`Key "${keyString}" is already bound to "${conflict.existingAction}"`
|
||||
`Key "${keyString}" is already bound to "${conflict.existingAction}"`,
|
||||
);
|
||||
setRecordingShortcut(null);
|
||||
return;
|
||||
|
|
@ -110,10 +110,10 @@ export function KeyboardShortcutsHelp() {
|
|||
Shortcuts
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-2xl max-h-[80vh] flex flex-col p-0">
|
||||
<DialogContent className="flex max-h-[80vh] max-w-2xl flex-col p-0">
|
||||
<DialogHeader className="flex-shrink-0 p-6 pb-0">
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Keyboard className="w-5 h-5" />
|
||||
<Keyboard className="h-5 w-5" />
|
||||
Keyboard Shortcuts
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
|
|
@ -122,11 +122,11 @@ export function KeyboardShortcutsHelp() {
|
|||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="overflow-y-auto flex-grow scrollbar-thin">
|
||||
<div className="scrollbar-thin flex-grow overflow-y-auto">
|
||||
<div className="space-y-6 p-6 pt-2">
|
||||
{categories.map((category) => (
|
||||
<div key={category} className="flex flex-col gap-1">
|
||||
<h3 className="text-xs text-muted-foreground uppercase tracking-wide font-medium">
|
||||
<h3 className="text-muted-foreground text-xs font-medium tracking-wide uppercase">
|
||||
{category}
|
||||
</h3>
|
||||
<div className="space-y-1">
|
||||
|
|
@ -153,7 +153,6 @@ export function KeyboardShortcutsHelp() {
|
|||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -204,7 +203,7 @@ function ShortcutItem({
|
|||
})}
|
||||
</div>
|
||||
{index < displayKeys.length - 1 && (
|
||||
<span className="text-xs text-muted-foreground">or</span>
|
||||
<span className="text-muted-foreground text-xs">or</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -240,4 +239,4 @@ function EditableShortcutKey({
|
|||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,12 +111,12 @@ export function Handlebars({ children }: HandlebarsProps) {
|
|||
width > 0 ? (rightHandle / (width + 10)) * 100 : 0;
|
||||
|
||||
return (
|
||||
<div className="leading-16 flex justify-center gap-4">
|
||||
<div className="flex justify-center gap-4 leading-16">
|
||||
<div ref={containerRef} className="relative mt-0.5 -rotate-[2.76deg]">
|
||||
<div className="absolute inset-0 z-10 flex h-full w-full justify-between rounded-2xl border border-yellow-500">
|
||||
<div
|
||||
ref={leftHandleRef}
|
||||
className="bg-background absolute left-0 z-20 flex h-full w-7 cursor-ew-resize touch-none select-none items-center justify-center rounded-full border border-yellow-500"
|
||||
className="bg-background absolute left-0 z-20 flex h-full w-7 cursor-ew-resize touch-none items-center justify-center rounded-full border border-yellow-500 select-none"
|
||||
style={{
|
||||
translate: `${leftHandle}px 0`,
|
||||
}}
|
||||
|
|
@ -135,7 +135,7 @@ export function Handlebars({ children }: HandlebarsProps) {
|
|||
|
||||
<div
|
||||
ref={rightHandleRef}
|
||||
className="bg-background absolute -left-[30px] z-20 flex h-full w-7 cursor-ew-resize touch-none select-none items-center justify-center rounded-full border border-yellow-500"
|
||||
className="bg-background absolute -left-[30px] z-20 flex h-full w-7 cursor-ew-resize touch-none items-center justify-center rounded-full border border-yellow-500 select-none"
|
||||
style={{
|
||||
translate: `${rightHandle}px 0`,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -8,31 +8,31 @@ import Link from "next/link";
|
|||
|
||||
export function Hero() {
|
||||
return (
|
||||
<div className="min-h-[calc(100svh-4.5rem)] flex flex-col justify-between items-center text-center px-4">
|
||||
<div className="flex min-h-[calc(100svh-4.5rem)] flex-col items-center justify-between px-4 text-center">
|
||||
<Image
|
||||
className="absolute top-0 left-0 -z-50 size-full object-cover invert dark:invert-0 opacity-85"
|
||||
className="absolute top-0 left-0 -z-50 size-full object-cover opacity-85 invert dark:invert-0"
|
||||
src="/landing-page-dark.png"
|
||||
height={1903.5}
|
||||
width={1269}
|
||||
alt="landing-page.bg"
|
||||
/>
|
||||
<div className="max-w-3xl mx-auto w-full flex-1 flex flex-col justify-center">
|
||||
<div className="inline-block font-bold tracking-tighter text-4xl md:text-[4rem]">
|
||||
<div className="mx-auto flex w-full max-w-3xl flex-1 flex-col justify-center">
|
||||
<div className="inline-block text-4xl font-bold tracking-tighter md:text-[4rem]">
|
||||
<h1>The open source</h1>
|
||||
<Handlebars>Video Editor</Handlebars>
|
||||
</div>
|
||||
|
||||
<p className="mt-10 text-base sm:text-xl text-muted-foreground font-light tracking-wide max-w-xl mx-auto">
|
||||
<p className="text-muted-foreground mx-auto mt-10 max-w-xl text-base font-light tracking-wide sm:text-xl">
|
||||
A simple but powerful video editor that gets the job done. Works on
|
||||
any platform.
|
||||
</p>
|
||||
|
||||
<div className="mt-8 flex gap-8 justify-center">
|
||||
<div className="mt-8 flex justify-center gap-8">
|
||||
<Link href="/projects">
|
||||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
className="px-6 h-11 text-base bg-foreground"
|
||||
className="bg-foreground h-11 px-6 text-base"
|
||||
>
|
||||
Try early beta
|
||||
<ArrowRight className="ml-0.5" />
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ interface LanguageSelectProps {
|
|||
|
||||
function FlagPreloader({ languages }: { languages: Language[] }) {
|
||||
return (
|
||||
<div className="absolute -top-[9999px] left-0 pointer-events-none">
|
||||
<div className="pointer-events-none absolute -top-[9999px] left-0">
|
||||
{languages.map((language) => (
|
||||
<ReactCountryFlag
|
||||
key={language.code}
|
||||
|
|
@ -74,7 +74,7 @@ export function LanguageSelect({
|
|||
}, [expanded]);
|
||||
|
||||
const selectedLanguage = languages.find(
|
||||
(lang) => lang.code === selectedCountry
|
||||
(lang) => lang.code === selectedCountry,
|
||||
);
|
||||
|
||||
const handleSelect = ({
|
||||
|
|
@ -91,14 +91,14 @@ export function LanguageSelect({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-9">
|
||||
<div className="relative h-9 w-full">
|
||||
<FlagPreloader languages={languages} />
|
||||
<motion.button
|
||||
type="button"
|
||||
className={cn(
|
||||
"absolute w-full h-full flex flex-col overflow-hidden items-start justify-between z-10 rounded-lg px-3 cursor-pointer",
|
||||
"!bg-foreground/10 backdrop-blur-md text-foreground py-0",
|
||||
"transition-[color,box-shadow] focus:border-ring focus:ring-ring/50 focus:ring-[1px]"
|
||||
"absolute z-10 flex h-full w-full cursor-pointer flex-col items-start justify-between overflow-hidden rounded-lg px-3",
|
||||
"!bg-foreground/10 text-foreground py-0 backdrop-blur-md",
|
||||
"focus:border-ring focus:ring-ring/50 transition-[color,box-shadow] focus:ring-[1px]",
|
||||
)}
|
||||
initial={{
|
||||
height: collapsedHeight,
|
||||
|
|
@ -117,7 +117,7 @@ export function LanguageSelect({
|
|||
>
|
||||
{!expanded ? (
|
||||
<div
|
||||
className="flex items-center justify-between w-full"
|
||||
className="flex w-full items-center justify-between"
|
||||
style={{
|
||||
height: collapsedHeight,
|
||||
}}
|
||||
|
|
@ -138,7 +138,7 @@ export function LanguageSelect({
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2 my-2.5 w-full overflow-y-auto scrollbar-hidden">
|
||||
<div className="scrollbar-hidden my-2.5 flex w-full flex-col gap-2 overflow-y-auto">
|
||||
<LanguageButton
|
||||
language={{ code: "auto", name: "Auto" }}
|
||||
onSelect={handleSelect}
|
||||
|
|
@ -157,7 +157,7 @@ export function LanguageSelect({
|
|||
</motion.button>
|
||||
|
||||
<motion.div
|
||||
className="absolute top-1/2 right-3 -translate-y-1/2 pointer-events-none z-20 mt-0.5"
|
||||
className="pointer-events-none absolute top-1/2 right-3 z-20 mt-0.5 -translate-y-1/2"
|
||||
initial={{ opacity: 1 }}
|
||||
animate={{ opacity: expanded ? 0 : 1 }}
|
||||
transition={{ duration: 0.2, ease: "easeInOut" }}
|
||||
|
|
@ -186,7 +186,7 @@ function LanguageButton({
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-2 cursor-pointer text-foreground hover:text-foreground/75"
|
||||
className="text-foreground hover:text-foreground/75 flex cursor-pointer items-center gap-2"
|
||||
onClick={(e) => onSelect({ code: language.code, e })}
|
||||
>
|
||||
{language.code === "auto" ? (
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export function StorageProvider({ children }: StorageProviderProps) {
|
|||
|
||||
if (!hasSupport) {
|
||||
toast.warning(
|
||||
"Storage not fully supported. Some features may not work."
|
||||
"Storage not fully supported. Some features may not work.",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ interface ThemeToggleProps {
|
|||
onToggle?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
}
|
||||
|
||||
export function ThemeToggle({ className, iconClassName, onToggle }: ThemeToggleProps) {
|
||||
export function ThemeToggle({
|
||||
className,
|
||||
iconClassName,
|
||||
onToggle,
|
||||
}: ThemeToggleProps) {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const AccordionContent = React.forwardRef<
|
|||
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
||||
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
));
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ const AlertDialogOverlay = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
|
|
@ -36,8 +36,8 @@ const AlertDialogContent = React.forwardRef<
|
|||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -52,7 +52,7 @@ const AlertDialogHeader = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -66,7 +66,7 @@ const AlertDialogFooter = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -91,7 +91,7 @@ const AlertDialogDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -119,7 +119,7 @@ const AlertDialogCancel = React.forwardRef<
|
|||
className={cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"mt-2 sm:mt-0",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const alertVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const Alert = React.forwardRef<
|
||||
|
|
@ -38,7 +38,7 @@ const AlertTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
className={cn("mb-1 leading-none font-medium tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const Avatar = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -39,8 +39,8 @@ const AvatarFallback = React.forwardRef<
|
|||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
"bg-muted flex h-full w-full items-center justify-center rounded-full",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@ const badgeVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> { }
|
||||
extends
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ const BreadcrumbList = React.forwardRef<
|
|||
<ol
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
||||
className
|
||||
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -50,7 +50,7 @@ const BreadcrumbLink = React.forwardRef<
|
|||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn("transition-colors hover:text-foreground", className)}
|
||||
className={cn("hover:text-foreground transition-colors", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
@ -66,7 +66,7 @@ const BreadcrumbPage = React.forwardRef<
|
|||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
className={cn("font-normal text-foreground", className)}
|
||||
className={cn("text-foreground font-normal", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -80,7 +80,7 @@ const BreadcrumbSeparator = ({
|
|||
<li
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
|
||||
className={cn("[&>svg]:h-3.5 [&>svg]:w-3.5", className)}
|
||||
{...props}
|
||||
>
|
||||
{children ?? <ChevronRight />}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ const buttonVariants = cva(
|
|||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
extends
|
||||
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function Calendar({
|
|||
nav: "space-x-1 flex items-center",
|
||||
nav_button: cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
||||
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
|
||||
),
|
||||
nav_button_previous: "absolute left-1",
|
||||
nav_button_next: "absolute right-1",
|
||||
|
|
@ -40,11 +40,11 @@ function Calendar({
|
|||
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
|
||||
props.mode === "range"
|
||||
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
|
||||
: "[&:has([aria-selected])]:rounded-md"
|
||||
: "[&:has([aria-selected])]:rounded-md",
|
||||
),
|
||||
day: cn(
|
||||
buttonVariants({ variant: "text" }),
|
||||
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
|
||||
"h-8 w-8 p-0 font-normal aria-selected:opacity-100",
|
||||
),
|
||||
day_range_start: "day-range-start",
|
||||
day_range_end: "day-range-end",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const Card = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("rounded-2xl border bg-card text-card-foreground", className)}
|
||||
className={cn("bg-card text-card-foreground rounded-2xl border", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -32,7 +32,7 @@ const CardTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("font-semibold leading-none tracking-tight", className)}
|
||||
className={cn("leading-none font-semibold tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -44,7 +44,7 @@ const CardDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -56,14 +56,14 @@ const Carousel = React.forwardRef<
|
|||
children,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
},
|
||||
plugins
|
||||
plugins,
|
||||
);
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
||||
|
|
@ -95,7 +95,7 @@ const Carousel = React.forwardRef<
|
|||
scrollNext();
|
||||
}
|
||||
},
|
||||
[scrollPrev, scrollNext]
|
||||
[scrollPrev, scrollNext],
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
@ -146,7 +146,7 @@ const Carousel = React.forwardRef<
|
|||
</div>
|
||||
</CarouselContext.Provider>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
Carousel.displayName = "Carousel";
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ const CarouselContent = React.forwardRef<
|
|||
className={cn(
|
||||
"flex",
|
||||
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -186,7 +186,7 @@ const CarouselItem = React.forwardRef<
|
|||
className={cn(
|
||||
"min-w-0 shrink-0 grow-0 basis-full",
|
||||
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -206,11 +206,11 @@ const CarouselPrevious = React.forwardRef<
|
|||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-left-12 top-1/2 -translate-y-1/2"
|
||||
? "top-1/2 -left-12 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
disabled={!canScrollPrev}
|
||||
onClick={scrollPrev}
|
||||
|
|
@ -237,9 +237,9 @@ const CarouselNext = React.forwardRef<
|
|||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-right-12 top-1/2 -translate-y-1/2"
|
||||
? "top-1/2 -right-12 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
disabled={!canScrollNext}
|
||||
onClick={scrollNext}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ const ChartContainer = React.forwardRef<
|
|||
data-chart={chartId}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-hidden [&_.recharts-surface]:outline-hidden",
|
||||
className
|
||||
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -74,7 +74,7 @@ ChartContainer.displayName = "Chart";
|
|||
|
||||
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||
const colorConfig = Object.entries(config).filter(
|
||||
([_, config]) => config.theme || config.color
|
||||
([_, config]) => config.theme || config.color,
|
||||
);
|
||||
|
||||
if (!colorConfig.length) {
|
||||
|
|
@ -89,15 +89,15 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
|||
([theme, prefix]) => `
|
||||
${prefix} [data-chart=${id}] {
|
||||
${colorConfig
|
||||
.map(([key, itemConfig]) => {
|
||||
const color =
|
||||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
||||
itemConfig.color;
|
||||
return color ? ` --color-${key}: ${color};` : null;
|
||||
})
|
||||
.join("\n")}
|
||||
.map(([key, itemConfig]) => {
|
||||
const color =
|
||||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
||||
itemConfig.color;
|
||||
return color ? ` --color-${key}: ${color};` : null;
|
||||
})
|
||||
.join("\n")}
|
||||
}
|
||||
`
|
||||
`,
|
||||
)
|
||||
.join("\n"),
|
||||
}}
|
||||
|
|
@ -110,13 +110,13 @@ const ChartTooltip = RechartsPrimitive.Tooltip;
|
|||
const ChartTooltipContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: "line" | "dot" | "dashed";
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: "line" | "dot" | "dashed";
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}
|
||||
>(
|
||||
(
|
||||
{
|
||||
|
|
@ -134,7 +134,7 @@ const ChartTooltipContent = React.forwardRef<
|
|||
nameKey,
|
||||
labelKey,
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const { config } = useChart();
|
||||
|
||||
|
|
@ -184,8 +184,8 @@ const ChartTooltipContent = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className
|
||||
"border-border/50 bg-background grid min-w-32 items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{nestLabel ? null : tooltipLabel}
|
||||
|
|
@ -199,8 +199,8 @@ const ChartTooltipContent = React.forwardRef<
|
|||
<div
|
||||
key={item.dataKey}
|
||||
className={cn(
|
||||
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||
indicator === "dot" && "items-center"
|
||||
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
|
||||
indicator === "dot" && "items-center",
|
||||
)}
|
||||
>
|
||||
{formatter && item?.value !== undefined && item.name ? (
|
||||
|
|
@ -220,7 +220,7 @@ const ChartTooltipContent = React.forwardRef<
|
|||
"w-0 border-[1.5px] border-dashed bg-transparent":
|
||||
indicator === "dashed",
|
||||
"my-0.5": nestLabel && indicator === "dashed",
|
||||
}
|
||||
},
|
||||
)}
|
||||
style={
|
||||
{
|
||||
|
|
@ -234,7 +234,7 @@ const ChartTooltipContent = React.forwardRef<
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-1 justify-between leading-none",
|
||||
nestLabel ? "items-end" : "items-center"
|
||||
nestLabel ? "items-end" : "items-center",
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-1.5">
|
||||
|
|
@ -244,7 +244,7 @@ const ChartTooltipContent = React.forwardRef<
|
|||
</span>
|
||||
</div>
|
||||
{item.value && (
|
||||
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||
<span className="text-foreground font-mono font-medium tabular-nums">
|
||||
{item.value.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -257,7 +257,7 @@ const ChartTooltipContent = React.forwardRef<
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
ChartTooltipContent.displayName = "ChartTooltip";
|
||||
|
||||
|
|
@ -266,14 +266,14 @@ const ChartLegend = RechartsPrimitive.Legend;
|
|||
const ChartLegendContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<"div"> &
|
||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}
|
||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}
|
||||
>(
|
||||
(
|
||||
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const { config } = useChart();
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ const ChartLegendContent = React.forwardRef<
|
|||
className={cn(
|
||||
"flex items-center justify-center gap-4",
|
||||
verticalAlign === "top" ? "pb-3" : "pt-3",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{payload.map((item) => {
|
||||
|
|
@ -298,7 +298,7 @@ const ChartLegendContent = React.forwardRef<
|
|||
<div
|
||||
key={item.value}
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
|
||||
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3",
|
||||
)}
|
||||
>
|
||||
{itemConfig?.icon && !hideIcon ? (
|
||||
|
|
@ -317,7 +317,7 @@ const ChartLegendContent = React.forwardRef<
|
|||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
ChartLegendContent.displayName = "ChartLegend";
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ ChartLegendContent.displayName = "ChartLegend";
|
|||
function getPayloadConfigFromPayload(
|
||||
config: ChartConfig,
|
||||
payload: unknown,
|
||||
key: string
|
||||
key: string,
|
||||
) {
|
||||
if (typeof payload !== "object" || payload === null) {
|
||||
return;
|
||||
|
|
@ -333,8 +333,8 @@ function getPayloadConfigFromPayload(
|
|||
|
||||
const payloadPayload =
|
||||
"payload" in payload &&
|
||||
typeof payload.payload === "object" &&
|
||||
payload.payload !== null
|
||||
typeof payload.payload === "object" &&
|
||||
payload.payload !== null
|
||||
? payload.payload
|
||||
: undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ const Checkbox = React.forwardRef<
|
|||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow-sm focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
"peer border-primary focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground h-4 w-4 shrink-0 rounded-sm border shadow-sm focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -135,11 +135,11 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
const rect = saturationRef.current.getBoundingClientRect();
|
||||
const x = Math.max(
|
||||
0,
|
||||
Math.min(1, (e.clientX - rect.left) / rect.width)
|
||||
Math.min(1, (e.clientX - rect.left) / rect.width),
|
||||
);
|
||||
const y = Math.max(
|
||||
0,
|
||||
Math.min(1, (e.clientY - rect.top) / rect.height)
|
||||
Math.min(1, (e.clientY - rect.top) / rect.height),
|
||||
);
|
||||
const newS = x;
|
||||
const newV = 1 - y;
|
||||
|
|
@ -151,7 +151,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
const rect = hueRef.current.getBoundingClientRect();
|
||||
const x = Math.max(
|
||||
0,
|
||||
Math.min(1, (e.clientX - rect.left) / rect.width)
|
||||
Math.min(1, (e.clientX - rect.left) / rect.width),
|
||||
);
|
||||
const newH = x * 360;
|
||||
setInternalHue(newH);
|
||||
|
|
@ -231,14 +231,14 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"bg-panel-accent h-9 rounded-full flex items-center gap-2 px-[0.45rem]",
|
||||
className
|
||||
"bg-panel-accent flex h-9 items-center gap-2 rounded-full px-[0.45rem]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
ref={triggerRef}
|
||||
className="size-6 rounded-full cursor-pointer hover:ring-2 hover:ring-white/20 transition-all"
|
||||
className="size-6 cursor-pointer rounded-full transition-all hover:ring-2 hover:ring-white/20"
|
||||
style={{ backgroundColor: `#${value}` }}
|
||||
onClick={() => {
|
||||
if (!isOpen && triggerRef.current && containerRef?.current) {
|
||||
|
|
@ -252,9 +252,9 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
setIsOpen(!isOpen);
|
||||
}}
|
||||
/>
|
||||
<div className="flex-1 flex items-center">
|
||||
<div className="flex flex-1 items-center">
|
||||
<Input
|
||||
className="bg-transparent p-0 !ring-0 !ring-offset-0 !border-0"
|
||||
className="!border-0 bg-transparent p-0 !ring-0 !ring-offset-0"
|
||||
containerClassName="w-full"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
|
|
@ -268,7 +268,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
createPortal(
|
||||
<div
|
||||
ref={pickerRef}
|
||||
className="fixed z-50 p-4 bg-popover border border-border rounded-lg shadow-lg select-none"
|
||||
className="bg-popover border-border fixed z-50 rounded-lg border p-4 shadow-lg select-none"
|
||||
style={{
|
||||
right: pickerPosition.right,
|
||||
bottom: pickerPosition.bottom,
|
||||
|
|
@ -276,7 +276,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
>
|
||||
<div
|
||||
ref={saturationRef}
|
||||
className="relative w-48 h-32 cursor-crosshair mb-3"
|
||||
className="relative mb-3 h-32 w-48 cursor-crosshair"
|
||||
style={saturationStyle}
|
||||
onMouseDown={handleSaturationMouseDown}
|
||||
>
|
||||
|
|
@ -289,7 +289,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
|
||||
<div
|
||||
ref={hueRef}
|
||||
className="relative w-48 h-4 rounded-lg cursor-pointer"
|
||||
className="relative h-4 w-48 cursor-pointer rounded-lg"
|
||||
style={hueStyle}
|
||||
onMouseDown={handleHueMouseDown}
|
||||
>
|
||||
|
|
@ -303,11 +303,11 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||
/>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
document.body,
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
ColorPicker.displayName = "ColorPicker";
|
||||
|
||||
|
|
@ -321,8 +321,9 @@ const ColorCircle = ({
|
|||
color: string;
|
||||
}) => (
|
||||
<div
|
||||
className={`absolute border-3 border-white rounded-full shadow-lg pointer-events-none ${size === "sm" ? "size-3" : "size-4"
|
||||
}`}
|
||||
className={`pointer-events-none absolute rounded-full border-3 border-white shadow-lg ${
|
||||
size === "sm" ? "size-3" : "size-4"
|
||||
}`}
|
||||
style={{
|
||||
left: position.left,
|
||||
top: position.top,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ const Command = React.forwardRef<
|
|||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||
className
|
||||
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -26,7 +26,7 @@ const CommandDialog = ({ children, ...props }: DialogProps) => {
|
|||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
|
|
@ -43,8 +43,8 @@ const CommandInput = React.forwardRef<
|
|||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -59,7 +59,7 @@ const CommandList = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
className={cn("max-h-[300px] overflow-x-hidden overflow-y-auto", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -86,8 +86,8 @@ const CommandGroup = React.forwardRef<
|
|||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -101,7 +101,7 @@ const CommandSeparator = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-border", className)}
|
||||
className={cn("bg-border -mx-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -114,8 +114,8 @@ const CommandItem = React.forwardRef<
|
|||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -130,8 +130,8 @@ const CommandShortcut = ({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const contextMenuItemVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const ContextMenuSubTrigger = React.forwardRef<
|
||||
|
|
@ -47,7 +47,7 @@ const ContextMenuSubTrigger = React.forwardRef<
|
|||
contextMenuItemVariants({ variant }),
|
||||
"data-[state=open]:bg-accent data-[state=open]:opacity-65",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -64,8 +64,8 @@ const ContextMenuSubContent = React.forwardRef<
|
|||
<ContextMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -80,9 +80,9 @@ const ContextMenuContent = React.forwardRef<
|
|||
<ContextMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-32 overflow-hidden rounded-md border p-1 bg-popover text-popover-foreground shadow-md",
|
||||
"bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -102,7 +102,7 @@ const ContextMenuItem = React.forwardRef<
|
|||
className={cn(
|
||||
contextMenuItemVariants({ variant }),
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -117,7 +117,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
|
|||
>(({ className, children, checked, variant = "default", ...props }, ref) => (
|
||||
<ContextMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(contextMenuItemVariants({ variant }), "pl-8 pr-2", className)}
|
||||
className={cn(contextMenuItemVariants({ variant }), "pr-2 pl-8", className)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -140,7 +140,7 @@ const ContextMenuRadioItem = React.forwardRef<
|
|||
>(({ className, children, variant = "default", ...props }, ref) => (
|
||||
<ContextMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(contextMenuItemVariants({ variant }), "pl-8 pr-2", className)}
|
||||
className={cn(contextMenuItemVariants({ variant }), "pr-2 pl-8", className)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
|
|
@ -164,7 +164,7 @@ const ContextMenuLabel = React.forwardRef<
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -177,7 +177,7 @@ const ContextMenuSeparator = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-foreground/10", className)}
|
||||
className={cn("bg-foreground/10 -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ const DialogOverlay = React.forwardRef<
|
|||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-250 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-250 bg-black/50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -39,8 +39,8 @@ const DialogContent = React.forwardRef<
|
|||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] p-6 z-250 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-popover shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-lg",
|
||||
className
|
||||
"bg-popover data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-250 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200",
|
||||
className,
|
||||
)}
|
||||
onCloseAutoFocus={(e) => {
|
||||
e.stopPropagation();
|
||||
|
|
@ -49,7 +49,7 @@ const DialogContent = React.forwardRef<
|
|||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground cursor-pointer">
|
||||
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
|
|
@ -63,10 +63,7 @@ const DialogHeader = ({
|
|||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-left",
|
||||
className
|
||||
)}
|
||||
className={cn("flex flex-col space-y-2 text-left", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
@ -79,7 +76,7 @@ const DialogFooter = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -93,8 +90,8 @@ const DialogTitle = React.forwardRef<
|
|||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
"text-lg leading-none font-semibold tracking-tight",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -107,7 +104,7 @@ const DialogDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ export function DraggableItem({
|
|||
typeof document !== "undefined" &&
|
||||
createPortal(
|
||||
<div
|
||||
className="z-9999 pointer-events-none fixed"
|
||||
className="pointer-events-none fixed z-9999"
|
||||
style={{
|
||||
left: dragPosition.x - 40,
|
||||
top: dragPosition.y - 40,
|
||||
|
|
@ -179,7 +179,7 @@ export function DraggableItem({
|
|||
<div className="w-[80px]">
|
||||
<AspectRatio
|
||||
ratio={1}
|
||||
className="ring-3 ring-primary relative overflow-hidden rounded-md shadow-2xl"
|
||||
className="ring-primary relative overflow-hidden rounded-md shadow-2xl ring-3"
|
||||
>
|
||||
<div className="h-full w-full [&_img]:h-full [&_img]:w-full [&_img]:rounded-none [&_img]:object-cover">
|
||||
{preview}
|
||||
|
|
@ -212,7 +212,7 @@ function PlusButton({
|
|||
<Button
|
||||
size="icon"
|
||||
className={cn(
|
||||
"bg-background hover:bg-panel text-foreground absolute bottom-2 right-2 size-5",
|
||||
"bg-background hover:bg-panel text-foreground absolute right-2 bottom-2 size-5",
|
||||
className,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ const DrawerContent = React.forwardRef<
|
|||
<DrawerPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
||||
className
|
||||
"bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
||||
<div className="bg-muted mx-auto mt-4 h-2 w-[100px] rounded-full" />
|
||||
{children}
|
||||
</DrawerPrimitive.Content>
|
||||
</DrawerPortal>
|
||||
|
|
@ -84,8 +84,8 @@ const DrawerTitle = React.forwardRef<
|
|||
<DrawerPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
"text-lg leading-none font-semibold tracking-tight",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -98,7 +98,7 @@ const DrawerDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const dropdownMenuItemVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
|
|
@ -47,7 +47,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
dropdownMenuItemVariants({ variant }),
|
||||
"data-[state=open]:bg-accent data-[state=open]:opacity-65",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -65,8 +65,8 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -87,9 +87,9 @@ const DropdownMenuContent = React.forwardRef<
|
|||
e.preventDefault();
|
||||
}}
|
||||
className={cn(
|
||||
"z-50 min-w-32 overflow-hidden rounded-md border p-1 bg-popover text-popover-foreground shadow-md",
|
||||
"bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -109,7 +109,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
className={cn(
|
||||
dropdownMenuItemVariants({ variant }),
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -126,8 +126,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
dropdownMenuItemVariants({ variant }),
|
||||
"pl-2 pr-8",
|
||||
className
|
||||
"pr-8 pl-2",
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
onSelect={(e) => {
|
||||
|
|
@ -157,8 +157,8 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
dropdownMenuItemVariants({ variant }),
|
||||
"pl-8 pr-2",
|
||||
className
|
||||
"pr-2 pl-8",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -183,7 +183,7 @@ const DropdownMenuLabel = React.forwardRef<
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -196,7 +196,7 @@ const DropdownMenuSeparator = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-foreground/10", className)}
|
||||
className={cn("bg-foreground/10 -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ export function FontPicker({
|
|||
}: FontPickerProps) {
|
||||
return (
|
||||
<Select defaultValue={defaultValue} onValueChange={onValueChange}>
|
||||
<SelectTrigger className={`w-full bg-panel-accent h-8 text-xs ${className || ""}`}>
|
||||
<SelectTrigger
|
||||
className={`bg-panel-accent h-8 w-full text-xs ${className || ""}`}
|
||||
>
|
||||
<SelectValue placeholder="Select a font" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ type FormFieldContextValue<
|
|||
};
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
{} as FormFieldContextValue,
|
||||
);
|
||||
|
||||
const FormField = <
|
||||
|
|
@ -69,7 +69,7 @@ type FormItemContextValue = {
|
|||
};
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
{} as FormItemContextValue,
|
||||
);
|
||||
|
||||
const FormItem = React.forwardRef<
|
||||
|
|
@ -134,7 +134,7 @@ const FormDescription = React.forwardRef<
|
|||
<p
|
||||
ref={ref}
|
||||
id={formDescriptionId}
|
||||
className={cn("text-[0.8rem] text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-[0.8rem]", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
@ -156,7 +156,7 @@ const FormMessage = React.forwardRef<
|
|||
<p
|
||||
ref={ref}
|
||||
id={formMessageId}
|
||||
className={cn("text-[0.8rem] font-medium text-destructive", className)}
|
||||
className={cn("text-destructive text-[0.8rem] font-medium", className)}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ const HoverCardContent = React.forwardRef<
|
|||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const InputOTP = React.forwardRef<
|
|||
ref={ref}
|
||||
containerClassName={cn(
|
||||
"flex items-center justify-between gap-2 w-full has-disabled:opacity-50",
|
||||
containerClassName
|
||||
containerClassName,
|
||||
)}
|
||||
className={cn("disabled:cursor-not-allowed", className)}
|
||||
{...props}
|
||||
|
|
@ -28,7 +28,7 @@ const InputOTPGroup = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center flex-1 gap-2", className)}
|
||||
className={cn("flex flex-1 items-center gap-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -45,16 +45,16 @@ const InputOTPSlot = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex aspect-square flex-1 min-w-[36px] items-center justify-center border border-input text-lg shadow-xs transition-all first:rounded-l-md first:border-l last:rounded-r-md",
|
||||
isActive && "z-10 ring-1 ring-ring",
|
||||
className
|
||||
"border-input relative flex aspect-square min-w-[36px] flex-1 items-center justify-center border text-lg shadow-xs transition-all first:rounded-l-md first:border-l last:rounded-r-md",
|
||||
isActive && "ring-ring z-10 ring-1",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{char}
|
||||
{hasFakeCaret && (
|
||||
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
|
||||
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export function InputWithBack({
|
|||
return (
|
||||
<div ref={setContainerRef} className="relative w-full">
|
||||
<motion.div
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 cursor-pointer hover:opacity-75 transition-opacity z-10"
|
||||
className="absolute top-1/2 left-0 z-10 -translate-y-1/2 cursor-pointer transition-opacity hover:opacity-75"
|
||||
initial={{
|
||||
x: isExpanded ? 0 : buttonOffset,
|
||||
opacity: isExpanded ? 1 : 0.5,
|
||||
|
|
@ -55,7 +55,7 @@ export function InputWithBack({
|
|||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="!size-9 rounded-full bg-panel-accent"
|
||||
className="bg-panel-accent !size-9 rounded-full"
|
||||
>
|
||||
<ArrowLeft />
|
||||
</Button>
|
||||
|
|
@ -74,10 +74,10 @@ export function InputWithBack({
|
|||
}}
|
||||
transition={smoothTransition}
|
||||
>
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
|
||||
<Input
|
||||
placeholder={placeholder}
|
||||
className="pl-9 bg-panel-accent w-full"
|
||||
className="bg-panel-accent w-full pl-9"
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
onBlur,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
|
|
@ -49,15 +49,17 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
iconCount === 2 ? "pr-20" : iconCount === 1 ? "pr-10" : "";
|
||||
|
||||
return (
|
||||
<div className={cn(hasIcons ? "relative w-full" : "", containerClassName)}>
|
||||
<div
|
||||
className={cn(hasIcons ? "relative w-full" : "", containerClassName)}
|
||||
>
|
||||
<input
|
||||
type={inputType}
|
||||
className={cn(
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-input flex h-9 w-full min-w-0 rounded-md border bg-background px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-input bg-background flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[2px]",
|
||||
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
paddingRight,
|
||||
className
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
value={value}
|
||||
|
|
@ -80,7 +82,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
e.preventDefault();
|
||||
onClear?.();
|
||||
}}
|
||||
className="absolute right-0 top-0 h-full px-3 text-muted-foreground !opacity-100"
|
||||
className="text-muted-foreground absolute top-0 right-0 h-full px-3 !opacity-100"
|
||||
aria-label="Clear input"
|
||||
>
|
||||
<X className="!size-[0.85]" />
|
||||
|
|
@ -93,8 +95,8 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
size="icon"
|
||||
onClick={() => onShowPasswordChange?.(!showPassword)}
|
||||
className={cn(
|
||||
"absolute top-0 h-full px-3 text-muted-foreground hover:text-foreground",
|
||||
showClear ? "right-10" : "right-0"
|
||||
"text-muted-foreground hover:text-foreground absolute top-0 h-full px-3",
|
||||
showClear ? "right-10" : "right-0",
|
||||
)}
|
||||
aria-label={showPassword ? "Hide password" : "Show password"}
|
||||
>
|
||||
|
|
@ -107,7 +109,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
Input.displayName = "Input";
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|||
import { cn } from "@/utils/ui";
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ const Menubar = React.forwardRef<
|
|||
<MenubarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-xs",
|
||||
className
|
||||
"bg-background flex h-9 items-center space-x-1 rounded-md border p-1 shadow-xs",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -38,8 +38,8 @@ const MenubarTrigger = React.forwardRef<
|
|||
<MenubarPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
className
|
||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-3 py-1 text-sm font-medium outline-hidden select-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -55,9 +55,9 @@ const MenubarSubTrigger = React.forwardRef<
|
|||
<MenubarPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -74,8 +74,8 @@ const MenubarSubContent = React.forwardRef<
|
|||
<MenubarPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -88,7 +88,7 @@ const MenubarContent = React.forwardRef<
|
|||
>(
|
||||
(
|
||||
{ className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
|
||||
ref
|
||||
ref,
|
||||
) => (
|
||||
<MenubarPrimitive.Portal>
|
||||
<MenubarPrimitive.Content
|
||||
|
|
@ -97,13 +97,13 @@ const MenubarContent = React.forwardRef<
|
|||
alignOffset={alignOffset}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-48 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-48 overflow-hidden rounded-md border p-1 shadow-md",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</MenubarPrimitive.Portal>
|
||||
)
|
||||
),
|
||||
);
|
||||
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
|
||||
|
||||
|
|
@ -116,9 +116,9 @@ const MenubarItem = React.forwardRef<
|
|||
<MenubarPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -132,8 +132,8 @@ const MenubarCheckboxItem = React.forwardRef<
|
|||
<MenubarPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
|
|
@ -155,8 +155,8 @@ const MenubarRadioItem = React.forwardRef<
|
|||
<MenubarPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -181,7 +181,7 @@ const MenubarLabel = React.forwardRef<
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -194,7 +194,7 @@ const MenubarSeparator = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
className={cn("bg-muted -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -207,8 +207,8 @@ const MenubarShortcut = ({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const NavigationMenu = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -31,7 +31,7 @@ const NavigationMenuList = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"group flex flex-1 list-none items-center justify-center space-x-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -41,7 +41,7 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
|
|||
const NavigationMenuItem = NavigationMenuPrimitive.Item;
|
||||
|
||||
const navigationMenuTriggerStyle = cva(
|
||||
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-hidden disabled:pointer-events-none disabled:opacity-50 data-active:bg-accent/50 data-[state=open]:bg-accent/50"
|
||||
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-hidden disabled:pointer-events-none disabled:opacity-50 data-active:bg-accent/50 data-[state=open]:bg-accent/50",
|
||||
);
|
||||
|
||||
const NavigationMenuTrigger = React.forwardRef<
|
||||
|
|
@ -69,8 +69,8 @@ const NavigationMenuContent = React.forwardRef<
|
|||
<NavigationMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
|
||||
className
|
||||
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full md:absolute md:w-auto",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -83,11 +83,11 @@ const NavigationMenuViewport = React.forwardRef<
|
|||
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className={cn("absolute left-0 top-full flex justify-center")}>
|
||||
<div className={cn("absolute top-full left-0 flex justify-center")}>
|
||||
<NavigationMenuPrimitive.Viewport
|
||||
className={cn(
|
||||
"origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-(--radix-navigation-menu-viewport-width)",
|
||||
className
|
||||
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-md border shadow-sm md:w-(--radix-navigation-menu-viewport-width)",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
|
|
@ -104,12 +104,12 @@ const NavigationMenuIndicator = React.forwardRef<
|
|||
<NavigationMenuPrimitive.Indicator
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
|
||||
className
|
||||
"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-1 flex h-1.5 items-end justify-center overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
||||
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
|
||||
</NavigationMenuPrimitive.Indicator>
|
||||
));
|
||||
NavigationMenuIndicator.displayName =
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const PaginationLink = ({
|
|||
variant: isActive ? "outline" : "text",
|
||||
size,
|
||||
}),
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const PhoneInput: React.ForwardRefExoticComponent<PhoneInputProps> =
|
|||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
PhoneInput.displayName = "PhoneInput";
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ const InputComponent = React.forwardRef<
|
|||
React.ComponentProps<"input">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<Input
|
||||
className={cn("rounded-e-lg rounded-s-none", className)}
|
||||
className={cn("rounded-s-none rounded-e-lg", className)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
|
|
@ -89,7 +89,7 @@ const CountrySelect = ({
|
|||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="flex gap-1 rounded-e-none rounded-s-lg border-r-0 px-3 focus:z-10"
|
||||
className="flex gap-1 rounded-s-lg rounded-e-none border-r-0 px-3 focus:z-10"
|
||||
disabled={disabled}
|
||||
>
|
||||
<FlagComponent
|
||||
|
|
@ -99,7 +99,7 @@ const CountrySelect = ({
|
|||
<ChevronsUpDown
|
||||
className={cn(
|
||||
"-mr-2 size-4 opacity-50",
|
||||
disabled ? "hidden" : "opacity-100"
|
||||
disabled ? "hidden" : "opacity-100",
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
|
|
@ -120,7 +120,7 @@ const CountrySelect = ({
|
|||
selectedCountry={selectedCountry}
|
||||
onChange={onChange}
|
||||
/>
|
||||
) : null
|
||||
) : null,
|
||||
)}
|
||||
</CommandGroup>
|
||||
</ScrollArea>
|
||||
|
|
@ -146,7 +146,7 @@ const CountrySelectOption = ({
|
|||
<CommandItem className="gap-2" onSelect={() => onChange(country)}>
|
||||
<FlagComponent country={country} countryName={countryName} />
|
||||
<span className="flex-1 text-sm">{countryName}</span>
|
||||
<span className="text-sm text-foreground/50">{`+${RPNInput.getCountryCallingCode(country)}`}</span>
|
||||
<span className="text-foreground/50 text-sm">{`+${RPNInput.getCountryCallingCode(country)}`}</span>
|
||||
<CheckIcon
|
||||
className={`ml-auto size-4 ${country === selectedCountry ? "opacity-100" : "opacity-0"}`}
|
||||
/>
|
||||
|
|
@ -158,7 +158,7 @@ const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => {
|
|||
const Flag = flags[country];
|
||||
|
||||
return (
|
||||
<span className="flex h-4 w-6 overflow-hidden rounded-sm bg-foreground/20 [&_svg]:size-full">
|
||||
<span className="bg-foreground/20 flex h-4 w-6 overflow-hidden rounded-sm [&_svg]:size-full">
|
||||
{Flag && <Flag title={countryName} />}
|
||||
</span>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ const PopoverContent = React.forwardRef<
|
|||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-[0_0_10px_rgba(0,0,0,0.15)] outline-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-[0_0_10px_rgba(0,0,0,0.15)] outline-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ const Progress = React.forwardRef<
|
|||
<ProgressPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative h-2 w-full overflow-hidden rounded-full bg-accent",
|
||||
className
|
||||
"bg-accent relative h-2 w-full overflow-hidden rounded-full",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ProgressPrimitive.Indicator
|
||||
className="h-full w-full flex-1 bg-foreground transition-all"
|
||||
className="bg-foreground h-full w-full flex-1 transition-all"
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ function Prose({ children, html, className }: ProseProps) {
|
|||
return (
|
||||
<article
|
||||
className={cn(
|
||||
"prose prose-h2:font-semibold max-w-none prose-h1:text-xl prose-a:text-blue-600 prose-p:text-justify dark:prose-invert mx-auto",
|
||||
className
|
||||
"prose prose-h2:font-semibold prose-h1:text-xl prose-a:text-blue-600 prose-p:text-justify dark:prose-invert mx-auto max-w-none",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{html ? <div dangerouslySetInnerHTML={{ __html: html }} /> : children}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ const RadioGroupItem = React.forwardRef<
|
|||
<RadioGroupPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow-sm focus:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
"border-primary text-primary focus-visible:ring-ring aspect-square h-4 w-4 rounded-full border shadow-sm focus:outline-hidden focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
||||
<Circle className="h-3.5 w-3.5 fill-primary" />
|
||||
<Circle className="fill-primary h-3.5 w-3.5" />
|
||||
</RadioGroupPrimitive.Indicator>
|
||||
</RadioGroupPrimitive.Item>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const ResizablePanelGroup = ({
|
|||
<ResizablePrimitive.PanelGroup
|
||||
className={cn(
|
||||
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -28,8 +28,8 @@ const ResizableHandle = ({
|
|||
}) => (
|
||||
<ResizablePrimitive.PanelResizeHandle
|
||||
className={cn(
|
||||
"relative flex w-px items-center justify-center bg-transparent after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
||||
className
|
||||
"focus-visible:ring-ring relative flex w-px items-center justify-center bg-transparent after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const ScrollArea = React.forwardRef<
|
|||
>(({ className, children, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("overflow-auto scrollbar-thin", className)}
|
||||
className={cn("scrollbar-thin overflow-auto", className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const selectItemVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
|
|
@ -35,8 +35,8 @@ const SelectTrigger = React.forwardRef<
|
|||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex gap-1 h-7 cursor-pointer w-auto items-center justify-between whitespace-nowrap rounded-md bg-accent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
"bg-accent ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-7 w-auto cursor-pointer items-center justify-between gap-1 rounded-md px-3 py-2 text-sm whitespace-nowrap focus:ring-1 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -56,7 +56,7 @@ const SelectScrollUpButton = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -73,7 +73,7 @@ const SelectScrollDownButton = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
@ -91,10 +91,10 @@ const SelectContent = React.forwardRef<
|
|||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
onCloseAutoFocus={(e) => {
|
||||
|
|
@ -108,7 +108,7 @@ const SelectContent = React.forwardRef<
|
|||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)"
|
||||
"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
|
@ -158,7 +158,7 @@ const SelectSeparator = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-foreground/10", className)}
|
||||
className={cn("bg-foreground/10 -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -11,20 +11,20 @@ const Separator = React.forwardRef<
|
|||
>(
|
||||
(
|
||||
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||
ref
|
||||
ref,
|
||||
) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"shrink-0 bg-border",
|
||||
"bg-border shrink-0",
|
||||
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
),
|
||||
);
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ const SheetOverlay = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-200 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-200 bg-black/50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
|
|
@ -46,12 +46,13 @@ const sheetVariants = cva(
|
|||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
interface SheetContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> { }
|
||||
extends
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {}
|
||||
|
||||
const SheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||
|
|
@ -68,7 +69,7 @@ const SheetContent = React.forwardRef<
|
|||
}}
|
||||
{...props}
|
||||
>
|
||||
<SheetPrimitive.Close className="absolute cursor-pointer right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 cursor-pointer rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||
<X className="size-5" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
|
|
@ -85,7 +86,7 @@ const SheetHeader = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -99,7 +100,7 @@ const SheetFooter = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -112,7 +113,7 @@ const SheetTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
className={cn("text-foreground text-lg font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -124,7 +125,7 @@ const SheetDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ function Skeleton({
|
|||
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-primary/10", className)}
|
||||
className={cn("bg-primary/10 animate-pulse rounded-md", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ const Slider = React.forwardRef<
|
|||
<SliderPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full touch-none select-none items-center",
|
||||
className
|
||||
"relative flex w-full touch-none items-center select-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
|
||||
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
||||
<SliderPrimitive.Track className="bg-primary/20 relative h-1.5 w-full grow overflow-hidden rounded-full">
|
||||
<SliderPrimitive.Range className="bg-primary absolute h-full" />
|
||||
</SliderPrimitive.Track>
|
||||
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow-sm transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
||||
<SliderPrimitive.Thumb className="border-primary/50 bg-background focus-visible:ring-ring block h-4 w-4 rounded-full border shadow-sm transition-colors focus-visible:ring-1 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50" />
|
||||
</SliderPrimitive.Root>
|
||||
));
|
||||
Slider.displayName = SliderPrimitive.Root.displayName;
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@ const SplitButton = forwardRef<HTMLDivElement, SplitButtonProps>(
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex rounded-full h-7 border border-input bg-panel-accent overflow-hidden",
|
||||
className
|
||||
"border-input bg-panel-accent inline-flex h-7 overflow-hidden rounded-full border",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
SplitButton.displayName = "SplitButton";
|
||||
|
||||
|
|
@ -39,18 +39,18 @@ const SplitButtonSide = forwardRef<
|
|||
ref={ref}
|
||||
variant="text"
|
||||
className={cn(
|
||||
"h-full rounded-none bg-panel-accent !opacity-100 border-0 gap-0 font-normal transition-colors disabled:text-muted-foreground",
|
||||
"bg-panel-accent disabled:text-muted-foreground h-full gap-0 rounded-none border-0 font-normal !opacity-100 transition-colors",
|
||||
onClick
|
||||
? "hover:bg-foreground/10 hover:opacity-100 cursor-pointer"
|
||||
? "hover:bg-foreground/10 cursor-pointer hover:opacity-100"
|
||||
: "cursor-default select-text",
|
||||
paddingClass,
|
||||
className
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
>
|
||||
{typeof children === "string" ? (
|
||||
<span className="font-normal cursor-text">{children}</span>
|
||||
<span className="cursor-text font-normal">{children}</span>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
|
|
@ -62,14 +62,14 @@ SplitButtonSide.displayName = "SplitButtonSide";
|
|||
const SplitButtonLeft = forwardRef<HTMLButtonElement, SplitButtonSideProps>(
|
||||
({ ...props }, ref) => {
|
||||
return <SplitButtonSide ref={ref} paddingClass="pl-3 pr-2" {...props} />;
|
||||
}
|
||||
},
|
||||
);
|
||||
SplitButtonLeft.displayName = "SplitButtonLeft";
|
||||
|
||||
const SplitButtonRight = forwardRef<HTMLButtonElement, SplitButtonSideProps>(
|
||||
({ ...props }, ref) => {
|
||||
return <SplitButtonSide ref={ref} paddingClass="pl-2 pr-3" {...props} />;
|
||||
}
|
||||
},
|
||||
);
|
||||
SplitButtonRight.displayName = "SplitButtonRight";
|
||||
|
||||
|
|
@ -79,11 +79,11 @@ const SplitButtonSeparator = forwardRef<HTMLDivElement, { className?: string }>(
|
|||
<Separator
|
||||
ref={ref}
|
||||
orientation="vertical"
|
||||
className={cn("h-full bg-foreground/15", className)}
|
||||
className={cn("bg-foreground/15 h-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
SplitButtonSeparator.displayName = "SplitButtonSeparator";
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ const Switch = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
"peer focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
"bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ const TableFooter = React.forwardRef<
|
|||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium last:[&>tr]:border-b-0",
|
||||
className
|
||||
"bg-muted/50 border-t font-medium last:[&>tr]:border-b-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -58,8 +58,8 @@ const TableRow = React.forwardRef<
|
|||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -73,8 +73,8 @@ const TableHead = React.forwardRef<
|
|||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
"text-muted-foreground h-10 px-2 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -89,7 +89,7 @@ const TableCell = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -102,7 +102,7 @@ const TableCaption = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
className={cn("text-muted-foreground mt-4 text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ const TabsList = React.forwardRef<
|
|||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-auto items-center justify-center gap-2 rounded-lg bg-transparent p-0 text-muted-foreground",
|
||||
className
|
||||
"text-muted-foreground inline-flex h-auto items-center justify-center gap-2 rounded-lg bg-transparent p-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -29,8 +29,8 @@ const TabsTrigger = React.forwardRef<
|
|||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center cursor-pointer justify-center whitespace-nowrap rounded-lg px-3 py-1 text-sm font-medium ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-panel-accent data-[state=active]:text-foreground",
|
||||
className
|
||||
"ring-offset-background focus-visible:ring-ring data-[state=active]:bg-panel-accent data-[state=active]:text-foreground inline-flex cursor-pointer items-center justify-center rounded-lg px-3 py-1 text-sm font-medium whitespace-nowrap focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -44,8 +44,8 @@ const TabsContent = React.forwardRef<
|
|||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
"ring-offset-background focus-visible:ring-ring mt-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ const Textarea = React.forwardRef<
|
|||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex min-h-[60px] w-full rounded-md border bg-accent/50 px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input bg-accent/50 flex min-h-[60px] w-full rounded-md border px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[2px]",
|
||||
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ const ToastViewport = React.forwardRef<
|
|||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-100 flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
||||
className
|
||||
"fixed top-0 z-100 flex max-h-screen w-full flex-col-reverse p-4 sm:top-auto sm:right-0 sm:bottom-0 sm:flex-col md:max-w-[420px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -37,13 +37,13 @@ const toastVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
||||
VariantProps<typeof toastVariants>
|
||||
VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
|
|
@ -62,8 +62,8 @@ const ToastAction = React.forwardRef<
|
|||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus-visible:outline-hidden focus-visible:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 hover:group-[.destructive]:border-destructive/30 hover:group-[.destructive]:bg-destructive hover:group-[.destructive]:text-destructive-foreground group-[.destructive]:focus-visible::ring-destructive",
|
||||
className
|
||||
"hover:bg-secondary focus:ring-ring group-[.destructive]:border-muted/40 hover:group-[.destructive]:border-destructive/30 hover:group-[.destructive]:bg-destructive hover:group-[.destructive]:text-destructive-foreground group-[.destructive]:focus-visible::ring-destructive inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors focus-visible:ring-1 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -77,8 +77,8 @@ const ToastClose = React.forwardRef<
|
|||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-hidden focus-visible::ring-1 group-hover:opacity-100 group-[.destructive]:text-muted-foreground hover:group-[.destructive]:text-red-50 focus-visible:group-[.destructive]:ring-red-400 focus-visible:group-[.destructive]:ring-offset-red-600",
|
||||
className
|
||||
"text-foreground/50 hover:text-foreground focus-visible::ring-1 group-[.destructive]:text-muted-foreground absolute top-1 right-1 rounded-md p-1 opacity-0 transition-opacity group-hover:opacity-100 hover:group-[.destructive]:text-red-50 focus:opacity-100 focus:outline-hidden focus-visible:group-[.destructive]:ring-red-400 focus-visible:group-[.destructive]:ring-offset-red-600",
|
||||
className,
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const ToggleGroupContext = React.createContext<
|
|||
const ToggleGroup = React.forwardRef<
|
||||
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, variant, size, children, ...props }, ref) => (
|
||||
<ToggleGroupPrimitive.Root
|
||||
ref={ref}
|
||||
|
|
@ -35,7 +35,7 @@ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
|
|||
const ToggleGroupItem = React.forwardRef<
|
||||
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, children, variant, size, ...props }, ref) => {
|
||||
const context = React.useContext(ToggleGroupContext);
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ const ToggleGroupItem = React.forwardRef<
|
|||
variant: context.variant || variant,
|
||||
size: context.size || size,
|
||||
}),
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ const toggleVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const Toggle = React.forwardRef<
|
||||
React.ElementRef<typeof TogglePrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, variant, size, ...props }, ref) => (
|
||||
<TogglePrimitive.Root
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
import { Tooltip as TooltipPrimitive } from 'radix-ui';
|
||||
import * as React from 'react';
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from '@/utils/ui';
|
||||
import { cn } from "@/utils/ui";
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider;
|
||||
|
||||
|
|
@ -11,36 +11,37 @@ const Tooltip = TooltipPrimitive.Root;
|
|||
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||
|
||||
const tooltipVariants = cva(
|
||||
'z-50 overflow-visible rounded-sm text-sm shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
"z-50 overflow-visible rounded-sm text-sm shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-popover text-popover-foreground border px-3 py-1.5',
|
||||
default: "bg-popover text-popover-foreground border px-3 py-1.5",
|
||||
destructive:
|
||||
'bg-destructive/10 text-destructive dark:bg-destructive/20 border-destructive [border-width:0.5px]',
|
||||
outline: 'border-border',
|
||||
"bg-destructive/10 text-destructive dark:bg-destructive/20 border-destructive [border-width:0.5px]",
|
||||
outline: "border-border",
|
||||
important:
|
||||
'bg-amber-100/90 text-amber-900 dark:bg-amber-900/20 dark:text-amber-300 border-amber-900 [border-width:0.5px]',
|
||||
"bg-amber-100/90 text-amber-900 dark:bg-amber-900/20 dark:text-amber-300 border-amber-900 [border-width:0.5px]",
|
||||
promotions:
|
||||
'bg-red-100/90 text-red-900 dark:bg-red-900/20 dark:text-red-300 border-red-900 [border-width:0.5px]',
|
||||
"bg-red-100/90 text-red-900 dark:bg-red-900/20 dark:text-red-300 border-red-900 [border-width:0.5px]",
|
||||
personal:
|
||||
'bg-green-100/90 text-green-900 dark:bg-green-900/20 dark:text-green-300 border-green-900 [border-width:0.5px]',
|
||||
"bg-green-100/90 text-green-900 dark:bg-green-900/20 dark:text-green-300 border-green-900 [border-width:0.5px]",
|
||||
updates:
|
||||
'bg-purple-100/90 text-purple-900 dark:bg-purple-900/20 dark:text-purple-300 border-purple-900 [border-width:0.5px]',
|
||||
"bg-purple-100/90 text-purple-900 dark:bg-purple-900/20 dark:text-purple-300 border-purple-900 [border-width:0.5px]",
|
||||
forums:
|
||||
'bg-blue-100/90 text-blue-900 dark:bg-blue-900/20 dark:text-blue-300 border-blue-900 [border-width:0.5px]',
|
||||
sidebar: 'bg-white dark:bg-[#413F3E] p-2.5 flex flex-col gap-2',
|
||||
"bg-blue-100/90 text-blue-900 dark:bg-blue-900/20 dark:text-blue-300 border-blue-900 [border-width:0.5px]",
|
||||
sidebar: "bg-white dark:bg-[#413F3E] p-2.5 flex flex-col gap-2",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
interface TooltipContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,
|
||||
VariantProps<typeof tooltipVariants> { }
|
||||
extends
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,
|
||||
VariantProps<typeof tooltipVariants> {}
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
|
|
@ -52,16 +53,19 @@ const TooltipContent = React.forwardRef<
|
|||
className={cn(tooltipVariants({ variant }), className)}
|
||||
{...props}
|
||||
>
|
||||
{variant === 'sidebar' && (
|
||||
{variant === "sidebar" && (
|
||||
<svg
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="absolute left-[-6px] top-1/2 -translate-y-1/2"
|
||||
className="absolute top-1/2 left-[-6px] -translate-y-1/2"
|
||||
>
|
||||
<path d="M6 0L0 5L6 10V0Z" className="fill-white/80 dark:fill-[#413F3E]" />
|
||||
<path
|
||||
d="M6 0L0 5L6 10V0Z"
|
||||
className="fill-white/80 dark:fill-[#413F3E]"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
{props.children}
|
||||
|
|
@ -69,4 +73,4 @@ const TooltipContent = React.forwardRef<
|
|||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue