Upgrade to Tailwind CSS v4 (#1173)
This commit is contained in:
parent
4ce76987a1
commit
848205f5cb
76 changed files with 1098 additions and 1050 deletions
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript",
|
||||
"prettier",
|
||||
"plugin:tailwindcss/recommended"
|
||||
],
|
||||
"plugins": ["tailwindcss"],
|
||||
"rules": {
|
||||
"tailwindcss/no-custom-classname": "off",
|
||||
"tailwindcss/classnames-order": "off"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true,
|
||||
"project": "./tsconfig.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ignorePatterns": ["**/components/ui/**"]
|
||||
}
|
||||
|
|
@ -50,17 +50,17 @@ export default function Page() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-dvh w-screen items-start pt-12 md:pt-0 md:items-center justify-center bg-background">
|
||||
<div className="w-full max-w-md overflow-hidden rounded-2xl flex flex-col gap-12">
|
||||
<div className="flex h-dvh w-screen items-start justify-center bg-background pt-12 md:items-center md:pt-0">
|
||||
<div className="flex w-full max-w-md flex-col gap-12 overflow-hidden rounded-2xl">
|
||||
<div className="flex flex-col items-center justify-center gap-2 px-4 text-center sm:px-16">
|
||||
<h3 className="text-xl font-semibold dark:text-zinc-50">Sign In</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-zinc-400">
|
||||
<h3 className="font-semibold text-xl dark:text-zinc-50">Sign In</h3>
|
||||
<p className="text-gray-500 text-sm dark:text-zinc-400">
|
||||
Use your email and password to sign in
|
||||
</p>
|
||||
</div>
|
||||
<AuthForm action={handleSubmit} defaultEmail={email}>
|
||||
<SubmitButton isSuccessful={isSuccessful}>Sign in</SubmitButton>
|
||||
<p className="text-center text-sm text-gray-600 mt-4 dark:text-zinc-400">
|
||||
<p className="mt-4 text-center text-gray-600 text-sm dark:text-zinc-400">
|
||||
{"Don't have an account? "}
|
||||
<Link
|
||||
href="/register"
|
||||
|
|
|
|||
|
|
@ -51,17 +51,17 @@ export default function Page() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-dvh w-screen items-start pt-12 md:pt-0 md:items-center justify-center bg-background">
|
||||
<div className="w-full max-w-md overflow-hidden rounded-2xl gap-12 flex flex-col">
|
||||
<div className="flex h-dvh w-screen items-start justify-center bg-background pt-12 md:items-center md:pt-0">
|
||||
<div className="flex w-full max-w-md flex-col gap-12 overflow-hidden rounded-2xl">
|
||||
<div className="flex flex-col items-center justify-center gap-2 px-4 text-center sm:px-16">
|
||||
<h3 className="text-xl font-semibold dark:text-zinc-50">Sign Up</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-zinc-400">
|
||||
<h3 className="font-semibold text-xl dark:text-zinc-50">Sign Up</h3>
|
||||
<p className="text-gray-500 text-sm dark:text-zinc-400">
|
||||
Create an account with your email and password
|
||||
</p>
|
||||
</div>
|
||||
<AuthForm action={handleSubmit} defaultEmail={email}>
|
||||
<SubmitButton isSuccessful={isSuccessful}>Sign Up</SubmitButton>
|
||||
<p className="text-center text-sm text-gray-600 mt-4 dark:text-zinc-400">
|
||||
<p className="mt-4 text-center text-gray-600 text-sm dark:text-zinc-400">
|
||||
{'Already have an account? '}
|
||||
<Link
|
||||
href="/login"
|
||||
|
|
|
|||
284
app/globals.css
284
app/globals.css
|
|
@ -1,7 +1,180 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
/* set base path to root directory to include utility classes from app, components, pages, etc. */
|
||||
@import "tailwindcss" source("..");
|
||||
|
||||
/* include utility classes in streamdown */
|
||||
@source '../node_modules/streamdown/dist/index.js';
|
||||
|
||||
/* custom variant for setting dark mode programmatically */
|
||||
@custom-variant dark (&:is(.dark, .dark *));
|
||||
|
||||
/* include plugins */
|
||||
@plugin "tailwindcss-animate";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
/* define design tokens (light mode) */
|
||||
:root {
|
||||
--background: hsl(0 0% 100%);
|
||||
--foreground: hsl(240 10% 3.9%);
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(240 10% 3.9%);
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(240 10% 3.9%);
|
||||
--primary: hsl(240 5.9% 10%);
|
||||
--primary-foreground: hsl(0 0% 98%);
|
||||
--secondary: hsl(240 4.8% 95.9%);
|
||||
--secondary-foreground: hsl(240 5.9% 10%);
|
||||
--muted: hsl(240 4.8% 95.9%);
|
||||
--muted-foreground: hsl(240 3.8% 46.1%);
|
||||
--accent: hsl(240 4.8% 95.9%);
|
||||
--accent-foreground: hsl(240 5.9% 10%);
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 5.9% 90%);
|
||||
--input: hsl(240 5.9% 90%);
|
||||
--ring: hsl(240 10% 3.9%);
|
||||
--chart-1: hsl(12 76% 61%);
|
||||
--chart-2: hsl(173 58% 39%);
|
||||
--chart-3: hsl(197 37% 24%);
|
||||
--chart-4: hsl(43 74% 66%);
|
||||
--chart-5: hsl(27 87% 67%);
|
||||
--sidebar-background: hsl(0 0% 98%);
|
||||
--sidebar-foreground: hsl(240 5.3% 26.1%);
|
||||
--sidebar-primary: hsl(240 5.9% 10%);
|
||||
--sidebar-primary-foreground: hsl(0 0% 98%);
|
||||
--sidebar-accent: hsl(240 4.8% 95.9%);
|
||||
--sidebar-accent-foreground: hsl(240 5.9% 10%);
|
||||
--sidebar-border: hsl(220 13% 91%);
|
||||
--sidebar-ring: hsl(217.2 91.2% 59.8%);
|
||||
/* border radius unit */
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* define design tokens (dark mode) */
|
||||
.dark {
|
||||
--background: hsl(240 10% 3.9%);
|
||||
--foreground: hsl(0 0% 98%);
|
||||
--card: hsl(240 10% 3.9%);
|
||||
--card-foreground: hsl(0 0% 98%);
|
||||
--popover: hsl(240 10% 3.9%);
|
||||
--popover-foreground: hsl(0 0% 98%);
|
||||
--primary: hsl(0 0% 98%);
|
||||
--primary-foreground: hsl(240 5.9% 10%);
|
||||
--secondary: hsl(240 3.7% 15.9%);
|
||||
--secondary-foreground: hsl(0 0% 98%);
|
||||
--muted: hsl(240 3.7% 15.9%);
|
||||
--muted-foreground: hsl(240 5% 64.9%);
|
||||
--accent: hsl(240 3.7% 15.9%);
|
||||
--accent-foreground: hsl(0 0% 98%);
|
||||
--destructive: hsl(0 62.8% 30.6%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 3.7% 15.9%);
|
||||
--input: hsl(240 3.7% 15.9%);
|
||||
--ring: hsl(240 4.9% 83.9%);
|
||||
--chart-1: hsl(220 70% 50%);
|
||||
--chart-2: hsl(160 60% 45%);
|
||||
--chart-3: hsl(30 80% 55%);
|
||||
--chart-4: hsl(280 65% 60%);
|
||||
--chart-5: hsl(340 75% 55%);
|
||||
--sidebar-background: hsl(240 5.9% 10%);
|
||||
--sidebar-foreground: hsl(240 4.8% 95.9%);
|
||||
--sidebar-primary: hsl(224.3 76.3% 48%);
|
||||
--sidebar-primary-foreground: hsl(0 0% 100%);
|
||||
--sidebar-accent: hsl(240 3.7% 15.9%);
|
||||
--sidebar-accent-foreground: hsl(240 4.8% 95.9%);
|
||||
--sidebar-border: hsl(240 3.7% 15.9%);
|
||||
--sidebar-ring: hsl(217.2 91.2% 59.8%);
|
||||
}
|
||||
|
||||
/* define theme */
|
||||
@theme {
|
||||
--font-sans: var(--font-geist);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
|
||||
--breakpoint-toast-mobile: 600px;
|
||||
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
|
||||
--color-sidebar: var(--sidebar-background);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
/*
|
||||
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
looks the same as it did with Tailwind CSS v3.
|
||||
|
||||
If we ever want to remove these styles, we need to add an explicit border
|
||||
color utility to any element that depends on these defaults.
|
||||
*/
|
||||
@layer base {
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentcolor);
|
||||
}
|
||||
}
|
||||
|
||||
@utility text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
@utility -webkit-overflow-scrolling-touch {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@utility touch-pan-y {
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
@utility overscroll-behavior-contain {
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
:root {
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
|
|
@ -15,95 +188,6 @@
|
|||
--background-end-rgb: 0, 0, 0;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.-webkit-overflow-scrolling-touch {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.touch-pan-y {
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
.overscroll-behavior-contain {
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 240 10% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
--sidebar-background: 0 0% 98%;
|
||||
--sidebar-foreground: 240 5.3% 26.1%;
|
||||
--sidebar-primary: 240 5.9% 10%;
|
||||
--sidebar-primary-foreground: 0 0% 98%;
|
||||
--sidebar-accent: 240 4.8% 95.9%;
|
||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||
--sidebar-border: 220 13% 91%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 224.3 76.3% 48%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
|
@ -147,22 +231,22 @@
|
|||
|
||||
.cm-editor,
|
||||
.cm-gutters {
|
||||
@apply bg-background dark:bg-zinc-800 outline-none selection:bg-zinc-900 !important;
|
||||
@apply bg-background! dark:bg-zinc-800! outline-hidden! selection:bg-zinc-900!;
|
||||
}
|
||||
|
||||
.ͼo.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground,
|
||||
.ͼo.cm-selectionBackground,
|
||||
.ͼo.cm-content::selection {
|
||||
@apply bg-zinc-200 dark:bg-zinc-900 !important;
|
||||
@apply bg-zinc-200! dark:bg-zinc-900!;
|
||||
}
|
||||
|
||||
.cm-activeLine,
|
||||
.cm-activeLineGutter {
|
||||
@apply bg-transparent !important;
|
||||
@apply bg-transparent!;
|
||||
}
|
||||
|
||||
.cm-activeLine {
|
||||
@apply rounded-r-sm !important;
|
||||
@apply rounded-r-sm!;
|
||||
}
|
||||
|
||||
.cm-lineNumbers {
|
||||
|
|
@ -174,7 +258,7 @@
|
|||
}
|
||||
|
||||
.cm-lineNumbers .cm-activeLineGutter {
|
||||
@apply rounded-l-sm !important;
|
||||
@apply rounded-l-sm!;
|
||||
}
|
||||
|
||||
.suggestion-highlight {
|
||||
|
|
@ -192,13 +276,13 @@
|
|||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: hsl(var(--border));
|
||||
background: var(--border);
|
||||
border-radius: 3px;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: hsl(var(--muted-foreground) / 0.5);
|
||||
background: --alpha(var(--muted-foreground) / 0.5);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
|
|
@ -208,5 +292,5 @@
|
|||
/* firefox scrollbar styling */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: hsl(var(--border)) transparent;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export const textArtifact = new Artifact<'text', TextArtifactMetadata>({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row py-8 md:p-20 px-4">
|
||||
<div className="flex flex-row px-4 py-8 md:p-20">
|
||||
<Editor
|
||||
content={content}
|
||||
suggestions={metadata ? metadata.suggestions : []}
|
||||
|
|
@ -88,7 +88,7 @@ export const textArtifact = new Artifact<'text', TextArtifactMetadata>({
|
|||
/>
|
||||
|
||||
{metadata?.suggestions && metadata.suggestions.length > 0 ? (
|
||||
<div className="md:hidden h-dvh w-12 shrink-0" />
|
||||
<div className="h-dvh w-12 shrink-0 md:hidden" />
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
"useArrayLiterals": "warn", // Not in recommended ruleset, turning on manually
|
||||
"noNewSymbol": "warn", // Not in recommended ruleset, turning on manually
|
||||
"useJsxKeyInIterable": "off", // Rule is buggy, revisit later
|
||||
"useExhaustiveDependencies": "off", // Community feedback on this rule has been poor, we will continue with ESLint
|
||||
"useExhaustiveDependencies": "warn", // Errors by default, switching to warn instead
|
||||
"noUnnecessaryContinue": "off" // Turned off due to developer preferences
|
||||
},
|
||||
"security": {
|
||||
|
|
@ -80,11 +80,12 @@
|
|||
"noExplicitAny": "off" // We trust Vercelians to use any only when necessary
|
||||
},
|
||||
"nursery": {
|
||||
"noStaticElementInteractions": "warn",
|
||||
"noHeadImportInDocument": "warn",
|
||||
"noDocumentImportInPage": "warn",
|
||||
"noDuplicateElseIf": "warn",
|
||||
"noHeadImportInDocument": "warn",
|
||||
"noIrregularWhitespace": "warn",
|
||||
"noStaticElementInteractions": "warn",
|
||||
"useSortedClasses": "error",
|
||||
"useValidAutocomplete": "warn"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"config": "",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true,
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ export function AppSidebar({ user }: { user: User | undefined }) {
|
|||
<Sidebar className="group-data-[side=left]:border-r-0">
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<Link
|
||||
href="/"
|
||||
onClick={() => {
|
||||
setOpenMobile(false);
|
||||
}}
|
||||
className="flex flex-row gap-3 items-center"
|
||||
className="flex flex-row items-center gap-3"
|
||||
>
|
||||
<span className="text-lg font-semibold px-2 hover:bg-muted rounded-md cursor-pointer">
|
||||
<span className="cursor-pointer rounded-md px-2 font-semibold text-lg hover:bg-muted">
|
||||
Chatbot
|
||||
</span>
|
||||
</Link>
|
||||
|
|
@ -43,7 +43,7 @@ export function AppSidebar({ user }: { user: User | undefined }) {
|
|||
<Button
|
||||
variant="ghost"
|
||||
type="button"
|
||||
className="p-1 h-8 md:p-2 md:h-fit"
|
||||
className="h-8 p-1 md:h-fit md:p-2"
|
||||
onClick={() => {
|
||||
setOpenMobile(false);
|
||||
router.push('/');
|
||||
|
|
@ -53,7 +53,9 @@ export function AppSidebar({ user }: { user: User | undefined }) {
|
|||
<PlusIcon />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent align="end" className="hidden md:block">New Chat</TooltipContent>
|
||||
<TooltipContent align="end" className="hidden md:block">
|
||||
New Chat
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</SidebarMenu>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ function PureArtifactActions({
|
|||
variant="outline"
|
||||
className={cn('h-fit dark:hover:bg-zinc-700', {
|
||||
'p-2': !action.label,
|
||||
'py-1.5 px-2': action.label,
|
||||
'px-2 py-1.5': action.label,
|
||||
})}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ function PureArtifactMessages({
|
|||
return (
|
||||
<div
|
||||
ref={messagesContainerRef}
|
||||
className="flex overflow-y-scroll flex-col gap-4 items-center px-4 pt-20 h-full"
|
||||
className="flex h-full flex-col items-center gap-4 overflow-y-scroll px-4 pt-20"
|
||||
>
|
||||
{messages.map((message, index) => (
|
||||
<PreviewMessage
|
||||
|
|
@ -71,7 +71,7 @@ function PureArtifactMessages({
|
|||
|
||||
<motion.div
|
||||
ref={messagesEndRef}
|
||||
className="shrink-0 min-w-[24px] min-h-[24px]"
|
||||
className="min-h-[24px] min-w-[24px] shrink-0"
|
||||
onViewportLeave={onViewportLeave}
|
||||
onViewportEnter={onViewportEnter}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -259,14 +259,14 @@ function PureArtifact({
|
|||
{artifact.isVisible && (
|
||||
<motion.div
|
||||
data-testid="artifact"
|
||||
className="flex flex-row h-dvh w-dvw fixed top-0 left-0 z-50 bg-transparent"
|
||||
className="fixed top-0 left-0 z-50 flex h-dvh w-dvw flex-row bg-transparent"
|
||||
initial={{ opacity: 1 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0, transition: { delay: 0.4 } }}
|
||||
>
|
||||
{!isMobile && (
|
||||
<motion.div
|
||||
className="fixed bg-background h-dvh"
|
||||
className="fixed h-dvh bg-background"
|
||||
initial={{
|
||||
width: isSidebarOpen ? windowWidth - 256 : windowWidth,
|
||||
right: 0,
|
||||
|
|
@ -281,7 +281,7 @@ function PureArtifact({
|
|||
|
||||
{!isMobile && (
|
||||
<motion.div
|
||||
className="relative w-[400px] bg-muted dark:bg-background h-dvh shrink-0"
|
||||
className="relative h-dvh w-[400px] shrink-0 bg-muted dark:bg-background"
|
||||
initial={{ opacity: 0, x: 10, scale: 1 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
|
|
@ -304,7 +304,7 @@ function PureArtifact({
|
|||
<AnimatePresence>
|
||||
{!isCurrentVersion && (
|
||||
<motion.div
|
||||
className="left-0 absolute h-dvh w-[400px] top-0 bg-zinc-900/50 z-50"
|
||||
className="absolute top-0 left-0 z-50 h-dvh w-[400px] bg-zinc-900/50"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
|
|
@ -312,7 +312,7 @@ function PureArtifact({
|
|||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="flex flex-col h-full justify-between items-center">
|
||||
<div className="flex h-full flex-col items-center justify-between">
|
||||
<ArtifactMessages
|
||||
chatId={chatId}
|
||||
status={status}
|
||||
|
|
@ -324,7 +324,7 @@ function PureArtifact({
|
|||
artifactStatus={artifact.status}
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-2 relative items-end w-full px-4 pb-4">
|
||||
<div className="relative flex w-full flex-row items-end gap-2 px-4 pb-4">
|
||||
<MultimodalInput
|
||||
chatId={chatId}
|
||||
input={input}
|
||||
|
|
@ -346,7 +346,7 @@ function PureArtifact({
|
|||
)}
|
||||
|
||||
<motion.div
|
||||
className="fixed dark:bg-muted bg-background h-dvh flex flex-col overflow-y-scroll md:border-l dark:border-zinc-700 border-zinc-200"
|
||||
className="fixed flex h-dvh flex-col overflow-y-scroll border-zinc-200 bg-background md:border-l dark:border-zinc-700 dark:bg-muted"
|
||||
initial={
|
||||
isMobile
|
||||
? {
|
||||
|
|
@ -412,19 +412,19 @@ function PureArtifact({
|
|||
},
|
||||
}}
|
||||
>
|
||||
<div className="p-2 flex flex-row justify-between items-start">
|
||||
<div className="flex flex-row gap-4 items-start">
|
||||
<div className="flex flex-row items-start justify-between p-2">
|
||||
<div className="flex flex-row items-start gap-4">
|
||||
<ArtifactCloseButton />
|
||||
|
||||
<div className="flex flex-col">
|
||||
<div className="font-medium">{artifact.title}</div>
|
||||
|
||||
{isContentDirty ? (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-muted-foreground text-sm">
|
||||
Saving changes...
|
||||
</div>
|
||||
) : document ? (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-muted-foreground text-sm">
|
||||
{`Updated ${formatDistance(
|
||||
new Date(document.createdAt),
|
||||
new Date(),
|
||||
|
|
@ -434,7 +434,7 @@ function PureArtifact({
|
|||
)}`}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-32 h-3 mt-2 bg-muted-foreground/20 rounded-md animate-pulse" />
|
||||
<div className="mt-2 h-3 w-32 animate-pulse rounded-md bg-muted-foreground/20" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -450,7 +450,7 @@ function PureArtifact({
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div className="dark:bg-muted bg-background h-full overflow-y-scroll !max-w-full items-center">
|
||||
<div className="h-full max-w-full! items-center overflow-y-scroll bg-background dark:bg-muted">
|
||||
<artifactDefinition.content
|
||||
title={artifact.title}
|
||||
content={
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function AuthForm({
|
|||
<div className="flex flex-col gap-2">
|
||||
<Label
|
||||
htmlFor="email"
|
||||
className="text-zinc-600 font-normal dark:text-zinc-400"
|
||||
className="font-normal text-zinc-600 dark:text-zinc-400"
|
||||
>
|
||||
Email Address
|
||||
</Label>
|
||||
|
|
@ -40,7 +40,7 @@ export function AuthForm({
|
|||
<div className="flex flex-col gap-2">
|
||||
<Label
|
||||
htmlFor="password"
|
||||
className="text-zinc-600 font-normal dark:text-zinc-400"
|
||||
className="font-normal text-zinc-600 dark:text-zinc-400"
|
||||
>
|
||||
Password
|
||||
</Label>
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ function PureChatHeader({
|
|||
const { width: windowWidth } = useWindowSize();
|
||||
|
||||
return (
|
||||
<header className="flex sticky top-0 bg-background py-1.5 items-center px-2 md:px-2 gap-2">
|
||||
<header className="sticky top-0 flex items-center gap-2 bg-background px-2 py-1.5 md:px-2">
|
||||
<SidebarToggle />
|
||||
|
||||
{(!open || windowWidth < 768) && (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="order-2 md:order-1 md:px-2 px-2 md:h-fit ml-auto md:ml-0"
|
||||
className="order-2 ml-auto px-2 md:order-1 md:ml-0 md:h-fit md:px-2"
|
||||
onClick={() => {
|
||||
router.push('/');
|
||||
router.refresh();
|
||||
|
|
@ -55,7 +55,7 @@ function PureChatHeader({
|
|||
)}
|
||||
|
||||
<Button
|
||||
className="bg-zinc-900 dark:bg-zinc-100 hover:bg-zinc-800 dark:hover:bg-zinc-200 text-zinc-50 dark:text-zinc-900 hidden md:flex py-1.5 px-2 h-fit md:h-[34px] order-3 md:ml-auto"
|
||||
className="order-3 hidden h-fit bg-zinc-900 px-2 py-1.5 text-zinc-50 hover:bg-zinc-800 md:ml-auto md:flex md:h-[34px] dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
|
||||
asChild
|
||||
>
|
||||
<Link
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ export function Chat({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col min-w-0 h-dvh bg-background touch-pan-y overscroll-behavior-contain">
|
||||
<div className="overscroll-behavior-contain flex h-dvh min-w-0 touch-pan-y flex-col bg-background">
|
||||
<ChatHeader
|
||||
chatId={id}
|
||||
selectedVisibilityType={initialVisibilityType}
|
||||
|
|
@ -156,7 +156,7 @@ export function Chat({
|
|||
selectedModelId={initialChatModel}
|
||||
/>
|
||||
|
||||
<div className="sticky bottom-0 flex gap-2 px-2 md:px-4 pb-3 md:pb-4 mx-auto w-full bg-background max-w-4xl z-[1] border-t-0">
|
||||
<div className="sticky bottom-0 z-1 mx-auto flex w-full max-w-4xl gap-2 border-t-0 bg-background px-2 pb-3 md:px-4 md:pb-4">
|
||||
{!isReadonly && (
|
||||
<MultimodalInput
|
||||
chatId={id}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ function PureCodeEditor({ content, onSaveContent, status }: EditorProps) {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="relative not-prose w-full pb-[calc(80dvh)] text-sm"
|
||||
className="not-prose relative w-full pb-[calc(80dvh)] text-sm"
|
||||
ref={containerRef}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
return consoleOutputs.length > 0 ? (
|
||||
<>
|
||||
<div
|
||||
className="fixed z-50 w-full h-2 cursor-ns-resize"
|
||||
className="fixed z-50 h-2 w-full cursor-ns-resize"
|
||||
onMouseDown={startResizing}
|
||||
style={{ bottom: height - 4 }}
|
||||
role="slider"
|
||||
|
|
@ -89,15 +89,15 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
|
||||
<div
|
||||
className={cn(
|
||||
'flex overflow-x-hidden overflow-y-scroll fixed bottom-0 z-40 flex-col w-full border-t dark:bg-zinc-900 bg-zinc-50 dark:border-zinc-700 border-zinc-200',
|
||||
'fixed bottom-0 z-40 flex w-full flex-col overflow-x-hidden overflow-y-scroll border-zinc-200 border-t bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900',
|
||||
{
|
||||
'select-none': isResizing,
|
||||
},
|
||||
)}
|
||||
style={{ height }}
|
||||
>
|
||||
<div className="flex sticky top-0 z-50 flex-row justify-between items-center px-2 py-1 w-full border-b h-fit dark:border-zinc-700 border-zinc-200 bg-muted">
|
||||
<div className="flex flex-row gap-3 items-center pl-2 text-sm dark:text-zinc-50 text-zinc-800">
|
||||
<div className="sticky top-0 z-50 flex h-fit w-full flex-row items-center justify-between border-zinc-200 border-b bg-muted px-2 py-1 dark:border-zinc-700">
|
||||
<div className="flex flex-row items-center gap-3 pl-2 text-sm text-zinc-800 dark:text-zinc-50">
|
||||
<div className="text-muted-foreground">
|
||||
<TerminalWindowIcon />
|
||||
</div>
|
||||
|
|
@ -105,7 +105,7 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="p-1 size-fit hover:dark:bg-zinc-700 hover:bg-zinc-200"
|
||||
className="size-fit p-1 hover:bg-zinc-200 dark:hover:bg-zinc-700"
|
||||
size="icon"
|
||||
onClick={() => setConsoleOutputs([])}
|
||||
>
|
||||
|
|
@ -117,7 +117,7 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
{consoleOutputs.map((consoleOutput, index) => (
|
||||
<div
|
||||
key={consoleOutput.id}
|
||||
className="flex flex-row px-4 py-2 font-mono text-sm border-b dark:border-zinc-700 border-zinc-200 dark:bg-zinc-900 bg-zinc-50"
|
||||
className="flex flex-row border-zinc-200 border-b bg-zinc-50 px-4 py-2 font-mono text-sm dark:border-zinc-700 dark:bg-zinc-900"
|
||||
>
|
||||
<div
|
||||
className={cn('w-12 shrink-0', {
|
||||
|
|
@ -135,7 +135,7 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
consoleOutput.status,
|
||||
) ? (
|
||||
<div className="flex flex-row gap-2">
|
||||
<div className="size-fit self-center mb-auto mt-0.5">
|
||||
<div className="mt-0.5 mb-auto size-fit self-center">
|
||||
<Loader size={16} />
|
||||
</div>
|
||||
<div className="text-muted-foreground">
|
||||
|
|
@ -149,14 +149,14 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex overflow-x-scroll flex-col gap-2 w-full dark:text-zinc-50 text-zinc-900">
|
||||
<div className="flex w-full flex-col gap-2 overflow-x-scroll text-zinc-900 dark:text-zinc-50">
|
||||
{consoleOutput.contents.map((content, index) =>
|
||||
content.type === 'image' ? (
|
||||
<picture key={`${consoleOutput.id}-${index}`}>
|
||||
<img
|
||||
src={content.value}
|
||||
alt="output"
|
||||
className="w-full rounded-md max-w-screen-toast-mobile"
|
||||
className="w-full max-w-(--breakpoint-toast-mobile) rounded-md"
|
||||
/>
|
||||
</picture>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -118,23 +118,23 @@ export function DocumentPreview({
|
|||
|
||||
const LoadingSkeleton = ({ artifactKind }: { artifactKind: ArtifactKind }) => (
|
||||
<div className="w-full">
|
||||
<div className="p-4 border rounded-t-2xl flex flex-row gap-2 items-center justify-between dark:bg-muted h-[57px] dark:border-zinc-700 border-b-0">
|
||||
<div className="flex h-[57px] flex-row items-center justify-between gap-2 rounded-t-2xl border border-b-0 p-4 dark:border-zinc-700 dark:bg-muted">
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<div className="text-muted-foreground">
|
||||
<div className="animate-pulse rounded-md size-4 bg-muted-foreground/20" />
|
||||
<div className="size-4 animate-pulse rounded-md bg-muted-foreground/20" />
|
||||
</div>
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-24" />
|
||||
<div className="h-4 w-24 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
</div>
|
||||
<div>
|
||||
<FullscreenIcon />
|
||||
</div>
|
||||
</div>
|
||||
{artifactKind === 'image' ? (
|
||||
<div className="overflow-y-scroll border rounded-b-2xl bg-muted border-t-0 dark:border-zinc-700">
|
||||
<div className="animate-pulse h-[257px] bg-muted-foreground/20 w-full" />
|
||||
<div className="overflow-y-scroll rounded-b-2xl border border-t-0 bg-muted dark:border-zinc-700">
|
||||
<div className="h-[257px] w-full animate-pulse bg-muted-foreground/20" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="overflow-y-scroll border rounded-b-2xl p-8 pt-4 bg-muted border-t-0 dark:border-zinc-700">
|
||||
<div className="overflow-y-scroll rounded-b-2xl border border-t-0 bg-muted p-8 pt-4 dark:border-zinc-700">
|
||||
<InlineDocumentSkeleton />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -179,14 +179,14 @@ const PureHitboxLayer = ({
|
|||
|
||||
return (
|
||||
<div
|
||||
className="size-full absolute top-0 left-0 rounded-xl z-10"
|
||||
className="absolute top-0 left-0 z-10 size-full rounded-xl"
|
||||
ref={hitboxRef}
|
||||
onClick={handleClick}
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div className="w-full p-4 flex justify-end items-center">
|
||||
<div className="absolute right-[9px] top-[13px] p-2 hover:dark:bg-zinc-700 rounded-md hover:bg-zinc-100">
|
||||
<div className="flex w-full items-center justify-end p-4">
|
||||
<div className="absolute top-[13px] right-[9px] rounded-md p-2 hover:bg-zinc-100 dark:hover:bg-zinc-700">
|
||||
<FullscreenIcon />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -208,8 +208,8 @@ const PureDocumentHeader = ({
|
|||
kind: ArtifactKind;
|
||||
isStreaming: boolean;
|
||||
}) => (
|
||||
<div className="p-4 border rounded-t-2xl flex flex-row gap-2 items-start sm:items-center justify-between dark:bg-muted border-b-0 dark:border-zinc-700">
|
||||
<div className="flex flex-row items-start sm:items-center gap-3">
|
||||
<div className="flex flex-row items-start justify-between gap-2 rounded-t-2xl border border-b-0 p-4 sm:items-center dark:border-zinc-700 dark:bg-muted">
|
||||
<div className="flex flex-row items-start gap-3 sm:items-center">
|
||||
<div className="text-muted-foreground">
|
||||
{isStreaming ? (
|
||||
<div className="animate-spin">
|
||||
|
|
@ -221,7 +221,7 @@ const PureDocumentHeader = ({
|
|||
<FileIcon />
|
||||
)}
|
||||
</div>
|
||||
<div className="-translate-y-1 sm:translate-y-0 font-medium">{title}</div>
|
||||
<div className="-translate-y-1 font-medium sm:translate-y-0">{title}</div>
|
||||
</div>
|
||||
<div className="w-8" />
|
||||
</div>
|
||||
|
|
@ -259,13 +259,13 @@ const DocumentContent = ({ document }: { document: Document }) => {
|
|||
{document.kind === 'text' ? (
|
||||
<Editor {...commonProps} onSaveContent={() => {}} />
|
||||
) : document.kind === 'code' ? (
|
||||
<div className="flex flex-1 relative w-full">
|
||||
<div className="relative flex w-full flex-1">
|
||||
<div className="absolute inset-0">
|
||||
<CodeEditor {...commonProps} onSaveContent={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
) : document.kind === 'sheet' ? (
|
||||
<div className="flex flex-1 relative size-full p-4">
|
||||
<div className="relative flex size-full flex-1 p-4">
|
||||
<div className="absolute inset-0">
|
||||
<SpreadsheetEditor {...commonProps} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,32 +8,32 @@ export const DocumentSkeleton = ({
|
|||
artifactKind: ArtifactKind;
|
||||
}) => {
|
||||
return artifactKind === 'image' ? (
|
||||
<div className="flex flex-col gap-4 w-full justify-center items-center h-[calc(100dvh-60px)]">
|
||||
<div className="animate-pulse rounded-lg bg-muted-foreground/20 size-96" />
|
||||
<div className="flex h-[calc(100dvh-60px)] w-full flex-col items-center justify-center gap-4">
|
||||
<div className="size-96 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="animate-pulse rounded-lg h-12 bg-muted-foreground/20 w-1/2" />
|
||||
<div className="animate-pulse rounded-lg h-5 bg-muted-foreground/20 w-full" />
|
||||
<div className="animate-pulse rounded-lg h-5 bg-muted-foreground/20 w-full" />
|
||||
<div className="animate-pulse rounded-lg h-5 bg-muted-foreground/20 w-1/3" />
|
||||
<div className="animate-pulse rounded-lg h-5 bg-transparent w-52" />
|
||||
<div className="animate-pulse rounded-lg h-8 bg-muted-foreground/20 w-52" />
|
||||
<div className="animate-pulse rounded-lg h-5 bg-muted-foreground/20 w-2/3" />
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<div className="h-12 w-1/2 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-5 w-full animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-5 w-full animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-5 w-1/3 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-5 w-52 animate-pulse rounded-lg bg-transparent" />
|
||||
<div className="h-8 w-52 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-5 w-2/3 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const InlineDocumentSkeleton = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-48" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-3/4" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-1/2" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-64" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-40" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-36" />
|
||||
<div className="animate-pulse rounded-lg h-4 bg-muted-foreground/20 w-64" />
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<div className="h-4 w-48 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-3/4 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-1/2 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-64 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-40 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-36 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
<div className="h-4 w-64 animate-pulse rounded-lg bg-muted-foreground/20" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ function PureDocumentToolResult({
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="bg-background cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
|
||||
className="flex w-fit cursor-pointer flex-row items-start gap-3 rounded-xl border bg-background px-3 py-2"
|
||||
onClick={(event) => {
|
||||
if (isReadonly) {
|
||||
toast.error(
|
||||
|
|
@ -68,7 +68,7 @@ function PureDocumentToolResult({
|
|||
});
|
||||
}}
|
||||
>
|
||||
<div className="text-muted-foreground mt-1">
|
||||
<div className="mt-1 text-muted-foreground">
|
||||
{type === 'create' ? (
|
||||
<FileIcon />
|
||||
) : type === 'update' ? (
|
||||
|
|
@ -105,7 +105,7 @@ function PureDocumentToolCall({
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="cursor pointer w-fit border py-2 px-3 rounded-xl flex flex-row items-start justify-between gap-3"
|
||||
className="cursor pointer flex w-fit flex-row items-start justify-between gap-3 rounded-xl border px-3 py-2"
|
||||
onClick={(event) => {
|
||||
if (isReadonly) {
|
||||
toast.error(
|
||||
|
|
@ -130,8 +130,8 @@ function PureDocumentToolCall({
|
|||
}));
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-3 items-start">
|
||||
<div className="text-zinc-500 mt-1">
|
||||
<div className="flex flex-row items-start gap-3">
|
||||
<div className="mt-1 text-zinc-500">
|
||||
{type === 'create' ? (
|
||||
<FileIcon />
|
||||
) : type === 'update' ? (
|
||||
|
|
@ -154,7 +154,7 @@ function PureDocumentToolCall({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="animate-spin mt-1">{<LoaderIcon />}</div>
|
||||
<div className="mt-1 animate-spin">{<LoaderIcon />}</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type { ComponentProps } from 'react';
|
|||
export type ActionsProps = ComponentProps<'div'>;
|
||||
|
||||
export const Actions = ({ className, children, ...props }: ActionsProps) => (
|
||||
<div className={cn('flex gap-1 items-center', className)} {...props}>
|
||||
<div className={cn('flex items-center gap-1', className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -35,7 +35,7 @@ export const Action = ({
|
|||
const button = (
|
||||
<Button
|
||||
className={cn(
|
||||
'size-9 p-1.5 text-muted-foreground hover:text-foreground relative',
|
||||
'relative size-9 p-1.5 text-muted-foreground hover:text-foreground',
|
||||
className,
|
||||
)}
|
||||
size={size}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export type ConversationProps = ComponentProps<typeof StickToBottom>;
|
|||
export const Conversation = ({ className, ...props }: ConversationProps) => (
|
||||
<StickToBottom
|
||||
className={cn(
|
||||
'overflow-y-auto relative flex-1 touch-pan-y will-change-scroll',
|
||||
'relative flex-1 touch-pan-y overflow-y-auto will-change-scroll',
|
||||
className,
|
||||
)}
|
||||
initial="smooth"
|
||||
|
|
@ -49,7 +49,7 @@ export const ConversationScrollButton = ({
|
|||
!isAtBottom && (
|
||||
<Button
|
||||
className={cn(
|
||||
'absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full z-10 shadow-lg',
|
||||
'-translate-x-1/2 absolute bottom-4 left-1/2 z-10 rounded-full shadow-lg',
|
||||
className,
|
||||
)}
|
||||
onClick={handleScrollToBottom}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export type PromptInputProps = HTMLAttributes<HTMLFormElement>;
|
|||
export const PromptInput = ({ className, ...props }: PromptInputProps) => (
|
||||
<form
|
||||
className={cn(
|
||||
'w-full overflow-hidden rounded-xl border bg-background shadow-sm',
|
||||
'w-full overflow-hidden rounded-xl border bg-background shadow-xs',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -72,8 +72,12 @@ export const PromptInputTextarea = ({
|
|||
return (
|
||||
<Textarea
|
||||
className={cn(
|
||||
'w-full resize-none rounded-none border-none p-3 shadow-none outline-none ring-0',
|
||||
disableAutoResize ? 'field-sizing-fixed' : resizeOnNewLinesOnly ? 'field-sizing-fixed' : 'field-sizing-content max-h-[6lh]',
|
||||
'w-full resize-none rounded-none border-none p-3 shadow-none outline-hidden ring-0',
|
||||
disableAutoResize
|
||||
? 'field-sizing-fixed'
|
||||
: resizeOnNewLinesOnly
|
||||
? 'field-sizing-fixed'
|
||||
: 'field-sizing-content max-h-[6lh]',
|
||||
'bg-transparent dark:bg-transparent',
|
||||
'focus-visible:ring-0',
|
||||
className,
|
||||
|
|
@ -196,7 +200,7 @@ export const PromptInputModelSelectTrigger = ({
|
|||
<SelectTrigger
|
||||
className={cn(
|
||||
'border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors',
|
||||
'hover:bg-accent hover:text-foreground [&[aria-expanded="true"]]:bg-accent [&[aria-expanded="true"]]:text-foreground',
|
||||
'hover:bg-accent hover:text-foreground aria-expanded:bg-accent aria-expanded:text-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ export const ReasoningTrigger = memo(
|
|||
return (
|
||||
<CollapsibleTrigger
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 text-muted-foreground text-xs hover:text-foreground transition-colors',
|
||||
'flex items-center gap-1.5 text-muted-foreground text-xs transition-colors hover:text-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -155,8 +155,8 @@ export const ReasoningContent = memo(
|
|||
({ className, children, ...props }: ReasoningContentProps) => (
|
||||
<CollapsibleContent
|
||||
className={cn(
|
||||
'mt-2 text-xs text-muted-foreground',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
'mt-2 text-muted-foreground text-xs',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const Response = memo(
|
|||
({ className, ...props }: ResponseProps) => (
|
||||
<Streamdown
|
||||
className={cn(
|
||||
'size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_pre]:overflow-x-auto [&_pre]:max-w-full [&_code]:break-words [&_code]:whitespace-pre-wrap',
|
||||
'size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_code]:whitespace-pre-wrap [&_code]:break-words [&_pre]:max-w-full [&_pre]:overflow-x-auto',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const SourcesContent = ({
|
|||
<CollapsibleContent
|
||||
className={cn(
|
||||
'mt-3 flex w-fit flex-col gap-2',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export const TaskContent = ({
|
|||
}: TaskContentProps) => (
|
||||
<CollapsibleContent
|
||||
className={cn(
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,10 @@ const getStatusBadge = (status: ToolUIPart['state']) => {
|
|||
} as const;
|
||||
|
||||
return (
|
||||
<Badge className="rounded-full text-xs flex items-center gap-1" variant="secondary">
|
||||
<Badge
|
||||
className="flex items-center gap-1 rounded-full text-xs"
|
||||
variant="secondary"
|
||||
>
|
||||
{icons[status]}
|
||||
<span>{labels[status]}</span>
|
||||
</Badge>
|
||||
|
|
@ -65,16 +68,16 @@ export const ToolHeader = ({
|
|||
}: ToolHeaderProps) => (
|
||||
<CollapsibleTrigger
|
||||
className={cn(
|
||||
'flex w-full items-center justify-between gap-2 p-3 min-w-0',
|
||||
'flex w-full min-w-0 items-center justify-between gap-2 p-3',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||
<WrenchIcon className="size-4 text-muted-foreground shrink-0" />
|
||||
<span className="font-medium text-sm truncate">{type}</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<WrenchIcon className="size-4 shrink-0 text-muted-foreground" />
|
||||
<span className="truncate font-medium text-sm">{type}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
{getStatusBadge(state)}
|
||||
<ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
|
||||
</div>
|
||||
|
|
@ -86,7 +89,7 @@ export type ToolContentProps = ComponentProps<typeof CollapsibleContent>;
|
|||
export const ToolContent = ({ className, ...props }: ToolContentProps) => (
|
||||
<CollapsibleContent
|
||||
className={cn(
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ export const WebPreviewConsole = ({
|
|||
<CollapsibleContent
|
||||
className={cn(
|
||||
'px-4 pb-4',
|
||||
'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 outline-none data-[state=closed]:animate-out 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 outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
)}
|
||||
>
|
||||
<div className="max-h-48 space-y-1 overflow-y-auto">
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ export const Greeting = () => {
|
|||
return (
|
||||
<div
|
||||
key="overview"
|
||||
className="max-w-3xl mx-auto mt-4 md:mt-16 px-4 md:px-8 size-full flex flex-col justify-center"
|
||||
className="mx-auto mt-4 flex size-full max-w-3xl flex-col justify-center px-4 md:mt-16 md:px-8"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ delay: 0.5 }}
|
||||
className="text-xl md:text-2xl font-semibold"
|
||||
className="font-semibold text-xl md:text-2xl"
|
||||
>
|
||||
Hello there!
|
||||
</motion.div>
|
||||
|
|
@ -20,7 +20,7 @@ export const Greeting = () => {
|
|||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ delay: 0.6 }}
|
||||
className="text-xl md:text-2xl text-zinc-500"
|
||||
className="text-xl text-zinc-500 md:text-2xl"
|
||||
>
|
||||
How can I help you today?
|
||||
</motion.div>
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ export function ImageEditor({
|
|||
}: ImageEditorProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn('flex flex-row items-center justify-center w-full', {
|
||||
className={cn('flex w-full flex-row items-center justify-center', {
|
||||
'h-[calc(100dvh-60px)]': !isInline,
|
||||
'h-[200px]': isInline,
|
||||
})}
|
||||
>
|
||||
{status === 'streaming' ? (
|
||||
<div className="flex flex-row gap-4 items-center">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{!isInline && (
|
||||
<div className="animate-spin">
|
||||
<LoaderIcon />
|
||||
|
|
@ -35,7 +35,7 @@ export function ImageEditor({
|
|||
) : (
|
||||
<picture>
|
||||
<img
|
||||
className={cn('w-full h-fit max-w-[800px]', {
|
||||
className={cn('h-fit w-full max-w-[800px]', {
|
||||
'p-0 md:p-20': !isInline,
|
||||
})}
|
||||
src={`data:image/png;base64,${content}`}
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ export function PureMessageActions({
|
|||
// User messages get edit (on hover) and copy actions
|
||||
if (message.role === 'user') {
|
||||
return (
|
||||
<Actions className="justify-end -mr-0.5">
|
||||
<Actions className="-mr-0.5 justify-end">
|
||||
<div className="relative">
|
||||
{setMode && (
|
||||
<Action
|
||||
tooltip="Edit"
|
||||
onClick={() => setMode('edit')}
|
||||
className="absolute top-0 -left-10 opacity-0 transition-opacity group-hover/message:opacity-100"
|
||||
className="-left-10 absolute top-0 opacity-0 transition-opacity group-hover/message:opacity-100"
|
||||
>
|
||||
<PencilEditIcon />
|
||||
</Action>
|
||||
|
|
|
|||
|
|
@ -53,19 +53,19 @@ export function MessageEditor({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<Textarea
|
||||
data-testid="message-editor"
|
||||
ref={textareaRef}
|
||||
className="bg-transparent outline-none overflow-hidden resize-none !text-base rounded-xl w-full"
|
||||
className="w-full resize-none overflow-hidden rounded-xl bg-transparent text-base! outline-hidden"
|
||||
value={draftContent}
|
||||
onChange={handleInput}
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-2 justify-end">
|
||||
<div className="flex flex-row justify-end gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-fit py-2 px-3"
|
||||
className="h-fit px-3 py-2"
|
||||
onClick={() => {
|
||||
setMode('view');
|
||||
}}
|
||||
|
|
@ -75,7 +75,7 @@ export function MessageEditor({
|
|||
<Button
|
||||
data-testid="message-editor-send-button"
|
||||
variant="default"
|
||||
className="h-fit py-2 px-3"
|
||||
className="h-fit px-3 py-2"
|
||||
disabled={isSubmitting}
|
||||
onClick={async () => {
|
||||
setIsSubmitting(true);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import { Reasoning, ReasoningTrigger, ReasoningContent } from './elements/reasoning';
|
||||
import {
|
||||
Reasoning,
|
||||
ReasoningTrigger,
|
||||
ReasoningContent,
|
||||
} from './elements/reasoning';
|
||||
|
||||
interface MessageReasoningProps {
|
||||
isLoading: boolean;
|
||||
|
|
|
|||
|
|
@ -57,19 +57,19 @@ const PurePreviewMessage = ({
|
|||
return (
|
||||
<motion.div
|
||||
data-testid={`message-${message.role}`}
|
||||
className="w-full group/message"
|
||||
className="group/message w-full"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
data-role={message.role}
|
||||
>
|
||||
<div
|
||||
className={cn('flex items-start gap-3 w-full', {
|
||||
className={cn('flex w-full items-start gap-3', {
|
||||
'justify-end': message.role === 'user' && mode !== 'edit',
|
||||
'justify-start': message.role === 'assistant',
|
||||
})}
|
||||
>
|
||||
{message.role === 'assistant' && (
|
||||
<div className="flex justify-center items-center -mt-1 rounded-full ring-1 size-8 shrink-0 ring-border bg-background">
|
||||
<div className="-mt-1 flex size-8 shrink-0 items-center justify-center rounded-full bg-background ring-1 ring-border">
|
||||
<SparklesIcon size={14} />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -93,7 +93,7 @@ const PurePreviewMessage = ({
|
|||
{attachmentsFromMessage.length > 0 && (
|
||||
<div
|
||||
data-testid={`message-attachments`}
|
||||
className="flex flex-row gap-2 justify-end"
|
||||
className="flex flex-row justify-end gap-2"
|
||||
>
|
||||
{attachmentsFromMessage.map((attachment) => (
|
||||
<PreviewAttachment
|
||||
|
|
@ -129,7 +129,7 @@ const PurePreviewMessage = ({
|
|||
<MessageContent
|
||||
data-testid="message-content"
|
||||
className={cn({
|
||||
'rounded-2xl px-3 py-2 break-words text-white text-right w-fit':
|
||||
'w-fit break-words rounded-2xl px-3 py-2 text-right text-white':
|
||||
message.role === 'user',
|
||||
'bg-transparent px-0 py-0 text-left':
|
||||
message.role === 'assistant',
|
||||
|
|
@ -150,10 +150,10 @@ const PurePreviewMessage = ({
|
|||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="flex flex-row gap-3 items-start w-full"
|
||||
className="flex w-full flex-row items-start gap-3"
|
||||
>
|
||||
<div className="size-8" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<MessageEditor
|
||||
key={message.id}
|
||||
message={message}
|
||||
|
|
@ -195,7 +195,7 @@ const PurePreviewMessage = ({
|
|||
return (
|
||||
<div
|
||||
key={toolCallId}
|
||||
className="p-4 text-red-500 bg-red-50 rounded-lg border border-red-200 dark:bg-red-950/50"
|
||||
className="rounded-lg border border-red-200 bg-red-50 p-4 text-red-500 dark:bg-red-950/50"
|
||||
>
|
||||
Error creating document: {String(part.output.error)}
|
||||
</div>
|
||||
|
|
@ -218,7 +218,7 @@ const PurePreviewMessage = ({
|
|||
return (
|
||||
<div
|
||||
key={toolCallId}
|
||||
className="p-4 text-red-500 bg-red-50 rounded-lg border border-red-200 dark:bg-red-950/50"
|
||||
className="rounded-lg border border-red-200 bg-red-50 p-4 text-red-500 dark:bg-red-950/50"
|
||||
>
|
||||
Error updating document: {String(part.output.error)}
|
||||
</div>
|
||||
|
|
@ -250,7 +250,7 @@ const PurePreviewMessage = ({
|
|||
<ToolOutput
|
||||
output={
|
||||
'error' in part.output ? (
|
||||
<div className="p-2 text-red-500 rounded border">
|
||||
<div className="rounded border p-2 text-red-500">
|
||||
Error: {String(part.output.error)}
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -306,17 +306,17 @@ export const ThinkingMessage = () => {
|
|||
return (
|
||||
<motion.div
|
||||
data-testid="message-assistant-loading"
|
||||
className="w-full group/message"
|
||||
className="group/message w-full"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
data-role={role}
|
||||
>
|
||||
<div className="flex gap-3 justify-start items-start">
|
||||
<div className="flex justify-center items-center -mt-1 rounded-full ring-1 size-8 shrink-0 ring-border bg-background">
|
||||
<div className="flex items-start justify-start gap-3">
|
||||
<div className="-mt-1 flex size-8 shrink-0 items-center justify-center rounded-full bg-background ring-1 ring-border">
|
||||
<SparklesIcon size={14} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 w-full md:gap-4">
|
||||
<div className="flex w-full flex-col gap-2 md:gap-4">
|
||||
<div className="p-0 text-sm text-muted-foreground">
|
||||
<LoadingText>Thinking...</LoadingText>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ function PureMessages({
|
|||
if (container) {
|
||||
container.scrollTo({
|
||||
top: container.scrollHeight,
|
||||
behavior: 'smooth'
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -63,7 +63,7 @@ function PureMessages({
|
|||
return (
|
||||
<div
|
||||
ref={messagesContainerRef}
|
||||
className="overflow-y-scroll flex-1 touch-pan-y overscroll-behavior-contain -webkit-overflow-scrolling-touch"
|
||||
className="overscroll-behavior-contain -webkit-overflow-scrolling-touch flex-1 touch-pan-y overflow-y-scroll"
|
||||
style={{ overflowAnchor: 'none' }}
|
||||
>
|
||||
<Conversation className="flex flex-col gap-4 px-2 py-4 mx-auto min-w-0 max-w-4xl md:gap-6 md:px-4">
|
||||
|
|
@ -96,20 +96,18 @@ function PureMessages({
|
|||
{status === 'submitted' &&
|
||||
messages.length > 0 &&
|
||||
messages[messages.length - 1].role === 'user' &&
|
||||
selectedModelId !== 'chat-model-reasoning' && (
|
||||
<ThinkingMessage />
|
||||
)}
|
||||
selectedModelId !== 'chat-model-reasoning' && <ThinkingMessage />}
|
||||
|
||||
<div
|
||||
ref={messagesEndRef}
|
||||
className="shrink-0 min-w-[24px] min-h-[24px]"
|
||||
className="min-h-[24px] min-w-[24px] shrink-0"
|
||||
/>
|
||||
</ConversationContent>
|
||||
</Conversation>
|
||||
|
||||
{!isAtBottom && (
|
||||
<button
|
||||
className="absolute bottom-40 left-1/2 z-10 p-2 rounded-full border shadow-lg transition-colors -translate-x-1/2 bg-background hover:bg-muted"
|
||||
className="-translate-x-1/2 absolute bottom-40 left-1/2 z-10 rounded-full border bg-background p-2 shadow-lg transition-colors hover:bg-muted"
|
||||
onClick={() => scrollToBottom('smooth')}
|
||||
type="button"
|
||||
aria-label="Scroll to bottom"
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export function ModelSelector({
|
|||
<Button
|
||||
data-testid="model-selector"
|
||||
variant="outline"
|
||||
className="md:px-2 md:h-[34px]"
|
||||
className="md:h-[34px] md:px-2"
|
||||
>
|
||||
{selectedChatModel?.name}
|
||||
<ChevronDownIcon />
|
||||
|
|
@ -83,16 +83,16 @@ export function ModelSelector({
|
|||
>
|
||||
<button
|
||||
type="button"
|
||||
className="gap-4 group/item flex flex-row justify-between items-center w-full"
|
||||
className="group/item flex w-full flex-row items-center justify-between gap-4"
|
||||
>
|
||||
<div className="flex flex-col gap-1 items-start">
|
||||
<div className="flex flex-col items-start gap-1">
|
||||
<div>{chatModel.name}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<div className="text-muted-foreground text-xs">
|
||||
{chatModel.description}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-foreground dark:text-foreground opacity-0 group-data-[active=true]/item:opacity-100">
|
||||
<div className="text-foreground opacity-0 group-data-[active=true]/item:opacity-100 dark:text-foreground">
|
||||
<CheckCircleFillIcon />
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
PromptInputModelSelectTrigger,
|
||||
PromptInputModelSelectContent,
|
||||
} from './elements/prompt-input';
|
||||
import { SelectItem, } from '@/components/ui/select';
|
||||
import { SelectItem } from '@/components/ui/select';
|
||||
import equal from 'fast-deep-equal';
|
||||
import type { UseChatHelpers } from '@ai-sdk/react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
|
@ -253,7 +253,7 @@ function PureMultimodalInput({
|
|||
}, [status, scrollToBottom]);
|
||||
|
||||
return (
|
||||
<div className="flex relative flex-col gap-4 w-full">
|
||||
<div className="relative flex w-full flex-col gap-4">
|
||||
<AnimatePresence>
|
||||
{!isAtBottom && (
|
||||
<motion.div
|
||||
|
|
@ -261,7 +261,7 @@ function PureMultimodalInput({
|
|||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
|
||||
className="absolute -top-12 left-1/2 z-50 -translate-x-1/2"
|
||||
className="-top-12 -translate-x-1/2 absolute left-1/2 z-50"
|
||||
>
|
||||
<Button
|
||||
data-testid="scroll-to-bottom-button"
|
||||
|
|
@ -291,7 +291,7 @@ function PureMultimodalInput({
|
|||
|
||||
<input
|
||||
type="file"
|
||||
className="fixed -top-4 -left-4 size-0.5 opacity-0 pointer-events-none"
|
||||
className="-top-4 -left-4 pointer-events-none fixed size-0.5 opacity-0"
|
||||
ref={fileInputRef}
|
||||
multiple
|
||||
onChange={handleFileChange}
|
||||
|
|
@ -299,7 +299,7 @@ function PureMultimodalInput({
|
|||
/>
|
||||
|
||||
<PromptInput
|
||||
className="rounded-xl border shadow-sm transition-all duration-200 bg-background border-border focus-within:border-border hover:border-muted-foreground/50"
|
||||
className="rounded-xl border border-border bg-background shadow-xs transition-all duration-200 focus-within:border-border hover:border-muted-foreground/50"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (status !== 'ready') {
|
||||
|
|
@ -312,7 +312,7 @@ function PureMultimodalInput({
|
|||
{(attachments.length > 0 || uploadQueue.length > 0) && (
|
||||
<div
|
||||
data-testid="attachments-preview"
|
||||
className="flex overflow-x-scroll flex-row gap-2 items-end px-3 py-2"
|
||||
className="flex flex-row items-end gap-2 overflow-x-scroll px-3 py-2"
|
||||
>
|
||||
{attachments.map((attachment) => (
|
||||
<PreviewAttachment
|
||||
|
|
@ -352,13 +352,13 @@ function PureMultimodalInput({
|
|||
minHeight={44}
|
||||
maxHeight={200}
|
||||
disableAutoResize={true}
|
||||
className="text-sm flex-grow resize-none py-3 px-3 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] bg-transparent !border-0 !border-none outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none placeholder:text-muted-foreground"
|
||||
className="text-sm grow resize-none py-3 px-3 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] bg-transparent border-0! border-none! outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-none placeholder:text-muted-foreground"
|
||||
rows={1}
|
||||
autoFocus
|
||||
/>{' '}
|
||||
<Context {...contextProps} />
|
||||
</div>
|
||||
<PromptInputToolbar className="px-3 py-2 !border-t-0 !border-top-0 shadow-none dark:!border-transparent dark:border-0">
|
||||
<PromptInputToolbar className="px-3 py-2 border-t-0! !border-top-0 shadow-none dark:border-transparent! dark:border-0">
|
||||
<PromptInputTools className="gap-2">
|
||||
<AttachmentsButton
|
||||
fileInputRef={fileInputRef}
|
||||
|
|
@ -374,7 +374,7 @@ function PureMultimodalInput({
|
|||
<PromptInputSubmit
|
||||
status={status}
|
||||
disabled={!input.trim() || uploadQueue.length > 0}
|
||||
className="p-2 rounded-full transition-colors duration-200 text-primary-foreground bg-primary hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground"
|
||||
className="rounded-full bg-primary p-2 text-primary-foreground transition-colors duration-200 hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground"
|
||||
>
|
||||
<ArrowUpIcon size={16} />
|
||||
</PromptInputSubmit>
|
||||
|
|
@ -413,7 +413,7 @@ function PureAttachmentsButton({
|
|||
return (
|
||||
<Button
|
||||
data-testid="attachments-button"
|
||||
className="rounded-md p-1.5 h-fit hover:bg-muted transition-colors duration-200"
|
||||
className="h-fit rounded-md p-1.5 transition-colors duration-200 hover:bg-muted"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
fileInputRef.current?.click();
|
||||
|
|
@ -455,16 +455,16 @@ function PureModelSelectorCompact({
|
|||
>
|
||||
<PromptInputModelSelectTrigger
|
||||
type="button"
|
||||
className="text-xs focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:ring-0 focus-visible:ring-offset-0 data-[state=open]:ring-0 data-[state=closed]:ring-0"
|
||||
className="text-xs focus:outline-hidden focus:ring-0 focus:ring-offset-0 focus-visible:ring-0 focus-visible:ring-offset-0 data-[state=closed]:ring-0 data-[state=open]:ring-0"
|
||||
>
|
||||
{selectedModel?.name || 'Select model'}
|
||||
</PromptInputModelSelectTrigger>
|
||||
<PromptInputModelSelectContent>
|
||||
{chatModels.map((model) => (
|
||||
<SelectItem key={model.id} value={model.name}>
|
||||
<div className="flex flex-col gap-1 items-start py-1">
|
||||
<div className="flex flex-col items-start gap-1 py-1">
|
||||
<div className="font-medium">{model.name}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<div className="text-muted-foreground text-xs">
|
||||
{model.description}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -487,7 +487,7 @@ function PureStopButton({
|
|||
return (
|
||||
<Button
|
||||
data-testid="stop-button"
|
||||
className="p-2 rounded-full border transition-colors duration-200 h-fit border-border hover:bg-muted"
|
||||
className="h-fit rounded-full border border-border p-2 transition-colors duration-200 hover:bg-muted"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
stop();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Attachment } from '@/lib/types';
|
||||
import { Loader } from './elements/loader';
|
||||
import { CrossSmallIcon, } from './icons';
|
||||
import { CrossSmallIcon } from './icons';
|
||||
import { Button } from './ui/button';
|
||||
import Image from 'next/image';
|
||||
|
||||
|
|
@ -44,13 +44,13 @@ export const PreviewAttachment = ({
|
|||
onClick={onRemove}
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
className="absolute top-0.5 right-0.5 opacity-0 group-hover:opacity-100 transition-opacity size-4 p-0 rounded-full"
|
||||
className="absolute top-0.5 right-0.5 size-4 rounded-full p-0 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<CrossSmallIcon size={8} />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="absolute bottom-0 inset-x-0 bg-gradient-to-t from-black/80 to-transparent text-white text-[10px] px-1 py-0.5 truncate">
|
||||
<div className="absolute bottom-0 inset-x-0 bg-linear-to-t from-black/80 to-transparent text-white text-[10px] px-1 py-0.5 truncate">
|
||||
{name}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ const PureChatItem = ({
|
|||
<DropdownMenu modal={true}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuAction
|
||||
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground mr-0.5"
|
||||
className="mr-0.5 data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||
showOnHover={!isActive}
|
||||
>
|
||||
<MoreHorizontalIcon />
|
||||
|
|
@ -75,7 +75,7 @@ const PureChatItem = ({
|
|||
setVisibilityType('private');
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<LockIcon size={12} />
|
||||
<span>Private</span>
|
||||
</div>
|
||||
|
|
@ -89,7 +89,7 @@ const PureChatItem = ({
|
|||
setVisibilityType('public');
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<GlobeIcon />
|
||||
<span>Public</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
return (
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<div className="flex flex-row gap-2 justify-center items-center px-2 w-full text-sm text-zinc-500">
|
||||
<div className="flex w-full flex-row items-center justify-center gap-2 px-2 text-sm text-zinc-500">
|
||||
Login to save and revisit previous chats!
|
||||
</div>
|
||||
</SidebarGroupContent>
|
||||
|
|
@ -163,7 +163,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
if (isLoading) {
|
||||
return (
|
||||
<SidebarGroup>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Today
|
||||
</div>
|
||||
<SidebarGroupContent>
|
||||
|
|
@ -171,10 +171,10 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
{[44, 32, 28, 64, 52].map((item) => (
|
||||
<div
|
||||
key={item}
|
||||
className="flex gap-2 items-center px-2 h-8 rounded-md"
|
||||
className="flex h-8 items-center gap-2 rounded-md px-2"
|
||||
>
|
||||
<div
|
||||
className="h-4 rounded-md flex-1 max-w-[--skeleton-width] bg-sidebar-accent-foreground/10"
|
||||
className="h-4 max-w-(--skeleton-width) flex-1 rounded-md bg-sidebar-accent-foreground/10"
|
||||
style={
|
||||
{
|
||||
'--skeleton-width': `${item}%`,
|
||||
|
|
@ -193,7 +193,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
return (
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<div className="flex flex-row gap-2 justify-center items-center px-2 w-full text-sm text-zinc-500">
|
||||
<div className="flex w-full flex-row items-center justify-center gap-2 px-2 text-sm text-zinc-500">
|
||||
Your conversations will appear here once you start chatting!
|
||||
</div>
|
||||
</SidebarGroupContent>
|
||||
|
|
@ -218,7 +218,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
<div className="flex flex-col gap-6">
|
||||
{groupedChats.today.length > 0 && (
|
||||
<div>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Today
|
||||
</div>
|
||||
{groupedChats.today.map((chat) => (
|
||||
|
|
@ -238,7 +238,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
|
||||
{groupedChats.yesterday.length > 0 && (
|
||||
<div>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Yesterday
|
||||
</div>
|
||||
{groupedChats.yesterday.map((chat) => (
|
||||
|
|
@ -258,7 +258,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
|
||||
{groupedChats.lastWeek.length > 0 && (
|
||||
<div>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Last 7 days
|
||||
</div>
|
||||
{groupedChats.lastWeek.map((chat) => (
|
||||
|
|
@ -278,7 +278,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
|
||||
{groupedChats.lastMonth.length > 0 && (
|
||||
<div>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Last 30 days
|
||||
</div>
|
||||
{groupedChats.lastMonth.map((chat) => (
|
||||
|
|
@ -298,7 +298,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
|
||||
{groupedChats.older.length > 0 && (
|
||||
<div>
|
||||
<div className="px-2 py-1 text-xs text-sidebar-foreground/50">
|
||||
<div className="px-2 py-1 text-sidebar-foreground/50 text-xs">
|
||||
Older than last month
|
||||
</div>
|
||||
{groupedChats.older.map((chat) => (
|
||||
|
|
@ -329,11 +329,11 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
|||
/>
|
||||
|
||||
{hasReachedEnd ? (
|
||||
<div className="flex flex-row gap-2 justify-center items-center px-2 mt-8 w-full text-sm text-zinc-500">
|
||||
<div className="mt-8 flex w-full flex-row items-center justify-center gap-2 px-2 text-sm text-zinc-500">
|
||||
You have reached the end of your chat history.
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-row gap-2 items-center p-2 mt-8 text-zinc-500 dark:text-zinc-400">
|
||||
<div className="mt-8 flex flex-row items-center gap-2 p-2 text-zinc-500 dark:text-zinc-400">
|
||||
<div className="animate-spin">
|
||||
<LoaderIcon />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ export function SidebarToggle({
|
|||
data-testid="sidebar-toggle-button"
|
||||
onClick={toggleSidebar}
|
||||
variant="outline"
|
||||
className="px-1 h-8 md:px-2 md:h-fit"
|
||||
className="h-8 px-1 md:h-fit md:px-2"
|
||||
>
|
||||
<SidebarLeftIcon size={16} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent align="start" className="hidden md:block">Toggle Sidebar</TooltipContent>
|
||||
<TooltipContent align="start" className="hidden md:block">
|
||||
Toggle Sidebar
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ export function SidebarUserNav({ user }: { user: User }) {
|
|||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
{status === 'loading' ? (
|
||||
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent bg-background data-[state=open]:text-sidebar-accent-foreground h-10 justify-between">
|
||||
<SidebarMenuButton className="h-10 justify-between bg-background data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
||||
<div className="flex flex-row gap-2">
|
||||
<div className="size-6 bg-zinc-500/30 rounded-full animate-pulse" />
|
||||
<span className="bg-zinc-500/30 text-transparent rounded-md animate-pulse">
|
||||
<div className="size-6 animate-pulse rounded-full bg-zinc-500/30" />
|
||||
<span className="animate-pulse rounded-md bg-zinc-500/30 text-transparent">
|
||||
Loading auth status
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -50,7 +50,7 @@ export function SidebarUserNav({ user }: { user: User }) {
|
|||
) : (
|
||||
<SidebarMenuButton
|
||||
data-testid="user-nav-button"
|
||||
className="data-[state=open]:bg-sidebar-accent bg-background data-[state=open]:text-sidebar-accent-foreground h-10"
|
||||
className="h-10 bg-background data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Image
|
||||
src={`https://avatar.vercel.sh/${user.email}`}
|
||||
|
|
@ -69,12 +69,14 @@ export function SidebarUserNav({ user }: { user: User }) {
|
|||
<DropdownMenuContent
|
||||
data-testid="user-nav-menu"
|
||||
side="top"
|
||||
className="w-[--radix-popper-anchor-width]"
|
||||
className="w-(--radix-popper-anchor-width)"
|
||||
>
|
||||
<DropdownMenuItem
|
||||
data-testid="user-nav-item-theme"
|
||||
className="cursor-pointer"
|
||||
onSelect={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
|
||||
onSelect={() =>
|
||||
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
|
||||
}
|
||||
>
|
||||
{`Toggle ${resolvedTheme === 'light' ? 'dark' : 'light'} mode`}
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const SignOutForm = () => {
|
|||
>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full text-left px-1 py-0.5 text-red-500"
|
||||
className="w-full px-1 py-0.5 text-left text-red-500"
|
||||
>
|
||||
Sign out
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function SubmitButton({
|
|||
{children}
|
||||
|
||||
{(pending || isSuccessful) && (
|
||||
<span className="animate-spin absolute right-4">
|
||||
<span className="absolute right-4 animate-spin">
|
||||
<LoaderIcon />
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,16 @@ function PureSuggestedActions({
|
|||
}: SuggestedActionsProps) {
|
||||
const suggestedActions = [
|
||||
'What are the advantages of using Next.js?',
|
||||
'Write code to demonstrate Dijkstra\'s algorithm',
|
||||
"Write code to demonstrate Dijkstra's algorithm",
|
||||
'Help me write an essay about Silicon Valley',
|
||||
'What is the weather in San Francisco?',
|
||||
];
|
||||
|
||||
return (
|
||||
<div data-testid="suggested-actions" className="grid sm:grid-cols-2 gap-2 w-full">
|
||||
<div
|
||||
data-testid="suggested-actions"
|
||||
className="grid w-full gap-2 sm:grid-cols-2"
|
||||
>
|
||||
{suggestedActions.map((suggestedAction, index) => (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
|
|
@ -44,7 +47,7 @@ function PureSuggestedActions({
|
|||
parts: [{ type: 'text', text: suggestion }],
|
||||
});
|
||||
}}
|
||||
className="text-left w-full h-auto whitespace-normal p-3"
|
||||
className="h-auto w-full whitespace-normal p-3 text-left"
|
||||
>
|
||||
{suggestedAction}
|
||||
</Suggestion>
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ export const Suggestion = ({
|
|||
<AnimatePresence>
|
||||
{!isExpanded ? (
|
||||
<motion.div
|
||||
className={cn('cursor-pointer text-muted-foreground p-1', {
|
||||
'absolute -right-8': artifactKind === 'text',
|
||||
className={cn('cursor-pointer p-1 text-muted-foreground', {
|
||||
'-right-8 absolute': artifactKind === 'text',
|
||||
'sticky top-0 right-4': artifactKind === 'code',
|
||||
})}
|
||||
onClick={() => {
|
||||
|
|
@ -41,21 +41,21 @@ export const Suggestion = ({
|
|||
) : (
|
||||
<motion.div
|
||||
key={suggestion.id}
|
||||
className="flex absolute -right-12 z-50 flex-col gap-3 p-3 w-56 font-sans text-sm rounded-2xl border shadow-xl bg-background md:-right-16"
|
||||
className="-right-12 md:-right-16 absolute z-50 flex w-56 flex-col gap-3 rounded-2xl border bg-background p-3 font-sans text-sm shadow-xl"
|
||||
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: -20 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
>
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div className="rounded-full size-4 bg-muted-foreground/25" />
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<div className="size-4 rounded-full bg-muted-foreground/25" />
|
||||
<div className="font-medium">Assistant</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs text-gray-500 cursor-pointer"
|
||||
className="cursor-pointer text-gray-500 text-xs"
|
||||
onClick={() => {
|
||||
setIsExpanded(false);
|
||||
}}
|
||||
|
|
@ -66,7 +66,7 @@ export const Suggestion = ({
|
|||
<div>{suggestion.description}</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-fit py-1.5 px-3 rounded-full"
|
||||
className="w-fit rounded-full px-3 py-1.5"
|
||||
onClick={onApply}
|
||||
>
|
||||
Apply
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ function PureEditor({
|
|||
}, [suggestions, content]);
|
||||
|
||||
return (
|
||||
<div className="relative prose dark:prose-invert" ref={containerRef} />
|
||||
<div className="prose dark:prose-invert relative" ref={containerRef} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ function Toast(props: ToastProps) {
|
|||
}, [description]);
|
||||
|
||||
return (
|
||||
<div className="flex w-full toast-mobile:w-[356px] justify-center">
|
||||
<div className="flex toast-mobile:w-[356px] w-full justify-center">
|
||||
<div
|
||||
data-testid="toast"
|
||||
key={id}
|
||||
className={cn(
|
||||
'bg-zinc-100 p-3 rounded-lg w-full toast-mobile:w-fit flex flex-row gap-3',
|
||||
'flex toast-mobile:w-fit w-full flex-row gap-3 rounded-lg bg-zinc-100 p-3',
|
||||
multiLine ? 'items-start' : 'items-center',
|
||||
)}
|
||||
>
|
||||
|
|
@ -58,7 +58,7 @@ function Toast(props: ToastProps) {
|
|||
>
|
||||
{iconsByType[type]}
|
||||
</div>
|
||||
<div ref={descriptionRef} className="text-zinc-950 text-sm">
|
||||
<div ref={descriptionRef} className="text-sm text-zinc-950">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ const Tool = ({
|
|||
<Tooltip open={isHovered && !isAnimating}>
|
||||
<TooltipTrigger asChild>
|
||||
<motion.div
|
||||
className={cx('p-3 rounded-full', {
|
||||
'bg-primary !text-primary-foreground': selectedTool === description,
|
||||
className={cx('rounded-full p-3', {
|
||||
'bg-primary text-primary-foreground!': selectedTool === description,
|
||||
})}
|
||||
onHoverStart={() => {
|
||||
setIsHovered(true);
|
||||
|
|
@ -122,7 +122,7 @@ const Tool = ({
|
|||
<TooltipContent
|
||||
side="left"
|
||||
sideOffset={16}
|
||||
className="bg-foreground text-background rounded-2xl p-3 px-4"
|
||||
className="rounded-2xl bg-foreground p-3 px-4 text-background"
|
||||
>
|
||||
{description}
|
||||
</TooltipContent>
|
||||
|
|
@ -168,11 +168,11 @@ const ReadingLevelSelector = ({
|
|||
}, [yToLevel]);
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col justify-end items-center">
|
||||
<div className="relative flex flex-col items-center justify-end">
|
||||
{randomArr.map((id) => (
|
||||
<motion.div
|
||||
key={id}
|
||||
className="size-[40px] flex flex-row items-center justify-center"
|
||||
className="flex size-[40px] flex-row items-center justify-center"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
|
|
@ -187,7 +187,7 @@ const ReadingLevelSelector = ({
|
|||
<TooltipTrigger asChild>
|
||||
<motion.div
|
||||
className={cx(
|
||||
'absolute bg-background p-3 border rounded-full flex flex-row items-center',
|
||||
'absolute flex flex-row items-center rounded-full border bg-background p-3',
|
||||
{
|
||||
'bg-primary text-primary-foreground': currentLevel !== 2,
|
||||
'bg-background text-foreground': currentLevel === 2,
|
||||
|
|
@ -233,7 +233,7 @@ const ReadingLevelSelector = ({
|
|||
<TooltipContent
|
||||
side="left"
|
||||
sideOffset={16}
|
||||
className="bg-foreground text-background text-sm rounded-2xl p-3 px-4"
|
||||
className="rounded-2xl bg-foreground p-3 px-4 text-background text-sm"
|
||||
>
|
||||
{LEVELS[currentLevel]}
|
||||
</TooltipContent>
|
||||
|
|
@ -376,7 +376,7 @@ const PureToolbar = ({
|
|||
return (
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<motion.div
|
||||
className="cursor-pointer absolute right-6 bottom-6 p-1.5 border rounded-full shadow-lg bg-background flex flex-col justify-end"
|
||||
className="absolute right-6 bottom-6 flex cursor-pointer flex-col justify-end rounded-full border bg-background p-1.5 shadow-lg"
|
||||
initial={{ opacity: 0, y: -20, scale: 1 }}
|
||||
animate={
|
||||
isToolbarVisible
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ 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',
|
||||
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -36,7 +36,7 @@ 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',
|
||||
'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 bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -79,7 +79,7 @@ const AlertDialogTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold', className)}
|
||||
className={cn('font-semibold text-lg', 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}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
import * as React from 'react';
|
||||
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
|
|
@ -12,13 +12,13 @@ const Avatar = React.forwardRef<
|
|||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
));
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
|
|
@ -26,11 +26,11 @@ const AvatarImage = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Image
|
||||
ref={ref}
|
||||
className={cn("aspect-square h-full w-full", className)}
|
||||
className={cn('aspect-square h-full w-full', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
));
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
|
|
@ -39,12 +39,12 @@ const AvatarFallback = React.forwardRef<
|
|||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
'flex h-full w-full items-center justify-center rounded-full bg-muted',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
));
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
export { Avatar, AvatarImage, AvatarFallback };
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import * as React from 'react';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
||||
outline: 'text-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
variant: 'default',
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
|
|
@ -30,7 +30,7 @@ export interface BadgeProps
|
|||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants }
|
||||
export { Badge, badgeVariants };
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|||
import { cn } from '@/lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const Card = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
||||
'rounded-lg border bg-card text-card-foreground shadow-xs',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -36,7 +36,7 @@ const CardTitle = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'text-2xl font-semibold leading-none tracking-tight',
|
||||
'font-semibold text-2xl leading-none tracking-tight',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -50,7 +50,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}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
import useEmblaCarousel, {
|
||||
type UseEmblaCarouselType,
|
||||
} from "embla-carousel-react"
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||
} from 'embla-carousel-react';
|
||||
import { ArrowLeft, ArrowRight } from 'lucide-react';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
type CarouselApi = UseEmblaCarouselType[1]
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||
type CarouselOptions = UseCarouselParameters[0]
|
||||
type CarouselPlugin = UseCarouselParameters[1]
|
||||
type CarouselApi = UseEmblaCarouselType[1];
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||
type CarouselOptions = UseCarouselParameters[0];
|
||||
type CarouselPlugin = UseCarouselParameters[1];
|
||||
|
||||
type CarouselProps = {
|
||||
opts?: CarouselOptions
|
||||
plugins?: CarouselPlugin
|
||||
orientation?: "horizontal" | "vertical"
|
||||
setApi?: (api: CarouselApi) => void
|
||||
}
|
||||
opts?: CarouselOptions;
|
||||
plugins?: CarouselPlugin;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
setApi?: (api: CarouselApi) => void;
|
||||
};
|
||||
|
||||
type CarouselContextProps = {
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||
scrollPrev: () => void
|
||||
scrollNext: () => void
|
||||
canScrollPrev: boolean
|
||||
canScrollNext: boolean
|
||||
} & CarouselProps
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
||||
api: ReturnType<typeof useEmblaCarousel>[1];
|
||||
scrollPrev: () => void;
|
||||
scrollNext: () => void;
|
||||
canScrollPrev: boolean;
|
||||
canScrollNext: boolean;
|
||||
} & CarouselProps;
|
||||
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
|
||||
|
||||
function useCarousel() {
|
||||
const context = React.useContext(CarouselContext)
|
||||
const context = React.useContext(CarouselContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useCarousel must be used within a <Carousel />")
|
||||
throw new Error('useCarousel must be used within a <Carousel />');
|
||||
}
|
||||
|
||||
return context
|
||||
return context;
|
||||
}
|
||||
|
||||
const Carousel = React.forwardRef<
|
||||
|
|
@ -48,7 +48,7 @@ const Carousel = React.forwardRef<
|
|||
>(
|
||||
(
|
||||
{
|
||||
orientation = "horizontal",
|
||||
orientation = 'horizontal',
|
||||
opts,
|
||||
setApi,
|
||||
plugins,
|
||||
|
|
@ -56,69 +56,69 @@ const Carousel = React.forwardRef<
|
|||
children,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
axis: orientation === 'horizontal' ? 'x' : 'y',
|
||||
},
|
||||
plugins
|
||||
)
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||
plugins,
|
||||
);
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
||||
|
||||
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||
if (!api) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollPrev(api.canScrollPrev())
|
||||
setCanScrollNext(api.canScrollNext())
|
||||
}, [])
|
||||
setCanScrollPrev(api.canScrollPrev());
|
||||
setCanScrollNext(api.canScrollNext());
|
||||
}, []);
|
||||
|
||||
const scrollPrev = React.useCallback(() => {
|
||||
api?.scrollPrev()
|
||||
}, [api])
|
||||
api?.scrollPrev();
|
||||
}, [api]);
|
||||
|
||||
const scrollNext = React.useCallback(() => {
|
||||
api?.scrollNext()
|
||||
}, [api])
|
||||
api?.scrollNext();
|
||||
}, [api]);
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault()
|
||||
scrollPrev()
|
||||
} else if (event.key === "ArrowRight") {
|
||||
event.preventDefault()
|
||||
scrollNext()
|
||||
if (event.key === 'ArrowLeft') {
|
||||
event.preventDefault();
|
||||
scrollPrev();
|
||||
} else if (event.key === 'ArrowRight') {
|
||||
event.preventDefault();
|
||||
scrollNext();
|
||||
}
|
||||
},
|
||||
[scrollPrev, scrollNext]
|
||||
)
|
||||
[scrollPrev, scrollNext],
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api || !setApi) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
setApi(api);
|
||||
}, [api, setApi]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
onSelect(api)
|
||||
api.on("reInit", onSelect)
|
||||
api.on("select", onSelect)
|
||||
onSelect(api);
|
||||
api.on('reInit', onSelect);
|
||||
api.on('select', onSelect);
|
||||
|
||||
return () => {
|
||||
api?.off("select", onSelect)
|
||||
}
|
||||
}, [api, onSelect])
|
||||
api?.off('select', onSelect);
|
||||
};
|
||||
}, [api, onSelect]);
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider
|
||||
|
|
@ -127,7 +127,7 @@ const Carousel = React.forwardRef<
|
|||
api: api,
|
||||
opts,
|
||||
orientation:
|
||||
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||
orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
canScrollPrev,
|
||||
|
|
@ -137,7 +137,7 @@ const Carousel = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
onKeyDownCapture={handleKeyDown}
|
||||
className={cn("relative", className)}
|
||||
className={cn('relative', className)}
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
{...props}
|
||||
|
|
@ -145,38 +145,38 @@ const Carousel = React.forwardRef<
|
|||
{children}
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
Carousel.displayName = "Carousel"
|
||||
);
|
||||
},
|
||||
);
|
||||
Carousel.displayName = 'Carousel';
|
||||
|
||||
const CarouselContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { carouselRef, orientation } = useCarousel()
|
||||
const { carouselRef, orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
<div ref={carouselRef} className="overflow-hidden">
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex",
|
||||
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||
className
|
||||
'flex',
|
||||
orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
CarouselContent.displayName = "CarouselContent"
|
||||
);
|
||||
});
|
||||
CarouselContent.displayName = 'CarouselContent';
|
||||
|
||||
const CarouselItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { orientation } = useCarousel()
|
||||
const { orientation } = useCarousel();
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -184,21 +184,21 @@ const CarouselItem = React.forwardRef<
|
|||
role="group"
|
||||
aria-roledescription="slide"
|
||||
className={cn(
|
||||
"min-w-0 shrink-0 grow-0 basis-full",
|
||||
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||
className
|
||||
'min-w-0 shrink-0 grow-0 basis-full',
|
||||
orientation === 'horizontal' ? 'pl-4' : 'pt-4',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
CarouselItem.displayName = "CarouselItem"
|
||||
);
|
||||
});
|
||||
CarouselItem.displayName = 'CarouselItem';
|
||||
|
||||
const CarouselPrevious = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||
>(({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -206,11 +206,11 @@ const CarouselPrevious = React.forwardRef<
|
|||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-left-12 top-1/2 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
'absolute h-8 w-8 rounded-full',
|
||||
orientation === 'horizontal'
|
||||
? '-left-12 -translate-y-1/2 top-1/2'
|
||||
: '-top-12 -translate-x-1/2 left-1/2 rotate-90',
|
||||
className,
|
||||
)}
|
||||
disabled={!canScrollPrev}
|
||||
onClick={scrollPrev}
|
||||
|
|
@ -219,15 +219,15 @@ const CarouselPrevious = React.forwardRef<
|
|||
<ArrowLeft className="h-4 w-4" />
|
||||
<span className="sr-only">Previous slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselPrevious.displayName = "CarouselPrevious"
|
||||
);
|
||||
});
|
||||
CarouselPrevious.displayName = 'CarouselPrevious';
|
||||
|
||||
const CarouselNext = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||
>(({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -235,11 +235,11 @@ const CarouselNext = React.forwardRef<
|
|||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-right-12 top-1/2 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
'absolute h-8 w-8 rounded-full',
|
||||
orientation === 'horizontal'
|
||||
? '-right-12 -translate-y-1/2 top-1/2'
|
||||
: '-bottom-12 -translate-x-1/2 left-1/2 rotate-90',
|
||||
className,
|
||||
)}
|
||||
disabled={!canScrollNext}
|
||||
onClick={scrollNext}
|
||||
|
|
@ -248,9 +248,9 @@ const CarouselNext = React.forwardRef<
|
|||
<ArrowRight className="h-4 w-4" />
|
||||
<span className="sr-only">Next slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselNext.displayName = "CarouselNext"
|
||||
);
|
||||
});
|
||||
CarouselNext.displayName = 'CarouselNext';
|
||||
|
||||
export {
|
||||
type CarouselApi,
|
||||
|
|
@ -259,4 +259,4 @@ export {
|
|||
CarouselItem,
|
||||
CarouselPrevious,
|
||||
CarouselNext,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
|
||||
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
|
||||
|
||||
const Collapsible = CollapsiblePrimitive.Root
|
||||
const Collapsible = CollapsiblePrimitive.Root;
|
||||
|
||||
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
|
||||
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
|
||||
|
||||
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
|
||||
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
|
|
@ -47,7 +47,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[8rem] 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',
|
||||
'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 bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
|
|||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 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',
|
||||
'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 bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -83,7 +83,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
|
|
@ -99,7 +99,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.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-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
|
|
@ -123,7 +123,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.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-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -147,7 +147,7 @@ const DropdownMenuLabel = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'px-2 py-1.5 text-sm font-semibold',
|
||||
'px-2 py-1.5 font-semibold text-sm',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
|
||||
import * as React from 'react';
|
||||
import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const HoverCard = HoverCardPrimitive.Root
|
||||
const HoverCard = HoverCardPrimitive.Root;
|
||||
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger;
|
||||
|
||||
const HoverCardContent = React.forwardRef<
|
||||
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||
<HoverCardPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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 origin-[--radix-hover-card-content-transform-origin]",
|
||||
className
|
||||
'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 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
|
||||
));
|
||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
|
||||
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
|
|||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
import * as React from 'react';
|
||||
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
|
|
@ -11,7 +11,7 @@ const ScrollArea = React.forwardRef<
|
|||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
className={cn('relative overflow-hidden', className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
|
|
@ -20,29 +20,29 @@ const ScrollArea = React.forwardRef<
|
|||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
));
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
'flex touch-none select-none transition-colors',
|
||||
orientation === 'vertical' &&
|
||||
'h-full w-2.5 border-l border-l-transparent p-px',
|
||||
orientation === 'horizontal' &&
|
||||
'h-2.5 flex-col border-t border-t-transparent p-px',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
));
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
||||
export { ScrollArea, ScrollBar };
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
|
|||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -75,9 +75,9 @@ const SelectContent = React.forwardRef<
|
|||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative z-50 max-h-96 min-w-[8rem] 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',
|
||||
'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 bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
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',
|
||||
'data-[side=left]:-translate-x-1 data-[side=top]:-translate-y-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1',
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
|
|
@ -88,7 +88,7 @@ const SelectContent = React.forwardRef<
|
|||
className={cn(
|
||||
'p-1',
|
||||
position === 'popper' &&
|
||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
|
||||
'h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
|
@ -105,7 +105,7 @@ const SelectLabel = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
||||
className={cn('py-1.5 pr-2 pl-8 font-semibold text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
|
|||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const Separator = React.forwardRef<
|
|||
orientation={orientation}
|
||||
className={cn(
|
||||
'shrink-0 bg-border',
|
||||
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
||||
orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const SheetOverlay = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.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',
|
||||
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80 data-[state=closed]:animate-out data-[state=open]:animate-in',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -65,7 +65,7 @@ const SheetContent = React.forwardRef<
|
|||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||
<SheetPrimitive.Close className="absolute top-4 right-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">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
|
|
@ -108,7 +108,7 @@ const SheetTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold text-foreground', className)}
|
||||
className={cn('font-semibold text-foreground text-lg', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -120,7 +120,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}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ const SidebarProvider = React.forwardRef<
|
|||
} as React.CSSProperties
|
||||
}
|
||||
className={cn(
|
||||
'group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar',
|
||||
'group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
|
@ -189,7 +189,7 @@ const Sidebar = React.forwardRef<
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground',
|
||||
'flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
|
@ -206,7 +206,7 @@ const Sidebar = React.forwardRef<
|
|||
<SheetContent
|
||||
data-sidebar="sidebar"
|
||||
data-mobile="true"
|
||||
className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
|
||||
className="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
|
||||
style={
|
||||
{
|
||||
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
|
||||
|
|
@ -224,7 +224,7 @@ const Sidebar = React.forwardRef<
|
|||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="group peer hidden md:block text-sidebar-foreground"
|
||||
className="group peer hidden text-sidebar-foreground md:block"
|
||||
data-state={state}
|
||||
data-collapsible={state === 'collapsed' ? collapsible : ''}
|
||||
data-variant={variant}
|
||||
|
|
@ -233,31 +233,31 @@ const Sidebar = React.forwardRef<
|
|||
{/* This is what handles the sidebar gap on desktop */}
|
||||
<div
|
||||
className={cn(
|
||||
'duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear',
|
||||
'relative h-svh w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
|
||||
'group-data-[collapsible=offcanvas]:w-0',
|
||||
'group-data-[side=right]:rotate-180',
|
||||
variant === 'floating' || variant === 'inset'
|
||||
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
|
||||
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',
|
||||
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
|
||||
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex',
|
||||
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
|
||||
side === 'left'
|
||||
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
||||
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
||||
// Adjust the padding for floating and inset variants.
|
||||
variant === 'floating' || variant === 'inset'
|
||||
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
|
||||
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
|
||||
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
|
||||
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
data-sidebar="sidebar"
|
||||
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
|
||||
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
|
@ -309,10 +309,10 @@ const SidebarRail = React.forwardRef<
|
|||
onClick={toggleSidebar}
|
||||
title="Toggle Sidebar"
|
||||
className={cn(
|
||||
'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex',
|
||||
'[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize',
|
||||
'-translate-x-1/2 group-data-[side=left]:-right-4 absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=right]:left-0 sm:flex',
|
||||
'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
|
||||
'[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
|
||||
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar',
|
||||
'group-data-[collapsible=offcanvas]:translate-x-0 hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:after:left-full',
|
||||
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
|
||||
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
|
||||
className,
|
||||
|
|
@ -332,7 +332,7 @@ const SidebarInset = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex min-h-svh flex-1 flex-col bg-background',
|
||||
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
|
||||
'peer-data-[variant=inset]:min-h-[calc(100svh-(--spacing(4)))] md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -448,7 +448,7 @@ const SidebarGroupLabel = React.forwardRef<
|
|||
ref={ref}
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
'duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'flex h-8 shrink-0 items-center rounded-md px-2 font-medium text-sidebar-foreground/70 text-xs outline-hidden ring-sidebar-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
|
||||
className,
|
||||
)}
|
||||
|
|
@ -469,9 +469,9 @@ const SidebarGroupAction = React.forwardRef<
|
|||
ref={ref}
|
||||
data-sidebar="group-action"
|
||||
className={cn(
|
||||
'absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
// Increases the hit area of the button on mobile.
|
||||
'after:absolute after:-inset-2 after:md:hidden',
|
||||
'after:-inset-2 after:absolute md:after:hidden',
|
||||
'group-data-[collapsible=icon]:hidden',
|
||||
className,
|
||||
)}
|
||||
|
|
@ -521,7 +521,7 @@ const SidebarMenuItem = React.forwardRef<
|
|||
SidebarMenuItem.displayName = 'SidebarMenuItem';
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
@ -532,7 +532,7 @@ const sidebarMenuButtonVariants = cva(
|
|||
size: {
|
||||
default: 'h-8 text-sm',
|
||||
sm: 'h-7 text-xs',
|
||||
lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',
|
||||
lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
|
@ -615,9 +615,9 @@ const SidebarMenuAction = React.forwardRef<
|
|||
ref={ref}
|
||||
data-sidebar="menu-action"
|
||||
className={cn(
|
||||
'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
// Increases the hit area of the button on mobile.
|
||||
'after:absolute after:-inset-2 after:md:hidden',
|
||||
'after:-inset-2 after:absolute md:after:hidden',
|
||||
'peer-data-[size=sm]/menu-button:top-1',
|
||||
'peer-data-[size=default]/menu-button:top-1.5',
|
||||
'peer-data-[size=lg]/menu-button:top-2.5',
|
||||
|
|
@ -640,7 +640,7 @@ const SidebarMenuBadge = React.forwardRef<
|
|||
ref={ref}
|
||||
data-sidebar="menu-badge"
|
||||
className={cn(
|
||||
'absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground select-none pointer-events-none',
|
||||
'pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 font-medium text-sidebar-foreground text-xs tabular-nums',
|
||||
'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
|
||||
'peer-data-[size=sm]/menu-button:top-1',
|
||||
'peer-data-[size=default]/menu-button:top-1.5',
|
||||
|
|
@ -668,7 +668,7 @@ const SidebarMenuSkeleton = React.forwardRef<
|
|||
<div
|
||||
ref={ref}
|
||||
data-sidebar="menu-skeleton"
|
||||
className={cn('rounded-md h-8 flex gap-2 px-2 items-center', className)}
|
||||
className={cn('flex h-8 items-center gap-2 rounded-md px-2', className)}
|
||||
{...props}
|
||||
>
|
||||
{showIcon && (
|
||||
|
|
@ -678,7 +678,7 @@ const SidebarMenuSkeleton = React.forwardRef<
|
|||
/>
|
||||
)}
|
||||
<Skeleton
|
||||
className="h-4 flex-1 max-w-[--skeleton-width]"
|
||||
className="h-4 max-w-(--skeleton-width) flex-1"
|
||||
data-sidebar="menu-skeleton-text"
|
||||
style={
|
||||
{
|
||||
|
|
@ -699,7 +699,7 @@ const SidebarMenuSub = React.forwardRef<
|
|||
ref={ref}
|
||||
data-sidebar="menu-sub"
|
||||
className={cn(
|
||||
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5',
|
||||
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-sidebar-border border-l px-2.5 py-0.5',
|
||||
'group-data-[collapsible=icon]:hidden',
|
||||
className,
|
||||
)}
|
||||
|
|
@ -731,7 +731,7 @@ const SidebarMenuSubButton = React.forwardRef<
|
|||
data-size={size}
|
||||
data-active={isActive}
|
||||
className={cn(
|
||||
'flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground',
|
||||
'-translate-x-px flex h-7 min-w-0 items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-hidden ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground',
|
||||
'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
|
||||
size === 'sm' && 'text-xs',
|
||||
size === 'md' && 'text-sm',
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const Textarea = React.forwardRef<
|
|||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const TooltipContent = React.forwardRef<
|
|||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground 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',
|
||||
'fade-in-0 zoom-in-95 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 animate-in overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-popover-foreground text-sm shadow-md data-[state=closed]:animate-out',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const VersionFooter = ({
|
|||
|
||||
return (
|
||||
<motion.div
|
||||
className="absolute flex flex-col gap-4 lg:flex-row bottom-0 bg-background p-4 w-full border-t z-50 justify-between"
|
||||
className="absolute bottom-0 z-50 flex w-full flex-col justify-between gap-4 border-t bg-background p-4 lg:flex-row"
|
||||
initial={{ y: isMobile ? 200 : 77 }}
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: isMobile ? 200 : 77 }}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export function VisibilitySelector({
|
|||
<Button
|
||||
data-testid="visibility-selector"
|
||||
variant="outline"
|
||||
className="hidden md:flex md:px-2 md:h-[34px] focus:outline-none focus:ring-0"
|
||||
className="hidden focus:outline-hidden focus:ring-0 md:flex md:h-[34px] md:px-2"
|
||||
>
|
||||
{selectedVisibility?.icon}
|
||||
{selectedVisibility?.label}
|
||||
|
|
@ -88,18 +88,18 @@ export function VisibilitySelector({
|
|||
setVisibilityType(visibility.id);
|
||||
setOpen(false);
|
||||
}}
|
||||
className="gap-4 group/item flex flex-row justify-between items-center"
|
||||
className="group/item flex flex-row items-center justify-between gap-4"
|
||||
data-active={visibility.id === visibilityType}
|
||||
>
|
||||
<div className="flex flex-col gap-1 items-start">
|
||||
<div className="flex flex-col items-start gap-1">
|
||||
{visibility.label}
|
||||
{visibility.description && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<div className="text-muted-foreground text-xs">
|
||||
{visibility.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-foreground dark:text-foreground opacity-0 group-data-[active=true]/item:opacity-100">
|
||||
<div className="text-foreground opacity-0 group-data-[active=true]/item:opacity-100 dark:text-foreground">
|
||||
<CheckCircleFillIcon />
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ export function Weather({
|
|||
return (
|
||||
<div
|
||||
className={cx(
|
||||
'flex flex-col gap-4 rounded-2xl p-4 skeleton-bg max-w-[500px]',
|
||||
'skeleton-bg flex max-w-[500px] flex-col gap-4 rounded-2xl p-4',
|
||||
{
|
||||
'bg-blue-400': isDay,
|
||||
},
|
||||
|
|
@ -260,11 +260,11 @@ export function Weather({
|
|||
},
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<div
|
||||
className={cx(
|
||||
'size-10 rounded-full skeleton-div',
|
||||
'skeleton-div size-10 rounded-full',
|
||||
{
|
||||
'bg-yellow-300': isDay,
|
||||
},
|
||||
|
|
@ -273,7 +273,7 @@ export function Weather({
|
|||
},
|
||||
)}
|
||||
/>
|
||||
<div className="text-4xl font-medium text-blue-50">
|
||||
<div className="font-medium text-4xl text-blue-50">
|
||||
{n(weatherAtLocation.current.temperature_2m)}
|
||||
{weatherAtLocation.current_units.temperature_2m}
|
||||
</div>
|
||||
|
|
@ -290,7 +290,7 @@ export function Weather({
|
|||
</div>
|
||||
<div
|
||||
className={cx(
|
||||
'size-6 rounded-full skeleton-div',
|
||||
'skeleton-div size-6 rounded-full',
|
||||
{
|
||||
'bg-yellow-300': isDay,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export function useScrollToBottom() {
|
|||
const container = containerRef.current;
|
||||
const scrollOptions: ScrollToOptions = {
|
||||
top: container.scrollHeight,
|
||||
behavior: scrollBehavior
|
||||
behavior: scrollBehavior,
|
||||
};
|
||||
container.scrollTo(scrollOptions);
|
||||
setScrollBehavior(false);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const chatModels: Array<ChatModel> = [
|
|||
{
|
||||
id: 'chat-model-reasoning',
|
||||
name: 'Grok Reasoning',
|
||||
description: 'Uses advanced chain-of-thought reasoning for complex problems',
|
||||
description:
|
||||
'Uses advanced chain-of-thought reasoning for complex problems',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
"dev": "next dev --turbo",
|
||||
"build": "tsx lib/db/migrate && next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint && biome lint --write --unsafe",
|
||||
"lint:fix": "next lint --fix && biome lint --write --unsafe",
|
||||
"lint": "biome lint --write --unsafe",
|
||||
"lint:fix": "biome lint --write --unsafe && biome format --write",
|
||||
"format": "biome format --write",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "npx tsx lib/db/migrate.ts",
|
||||
|
|
@ -104,6 +104,7 @@
|
|||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@types/d3-scale": "^4.0.8",
|
||||
"@types/node": "^22.8.6",
|
||||
|
|
@ -119,7 +120,7 @@
|
|||
"eslint-import-resolver-typescript": "^3.6.3",
|
||||
"eslint-plugin-tailwindcss": "^3.17.5",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"tsx": "^4.19.1",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
|
|
|
|||
694
pnpm-lock.yaml
generated
694
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,7 @@
|
|||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
'tailwindcss/nesting': {},
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
import type { Config } from 'tailwindcss';
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ['class'],
|
||||
content: [
|
||||
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./node_modules/streamdown/dist/index.js',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['var(--font-geist)'],
|
||||
mono: ['var(--font-geist-mono)'],
|
||||
},
|
||||
screens: {
|
||||
'toast-mobile': '600px',
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
colors: {
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
chart: {
|
||||
'1': 'hsl(var(--chart-1))',
|
||||
'2': 'hsl(var(--chart-2))',
|
||||
'3': 'hsl(var(--chart-3))',
|
||||
'4': 'hsl(var(--chart-4))',
|
||||
'5': 'hsl(var(--chart-5))',
|
||||
},
|
||||
sidebar: {
|
||||
DEFAULT: 'hsl(var(--sidebar-background))',
|
||||
foreground: 'hsl(var(--sidebar-foreground))',
|
||||
primary: 'hsl(var(--sidebar-primary))',
|
||||
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
|
||||
accent: 'hsl(var(--sidebar-accent))',
|
||||
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
|
||||
border: 'hsl(var(--sidebar-border))',
|
||||
ring: 'hsl(var(--sidebar-ring))',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
|
||||
};
|
||||
export default config;
|
||||
Loading…
Add table
Add a link
Reference in a new issue