From d87c6758abb96da3ea9e2eb29293e5d46a490def Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Sat, 4 Jul 2026 19:06:31 +0200 Subject: [PATCH] chore: update dependencies --- .vscode/settings.json | 5 +- apps/server/package.json | 8 +- apps/web/package.json | 10 +- .../components/layout/loading-screen.test.tsx | 25 +- .../src/components/layout/loading-screen.tsx | 8 +- apps/web/src/routes/agent/$threadId.tsx | 9 +- .../routes/agent/-components/agent-chat.tsx | 263 ++++-- knip.json | 2 - package.json | 2 +- packages/ai/package.json | 4 +- packages/api/package.json | 6 +- packages/auth/package.json | 2 +- packages/db/package.json | 2 +- packages/docx/package.json | 2 +- packages/docx/src/section-renderers.test.ts | 12 + packages/email/package.json | 2 +- packages/env/package.json | 2 +- packages/fonts/package.json | 2 +- packages/import/package.json | 2 +- packages/mcp/package.json | 2 +- packages/pdf/package.json | 2 +- packages/resume/package.json | 2 +- packages/schema/package.json | 2 +- packages/ui/package.json | 5 +- packages/ui/src/components/attachment.tsx | 182 ++++ packages/ui/src/components/bubble.tsx | 115 +++ packages/ui/src/components/marker.tsx | 64 ++ .../ui/src/components/message-scroller.tsx | 116 +++ packages/ui/src/components/message.tsx | 74 ++ packages/utils/package.json | 2 +- pnpm-lock.yaml | 886 +++++++++--------- tooling/package.json | 2 +- turbo.json | 2 +- 33 files changed, 1199 insertions(+), 625 deletions(-) create mode 100644 packages/ui/src/components/attachment.tsx create mode 100644 packages/ui/src/components/bubble.tsx create mode 100644 packages/ui/src/components/marker.tsx create mode 100644 packages/ui/src/components/message-scroller.tsx create mode 100644 packages/ui/src/components/message.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index a028ad7be..0cb018201 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,5 +27,8 @@ ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] ], "tailwindCSS.experimental.configFile": "src/styles/globals.css", - "typescript.experimental.useTsgo": true + "typescript.experimental.useTsgo": true, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + } } diff --git a/apps/server/package.json b/apps/server/package.json index 1edbd86d0..5d09c3149 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -17,7 +17,7 @@ "#react-pdf-renderer": "@react-pdf/renderer" }, "dependencies": { - "@ai-sdk/anthropic": "^4.0.7", + "@ai-sdk/anthropic": "^4.0.8", "@ai-sdk/google": "^4.0.8", "@ai-sdk/openai": "^4.0.7", "@ai-sdk/openai-compatible": "^3.0.5", @@ -46,7 +46,7 @@ "@sindresorhus/slugify": "^3.0.0", "@t3-oss/env-core": "^0.13.11", "@uiw/color-convert": "^2.10.3", - "ai": "^7.0.14", + "ai": "^7.0.15", "bcrypt": "^6.0.0", "better-auth": "1.6.23", "cjk-regex": "^3.4.0", @@ -56,7 +56,7 @@ "es-toolkit": "^1.49.0", "fast-json-patch": "^3.1.1", "hono": "^4.12.27", - "jsonrepair": "^3.14.1", + "jsonrepair": "^3.15.0", "node-html-parser": "^8.0.4", "nodemailer": "^9.0.3", "ollama-ai-provider-v2": "^3.6.0", @@ -77,7 +77,7 @@ "@types/node": "^26.1.0", "@types/pg": "^8.20.0", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "tsdown": "^0.22.3", "tsx": "^4.23.0", "typescript": "^6.0.3", diff --git a/apps/web/package.json b/apps/web/package.json index 81e0645eb..77d09a82c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -16,7 +16,7 @@ "lingui:extract": "lingui extract --clean --overwrite" }, "dependencies": { - "@ai-sdk/react": "^4.0.15", + "@ai-sdk/react": "^4.0.16", "@base-ui/react": "^1.6.0", "@better-auth/api-key": "^1.6.23", "@better-auth/infra": "^0.3.4", @@ -57,13 +57,13 @@ "@types/js-cookie": "^3.0.6", "@uiw/color-convert": "^2.10.3", "@uiw/react-color-colorful": "^2.10.3", - "ai": "^7.0.14", + "ai": "^7.0.15", "better-auth": "1.6.23", "cmdk": "^1.1.1", "drizzle-orm": "1.0.0-rc.4", "es-toolkit": "^1.49.0", "fuse.js": "^7.4.2", - "immer": "^11.1.9", + "immer": "^11.1.11", "js-cookie": "^3.0.8", "motion": "^12.42.2", "pdfjs-dist": "6.1.200", @@ -73,7 +73,7 @@ "react-dom": "^19.2.7", "react-easy-crop": "^6.1.0", "react-markdown": "^10.1.0", - "react-resizable-panels": "^4.12.0", + "react-resizable-panels": "^4.12.1", "react-window": "^2.2.7", "react-zoom-pan-pinch": "^4.0.3", "sonner": "^2.0.7", @@ -95,7 +95,7 @@ "@types/pg": "^8.20.0", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "@vitejs/plugin-react": "^6.0.3", "babel-plugin-macros": "^3.1.0", "babel-plugin-react-compiler": "^1.0.0", diff --git a/apps/web/src/components/layout/loading-screen.test.tsx b/apps/web/src/components/layout/loading-screen.test.tsx index bfa180712..03f0630b0 100644 --- a/apps/web/src/components/layout/loading-screen.test.tsx +++ b/apps/web/src/components/layout/loading-screen.test.tsx @@ -1,32 +1,19 @@ // @vitest-environment happy-dom import { render, screen } from "@testing-library/react"; -import { beforeAll, describe, expect, it } from "vitest"; -import { i18n } from "@lingui/core"; -import { I18nProvider } from "@lingui/react"; +import { describe, expect, it } from "vitest"; import { LoadingScreen } from "./loading-screen"; -beforeAll(() => { - i18n.loadAndActivate({ locale: "en", messages: {} }); -}); - describe("LoadingScreen", () => { - it("renders a spinner and the loading text", () => { - render( - - - , - ); + it("renders the Reactive Resume logo and spinner", () => { + render(); - expect(screen.getByText("Loading…")).toBeInTheDocument(); + expect(screen.getAllByAltText("Reactive Resume")).toHaveLength(2); + expect(screen.getByLabelText("Loading")).toBeInTheDocument(); }); it("fills the viewport (fixed inset-0)", () => { - const { container } = render( - - - , - ); + const { container } = render(); const wrapper = container.firstChild as HTMLElement; expect(wrapper.className).toContain("fixed"); diff --git a/apps/web/src/components/layout/loading-screen.tsx b/apps/web/src/components/layout/loading-screen.tsx index 0b1293dd5..df90b84c9 100644 --- a/apps/web/src/components/layout/loading-screen.tsx +++ b/apps/web/src/components/layout/loading-screen.tsx @@ -1,13 +1,11 @@ -import { Trans } from "@lingui/react/macro"; +import { BrandIcon } from "@reactive-resume/ui/components/brand-icon"; import { Spinner } from "@reactive-resume/ui/components/spinner"; export function LoadingScreen() { return ( -
+
+ -

- Loading… -

); } diff --git a/apps/web/src/routes/agent/$threadId.tsx b/apps/web/src/routes/agent/$threadId.tsx index 2ecc84054..5b888c77d 100644 --- a/apps/web/src/routes/agent/$threadId.tsx +++ b/apps/web/src/routes/agent/$threadId.tsx @@ -23,6 +23,7 @@ import { Tabs, TabsList, TabsTrigger } from "@reactive-resume/ui/components/tabs import { Tooltip, TooltipContent, TooltipTrigger } from "@reactive-resume/ui/components/tooltip"; import { downloadWithAnchor, generateFilename } from "@reactive-resume/utils/file"; import { cn } from "@reactive-resume/utils/style"; +import { LoadingScreen } from "@/components/layout/loading-screen"; import { createResumePdfBlob } from "@/features/resume/export/pdf-document"; import { ResumePreview } from "@/features/resume/preview/preview"; import { orpc } from "@/libs/orpc/client"; @@ -242,13 +243,7 @@ function RouteComponent() { } }, []); - if (isLoading) { - return ( -
- Loading agent workspace… -
- ); - } + if (isLoading) return ; if (error || !data) { return ( diff --git a/apps/web/src/routes/agent/-components/agent-chat.tsx b/apps/web/src/routes/agent/-components/agent-chat.tsx index 4c262c5c2..8a979f6c7 100644 --- a/apps/web/src/routes/agent/-components/agent-chat.tsx +++ b/apps/web/src/routes/agent/-components/agent-chat.tsx @@ -28,7 +28,14 @@ import { m } from "motion/react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import ReactMarkdown from "react-markdown"; import { toast } from "sonner"; -import { Badge } from "@reactive-resume/ui/components/badge"; +import { + Attachment, + AttachmentContent, + AttachmentGroup, + AttachmentMedia, + AttachmentTitle, +} from "@reactive-resume/ui/components/attachment"; +import { Bubble, BubbleContent } from "@reactive-resume/ui/components/bubble"; import { Button } from "@reactive-resume/ui/components/button"; import { DropdownMenu, @@ -37,7 +44,16 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@reactive-resume/ui/components/dropdown-menu"; -import { ScrollArea } from "@reactive-resume/ui/components/scroll-area"; +import { Marker, MarkerContent, MarkerIcon } from "@reactive-resume/ui/components/marker"; +import { Message, MessageContent } from "@reactive-resume/ui/components/message"; +import { + MessageScroller, + MessageScrollerButton, + MessageScrollerContent, + MessageScrollerItem, + MessageScrollerProvider, + MessageScrollerViewport, +} from "@reactive-resume/ui/components/message-scroller"; import { Textarea } from "@reactive-resume/ui/components/textarea"; import { cn } from "@reactive-resume/utils/style"; import { useConfirm } from "@/hooks/use-confirm"; @@ -65,6 +81,12 @@ type AssistantMarkdownProps = { text: string; }; +type FileAttachmentProps = { + filename?: string | null; + mediaType?: string | null; + state?: "idle" | "uploading" | "processing" | "error" | "done"; +}; + type MessagePartProps = { part: UIMessage["parts"][number]; isUser: boolean; @@ -392,23 +414,47 @@ function AssistantMarkdown({ text }: AssistantMarkdownProps) { ); } +function FileAttachment({ filename, mediaType, state = "done" }: FileAttachmentProps) { + return ( + + + + + + {filename || t`Attachment`} + {mediaType ? {mediaType} : null} + + + ); +} + function MessagePart({ part, isUser, onAnswer, onRevert, isReverting, actionsById }: MessagePartProps) { if (part.type === "text") { - return isUser ? ( -
{part.text}
- ) : ( - + return ( + + + {isUser ? ( +
{part.text}
+ ) : ( + + )} +
+
); } if (part.type === "reasoning") { return ( -
- - Thinking - -
{part.text}
-
+ + +
+ + Thinking + +
{part.text}
+
+
+
); } @@ -421,16 +467,20 @@ function MessagePart({ part, isUser, onAnswer, onRevert, isReverting, actionsByI const question = typeof input.question === "string" ? input.question : t`The agent needs your input.`; return ( -
-
{question}
-
- {choices.map((choice) => ( - - ))} -
-
+ + +
+
{question}
+
+ {choices.map((choice) => ( + + ))} +
+
+
+
); } @@ -442,33 +492,38 @@ function MessagePart({ part, isUser, onAnswer, onRevert, isReverting, actionsByI const actionId = typeof output?.actionId === "string" ? output.actionId : null; const action = actionId ? actionsById.get(actionId) : undefined; - return ; + return ( + + + + + + ); } if (part.type === "source-url") { const title = part.title?.trim() || null; return ( - - {title ? ( - <> - {title} - {part.url} - - ) : ( - {part.url} - )} - + + + + {title ? ( + <> + {title} + {part.url} + + ) : ( + {part.url} + )} + + + ); } if (part.type === "file") { - return ( -
- - {part.filename ?? part.url} -
- ); + return ; } return null; @@ -478,15 +533,8 @@ function ChatMessage({ message, onAnswer, onRevert, isReverting, actionsById }: const isUser = message.role === "user"; return ( -
-
+ + {message.parts.map((part) => ( ))} -
-
+ + ); } @@ -822,50 +870,63 @@ function AgentChatMessages({ onStarterSelect, }: AgentChatMessagesProps) { return ( - -
- {messages.length === 0 ? ( -
- -

- What do you want to do? -

- -
- ) : null} - - {messages.map((message) => ( - - ))} - - {isStreaming ? ( -
-
- Working… -
-
- ) : null} - - {error ? ( -
- {error.message} - {!isReadOnly ? ( - + + + + + {messages.length === 0 ? ( +
+ +

+ What do you want to do? +

+ +
) : null} -
- ) : null} -
-
+ + {messages.map((message) => ( + + + + ))} + + {isStreaming ? ( + + + + + + + Working… + + + + ) : null} + + {error ? ( + + + {error.message} + {!isReadOnly ? ( + + ) : null} + + + ) : null} + + + + + ); } @@ -977,16 +1038,18 @@ function AgentChatComposer({ onSend(); }} > -
+
{pendingAttachments.length > 0 ? ( -
+ {pendingAttachments.map((attachment) => ( - - - {attachment.filename} - + ))} -
+ ) : null}
diff --git a/knip.json b/knip.json index 9536246fd..bab3f4ded 100644 --- a/knip.json +++ b/knip.json @@ -33,8 +33,6 @@ "bcrypt", "cjk-regex", "deepmerge-ts", - "dompurify", - "dotenv", "drizzle-zod", "es-toolkit", "fast-json-patch", diff --git a/package.json b/package.json index dcd791d59..fa96ff063 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "lefthook": "^2.1.9", "npm-check-updates": "^22.2.9", "pg": "^8.22.0", - "turbo": "^2.10.2", + "turbo": "^2.10.3", "typescript": "^6.0.3", "vitest": "^4.1.9" } diff --git a/packages/ai/package.json b/packages/ai/package.json index aa9aece51..57a4af3cb 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -23,12 +23,12 @@ "@reactive-resume/schema": "workspace:*", "@reactive-resume/utils": "workspace:*", "deepmerge-ts": "^7.1.5", - "jsonrepair": "^3.14.1", + "jsonrepair": "^3.15.0", "zod": "^4.4.3" }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/api/package.json b/packages/api/package.json index b1ae99c90..4daa7be66 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -18,7 +18,7 @@ "test:agent": "vitest run --reporter=agent --reporter=json --outputFile.json=reports/vitest-results.json --passWithNoTests" }, "dependencies": { - "@ai-sdk/anthropic": "^4.0.7", + "@ai-sdk/anthropic": "^4.0.8", "@ai-sdk/google": "^4.0.8", "@ai-sdk/openai": "^4.0.7", "@ai-sdk/openai-compatible": "^3.0.5", @@ -34,7 +34,7 @@ "@reactive-resume/resume": "workspace:*", "@reactive-resume/schema": "workspace:*", "@reactive-resume/utils": "workspace:*", - "ai": "^7.0.14", + "ai": "^7.0.15", "bcrypt": "^6.0.0", "better-auth": "1.6.23", "drizzle-orm": "1.0.0-rc.4", @@ -51,7 +51,7 @@ "devDependencies": { "@reactive-resume/config": "workspace:*", "@types/bcrypt": "^6.0.0", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/auth/package.json b/packages/auth/package.json index 119b68ee3..c8e499876 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -35,7 +35,7 @@ "@reactive-resume/config": "workspace:*", "@types/bcrypt": "^6.0.0", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/db/package.json b/packages/db/package.json index 4bcbafc06..03790e426 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@reactive-resume/config": "workspace:*", "@types/pg": "^8.20.0", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "drizzle-kit": "1.0.0-rc.4", "typescript": "^6.0.3" } diff --git a/packages/docx/package.json b/packages/docx/package.json index 7680a81a4..277e1e854 100644 --- a/packages/docx/package.json +++ b/packages/docx/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/docx/src/section-renderers.test.ts b/packages/docx/src/section-renderers.test.ts index 57ff942ee..bd63d3c82 100644 --- a/packages/docx/src/section-renderers.test.ts +++ b/packages/docx/src/section-renderers.test.ts @@ -26,6 +26,8 @@ describe("renderSummary", () => { content: "

Hello

", hidden: true, columns: 1, + keepTogether: false, + startOnNewPage: false, }; expect(renderSummary(summary, HEX)).toEqual([]); }); @@ -37,6 +39,8 @@ describe("renderSummary", () => { content: "", hidden: false, columns: 1, + keepTogether: false, + startOnNewPage: false, }; expect(renderSummary(summary, HEX)).toEqual([]); }); @@ -48,6 +52,8 @@ describe("renderSummary", () => { content: "

Hello world

", hidden: false, columns: 1, + keepTogether: false, + startOnNewPage: false, }; const paragraphs = renderSummary(summary, HEX); // One heading + the htmlToParagraphs output for one

. @@ -61,6 +67,8 @@ describe("renderSummary", () => { content: "

Hello world

", hidden: false, columns: 1, + keepTogether: false, + startOnNewPage: false, }; const paragraphs = renderSummary(summary, HEX); expect(paragraphs.length).toBeGreaterThanOrEqual(1); @@ -73,6 +81,8 @@ const emptySection = (type: T): ResumeData["sections"][T] icon: getDefaultSectionIconName(type), columns: 1, hidden: false, + keepTogether: false, + startOnNewPage: false, items: [], }) as ResumeData["sections"][T]; @@ -99,6 +109,8 @@ describe("renderCustomSection", () => { icon: getDefaultSectionIconName("summary"), columns: 1, hidden: false, + keepTogether: false, + startOnNewPage: false, items: [], }; diff --git a/packages/email/package.json b/packages/email/package.json index e0b2651a0..64024b875 100644 --- a/packages/email/package.json +++ b/packages/email/package.json @@ -26,7 +26,7 @@ "@reactive-resume/config": "workspace:*", "@types/nodemailer": "^8.0.1", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/env/package.json b/packages/env/package.json index 3b6cceea7..ab8d87378 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@reactive-resume/config": "workspace:*", "@types/node": "^26.1.0", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/fonts/package.json b/packages/fonts/package.json index 0a3ea9a0e..4666f5ef3 100644 --- a/packages/fonts/package.json +++ b/packages/fonts/package.json @@ -19,7 +19,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/import/package.json b/packages/import/package.json index be3626bca..d4f6fbfa6 100644 --- a/packages/import/package.json +++ b/packages/import/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 5b4a91451..0d380e7d4 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3", "vitest": "^4.1.9" } diff --git a/packages/pdf/package.json b/packages/pdf/package.json index d57d39798..7d8ab648d 100644 --- a/packages/pdf/package.json +++ b/packages/pdf/package.json @@ -35,7 +35,7 @@ "@react-pdf/types": "^2.11.1", "@reactive-resume/config": "workspace:*", "@types/react": "^19.2.17", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/resume/package.json b/packages/resume/package.json index fbc0f8466..1709acb4d 100644 --- a/packages/resume/package.json +++ b/packages/resume/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/schema/package.json b/packages/schema/package.json index 575cc0995..eefcaa885 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@reactive-resume/config": "workspace:*", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "typescript": "^6.0.3" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index 8e20f7c6b..e03ba3d67 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -23,13 +23,14 @@ "@phosphor-icons/react": "^2.1.10", "@phosphor-icons/web": "^2.1.2", "@reactive-resume/utils": "workspace:*", + "@shadcn/react": "^0.2.0", "class-variance-authority": "^0.7.1", "cmdk": "^1.1.1", "js-cookie": "^3.0.8", "next-themes": "^0.4.6", "react": "^19.2.7", "react-dom": "^19.2.7", - "react-resizable-panels": "^4.12.0", + "react-resizable-panels": "^4.12.1", "shadcn": "^4.13.0", "sonner": "^2.0.7", "tw-animate-css": "^1.4.0" @@ -41,7 +42,7 @@ "@types/js-cookie": "^3.0.6", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@typescript/native-preview": "7.0.0-dev.20260703.1", + "@typescript/native-preview": "7.0.0-dev.20260704.1", "postcss": "^8.5.16", "tailwindcss": "^4.3.2", "typescript": "^6.0.3" diff --git a/packages/ui/src/components/attachment.tsx b/packages/ui/src/components/attachment.tsx new file mode 100644 index 000000000..a2047b2b2 --- /dev/null +++ b/packages/ui/src/components/attachment.tsx @@ -0,0 +1,182 @@ +import type { VariantProps } from "class-variance-authority"; +import type * as React from "react"; +import { mergeProps } from "@base-ui/react/merge-props"; +import { useRender } from "@base-ui/react/use-render"; +import { cva } from "class-variance-authority"; +import { cn } from "@reactive-resume/utils/style"; +import { Button } from "./button"; + +const attachmentVariants = cva( + "group/attachment relative flex w-fit min-w-0 max-w-full shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed", + { + variants: { + size: { + default: + "gap-2 text-sm has-data-[slot=attachment-media]:p-2 has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2", + sm: "gap-2.5 text-xs has-data-[slot=attachment-media]:p-1.5 has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5", + xs: "gap-1.5 rounded-lg text-xs has-data-[slot=attachment-media]:p-1 has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1", + }, + orientation: { + horizontal: "min-w-40 items-center", + vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30", + }, + }, + }, +); + +function Attachment({ + className, + state = "done", + size = "default", + orientation = "horizontal", + ...props +}: React.ComponentProps<"div"> & + VariantProps & { + state?: "idle" | "uploading" | "processing" | "error" | "done"; + }) { + return ( +
+ ); +} + +const attachmentMediaVariants = cva( + "relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none", + { + variants: { + variant: { + icon: "", + image: + "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover", + }, + }, + defaultVariants: { + variant: "icon", + }, + }, +); + +function AttachmentMedia({ + className, + variant = "icon", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function AttachmentContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AttachmentTitle({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ); +} + +function AttachmentDescription({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ); +} + +function AttachmentActions({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AttachmentAction({ className, variant, size = "icon-xs", ...props }: React.ComponentProps) { + return ( +