mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-14 23:07:01 +10:00
- fixes #2711
- fix improper re-ordering of chips - update dependencies, translations
This commit is contained in:
@@ -1,7 +1,4 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
invariant(process.env.DATABASE_URL, "DATABASE_URL is not set");
|
||||
|
||||
export default defineConfig({
|
||||
out: "./migrations",
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"project": ["src/**/*.{js,jsx,ts,tsx,mdx,css}"],
|
||||
"ignoreBinaries": ["mint"],
|
||||
"ignoreDependencies": ["npm-check-updates", "node-addon-api", "node-gyp"],
|
||||
"ignore": ["src/schema/**/*.ts", "src/components/**/*.{ts,tsx}", "src/routeTree.gen.ts"]
|
||||
"ignore": ["src/schema/**/*.ts", "src/components/**/*.{ts,tsx}"]
|
||||
}
|
||||
|
||||
Generated
BIN
Binary file not shown.
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "አጉር"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ዙሉ"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "تصغير"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "الزولو"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Uzaqlaşdır"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Намаляване"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Зулуски"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "জুম আউট"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "জুলু"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Allunya"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulú"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Oddálit"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zoom ud"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Herauszoomen"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Σμίκρυνση"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Ζουλού"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Alejar"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulú"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "کوچکنمایی"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "زولو"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Loitonna"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zoom arrière"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zoulou"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "התרחקות"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "זולו"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "ज़ूम आउट"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ज़ुलु"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Kicsinyítés"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Perkecil"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Rimpicciolisci"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "ズームアウト"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ズールー語"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "បង្រួម"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "ಗಾತ್ರ ಕುಗ್ಗಿಸಿ"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ಜೂಲೂ"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "축소"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "줄루어"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Tolinti"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulų"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Tālināt"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "സൂം ഔട്ട് ചെയ്യുക"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "സൂളു"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "बाहेर झूम करा"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "झुलू"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zum keluar"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "जूम आउट"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "जुलु"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Uitzoomen"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zoom ut"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "ଜୁମ୍ ଆଉଟ୍ କରନ୍ତୁ"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ଜୁଲୁ"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Pomniejsz"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Diminuir zoom"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Afastar"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Micșorează"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Уменьшить"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Зулу"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Oddialiť"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zvogëlo"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Умањи"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Зулу"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Zooma ut"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "சிறிதாக்கு"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ஜூலு"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "జూమ్ అవుట్ చేయండి"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "జులు"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "ซูมออก"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "ซูลู"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Uzaklaştır"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Зменшити"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Зулу"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Kichraytirish"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "Thu nhỏ"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "Zulu"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "缩小"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "祖鲁语"
|
||||
|
||||
|
||||
Generated
-1
@@ -2848,4 +2848,3 @@ msgstr "縮小"
|
||||
#: src/utils/locale.ts
|
||||
msgid "Zulu"
|
||||
msgstr "祖魯語"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+52
-53
@@ -4,7 +4,7 @@
|
||||
"version": "5.0.9",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8",
|
||||
"packageManager": "pnpm@10.30.1+sha512.3590e550d5384caa39bd5c7c739f72270234b2f6059e13018f975c313b1eb9fefcc09714048765d4d9efe961382c312e624572c0420762bdc5d5940cdf9be73a",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/amruthpillai/reactive-resume.git"
|
||||
@@ -31,45 +31,45 @@
|
||||
"typecheck": "tsgo --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^3.0.39",
|
||||
"@ai-sdk/google": "^3.0.23",
|
||||
"@ai-sdk/openai": "^3.0.26",
|
||||
"@ai-sdk/react": "^3.0.80",
|
||||
"@aws-sdk/client-s3": "^3.986.0",
|
||||
"@better-auth/core": "1.5.0-beta.13",
|
||||
"@ai-sdk/anthropic": "^3.0.46",
|
||||
"@ai-sdk/google": "^3.0.30",
|
||||
"@ai-sdk/openai": "^3.0.30",
|
||||
"@ai-sdk/react": "^3.0.99",
|
||||
"@aws-sdk/client-s3": "^3.995.0",
|
||||
"@better-auth/core": "1.5.0-beta.18",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fontsource-variable/ibm-plex-sans": "^5.2.8",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@lingui/core": "^5.9.0",
|
||||
"@lingui/react": "^5.9.0",
|
||||
"@lingui/core": "^5.9.2",
|
||||
"@lingui/react": "^5.9.2",
|
||||
"@monaco-editor/react": "4.8.0-rc.3",
|
||||
"@orpc/client": "^1.13.4",
|
||||
"@orpc/json-schema": "^1.13.4",
|
||||
"@orpc/openapi": "^1.13.4",
|
||||
"@orpc/server": "^1.13.4",
|
||||
"@orpc/tanstack-query": "^1.13.4",
|
||||
"@orpc/zod": "^1.13.4",
|
||||
"@orpc/client": "^1.13.5",
|
||||
"@orpc/json-schema": "^1.13.5",
|
||||
"@orpc/openapi": "^1.13.5",
|
||||
"@orpc/server": "^1.13.5",
|
||||
"@orpc/tanstack-query": "^1.13.5",
|
||||
"@orpc/zod": "^1.13.5",
|
||||
"@phosphor-icons/react": "^2.1.10",
|
||||
"@phosphor-icons/web": "^2.1.2",
|
||||
"@sindresorhus/slugify": "^3.0.0",
|
||||
"@t3-oss/env-core": "^0.13.10",
|
||||
"@tanstack/react-query": "5.90.20",
|
||||
"@tanstack/react-router": "^1.159.5",
|
||||
"@tanstack/react-router-ssr-query": "^1.159.5",
|
||||
"@tanstack/react-start": "^1.159.5",
|
||||
"@tanstack/zod-adapter": "^1.159.5",
|
||||
"@tiptap/extension-highlight": "^3.19.0",
|
||||
"@tiptap/extension-table": "^3.19.0",
|
||||
"@tiptap/extension-text-align": "^3.19.0",
|
||||
"@tiptap/pm": "^3.19.0",
|
||||
"@tiptap/react": "^3.19.0",
|
||||
"@tiptap/starter-kit": "^3.19.0",
|
||||
"ai": "^6.0.78",
|
||||
"ai-sdk-ollama": "^3.5.0",
|
||||
"@tanstack/react-query": "5.90.21",
|
||||
"@tanstack/react-router": "^1.162.6",
|
||||
"@tanstack/react-router-ssr-query": "^1.162.6",
|
||||
"@tanstack/react-start": "^1.162.6",
|
||||
"@tanstack/zod-adapter": "^1.162.6",
|
||||
"@tiptap/extension-highlight": "^3.20.0",
|
||||
"@tiptap/extension-table": "^3.20.0",
|
||||
"@tiptap/extension-text-align": "^3.20.0",
|
||||
"@tiptap/pm": "^3.20.0",
|
||||
"@tiptap/react": "^3.20.0",
|
||||
"@tiptap/starter-kit": "^3.20.0",
|
||||
"ai": "^6.0.97",
|
||||
"ai-sdk-ollama": "^3.7.1",
|
||||
"bcrypt": "^6.0.0",
|
||||
"better-auth": "1.5.0-beta.13",
|
||||
"better-auth": "1.5.0-beta.18",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -81,29 +81,28 @@
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-json-patch": "^3.1.1",
|
||||
"fuse.js": "^7.1.0",
|
||||
"immer": "^11.1.3",
|
||||
"immer": "^11.1.4",
|
||||
"input-otp": "^1.4.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"motion": "^12.34.0",
|
||||
"motion": "^12.34.3",
|
||||
"nodemailer": "^8.0.1",
|
||||
"pg": "^8.18.0",
|
||||
"puppeteer-core": "^24.37.2",
|
||||
"puppeteer-core": "^24.37.5",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-hook-form": "^7.71.1",
|
||||
"react-hook-form": "^7.71.2",
|
||||
"react-hotkeys-hook": "^5.2.4",
|
||||
"react-resizable-panels": "^4.6.2",
|
||||
"react-window": "^2.2.6",
|
||||
"react-resizable-panels": "^4.6.5",
|
||||
"react-window": "^2.2.7",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"shadcn": "^3.8.4",
|
||||
"shadcn": "^3.8.5",
|
||||
"sharp": "^0.34.5",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"ts-pattern": "^5.9.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
@@ -115,34 +114,34 @@
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.14",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.9.0",
|
||||
"@lingui/cli": "^5.9.0",
|
||||
"@lingui/vite-plugin": "^5.9.0",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@biomejs/biome": "^2.4.4",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
||||
"@lingui/cli": "^5.9.2",
|
||||
"@lingui/vite-plugin": "^5.9.2",
|
||||
"@tailwindcss/vite": "^4.2.1",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^25.2.2",
|
||||
"@types/nodemailer": "^7.0.9",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/nodemailer": "^7.0.11",
|
||||
"@types/pg": "^8.16.0",
|
||||
"@types/react": "^19.2.13",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260209.1",
|
||||
"@vitejs/plugin-react": "^5.1.3",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260223.1",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"drizzle-kit": "^1.0.0-beta.15-859cf75",
|
||||
"knip": "^5.83.1",
|
||||
"knip": "^5.85.0",
|
||||
"nitro": "npm:nitro-nightly@latest",
|
||||
"node-addon-api": "^8.5.0",
|
||||
"node-gyp": "^12.2.0",
|
||||
"npm-check-updates": "^19.3.2",
|
||||
"npm-check-updates": "^19.4.1",
|
||||
"tsx": "^4.21.0",
|
||||
"vite": "^8.0.0-beta.13",
|
||||
"vite": "^8.0.0-beta.15",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"vite": "^8.0.0-beta.13"
|
||||
"vite": "^8.0.0-beta.15"
|
||||
},
|
||||
"onlyBuiltDependencies": [
|
||||
"@prisma/engines",
|
||||
|
||||
Generated
+1785
-1966
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,22 @@
|
||||
import {
|
||||
closestCenter,
|
||||
DndContext,
|
||||
type DragEndEvent,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from "@dnd-kit/core";
|
||||
import {
|
||||
horizontalListSortingStrategy,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
useSortable,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { PencilSimpleIcon, XIcon } from "@phosphor-icons/react";
|
||||
import { motion, Reorder, useDragControls } from "motion/react";
|
||||
import { motion } from "motion/react";
|
||||
import * as React from "react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -12,6 +28,7 @@ const RETURN_KEY = "Enter";
|
||||
const COMMA_KEY = ",";
|
||||
|
||||
type ChipItemProps = {
|
||||
id: string;
|
||||
chip: string;
|
||||
index: number;
|
||||
isEditing: boolean;
|
||||
@@ -19,35 +36,37 @@ type ChipItemProps = {
|
||||
onRemove: (index: number) => void;
|
||||
};
|
||||
|
||||
function ChipItem({ chip, index, isEditing, onEdit, onRemove }: ChipItemProps) {
|
||||
const controls = useDragControls();
|
||||
function ChipItem({ id, chip, index, isEditing, onEdit, onRemove }: ChipItemProps) {
|
||||
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });
|
||||
|
||||
const [isHovered, setIsHovered] = React.useState(false);
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
zIndex: isDragging ? 10 : undefined,
|
||||
opacity: isDragging ? 0.6 : 1,
|
||||
};
|
||||
|
||||
return (
|
||||
<Reorder.Item
|
||||
value={chip}
|
||||
dragListener={false}
|
||||
dragControls={controls}
|
||||
initial={{ opacity: 1, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="relative"
|
||||
<div
|
||||
style={style}
|
||||
ref={setNodeRef}
|
||||
className="relative touch-none"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"flex h-7 cursor-grab select-none items-center gap-0 overflow-hidden px-3 active:cursor-grabbing",
|
||||
isEditing && "border-primary ring-1 ring-primary",
|
||||
isDragging && "opacity-80",
|
||||
)}
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault();
|
||||
controls.start(e);
|
||||
}}
|
||||
>
|
||||
<span className="max-w-32 truncate">{chip}</span>
|
||||
|
||||
<motion.div
|
||||
initial={false}
|
||||
animate={{ width: isHovered ? 40 : 0, marginInlineStart: isHovered ? 8 : 0, opacity: isHovered ? 1 : 0 }}
|
||||
@@ -80,7 +99,7 @@ function ChipItem({ chip, index, isEditing, onEdit, onRemove }: ChipItemProps) {
|
||||
</button>
|
||||
</motion.div>
|
||||
</Badge>
|
||||
</Reorder.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -116,7 +135,6 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
const trimmed = newValue.trim();
|
||||
if (!trimmed || index < 0 || index >= chips.length) return;
|
||||
|
||||
// Check if the new value already exists at a different index
|
||||
const existingIndex = chips.findIndex((c, i) => c === trimmed && i !== index);
|
||||
if (existingIndex !== -1) return;
|
||||
|
||||
@@ -133,12 +151,10 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
const newChips = chips.slice(0, index).concat(chips.slice(index + 1));
|
||||
setChips(newChips);
|
||||
|
||||
// If we were editing this chip, clear edit mode
|
||||
if (editingIndex === index) {
|
||||
setEditingIndex(null);
|
||||
setInput("");
|
||||
} else if (editingIndex !== null && editingIndex > index) {
|
||||
// Adjust editing index if we removed a chip before it
|
||||
setEditingIndex(editingIndex - 1);
|
||||
}
|
||||
},
|
||||
@@ -156,7 +172,6 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
|
||||
const handleReorder = React.useCallback(
|
||||
(newOrder: string[]) => {
|
||||
// Update editingIndex to follow the chip being edited
|
||||
if (editingIndex !== null) {
|
||||
const editingChip = chips[editingIndex];
|
||||
const newIndex = newOrder.indexOf(editingChip);
|
||||
@@ -169,14 +184,37 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
[chips, editingIndex, setChips],
|
||||
);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: { distance: 3 },
|
||||
}),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
}),
|
||||
);
|
||||
|
||||
const handleDragEnd = React.useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id) return;
|
||||
const oldIndex = chips.indexOf(active.id as string);
|
||||
const newIndex = chips.indexOf(over.id as string);
|
||||
if (oldIndex !== -1 && newIndex !== -1 && oldIndex !== newIndex) {
|
||||
const newOrder = Array.from(chips);
|
||||
const [removed] = newOrder.splice(oldIndex, 1);
|
||||
newOrder.splice(newIndex, 0, removed);
|
||||
handleReorder(newOrder);
|
||||
}
|
||||
},
|
||||
[chips, handleReorder],
|
||||
);
|
||||
|
||||
const handleInputChange = React.useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value;
|
||||
|
||||
// When editing, don't split on comma - allow full text editing
|
||||
if (editingIndex !== null) {
|
||||
if (newValue.includes(",")) {
|
||||
// Save current edit
|
||||
updateChip(editingIndex, newValue.replace(",", ""));
|
||||
setEditingIndex(null);
|
||||
setInput("");
|
||||
@@ -186,7 +224,6 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
return;
|
||||
}
|
||||
|
||||
// When adding new chips, split on comma
|
||||
if (newValue.includes(",")) {
|
||||
const parts = newValue.split(",");
|
||||
parts.slice(0, -1).forEach(addChip);
|
||||
@@ -204,19 +241,16 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
e.preventDefault();
|
||||
|
||||
if (editingIndex !== null) {
|
||||
// Save edit
|
||||
if (input.trim()) {
|
||||
updateChip(editingIndex, input);
|
||||
}
|
||||
setEditingIndex(null);
|
||||
setInput("");
|
||||
} else if (input.trim()) {
|
||||
// Add new chip
|
||||
addChip(input);
|
||||
setInput("");
|
||||
}
|
||||
} else if (e.key === "Escape" && editingIndex !== null) {
|
||||
// Cancel edit
|
||||
setEditingIndex(null);
|
||||
setInput("");
|
||||
}
|
||||
@@ -227,18 +261,23 @@ export function ChipInput({ value, defaultValue = [], onChange, className, ...pr
|
||||
return (
|
||||
<div className={cn("flex flex-col gap-2", className)} {...props}>
|
||||
{chips.length > 0 && (
|
||||
<Reorder.Group axis="x" values={chips} onReorder={handleReorder} className="flex flex-wrap gap-1.5">
|
||||
{chips.map((chip, idx) => (
|
||||
<ChipItem
|
||||
key={`${chip}-${idx}`}
|
||||
chip={chip}
|
||||
index={idx}
|
||||
isEditing={editingIndex === idx}
|
||||
onEdit={handleEdit}
|
||||
onRemove={removeChip}
|
||||
/>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={chips} strategy={horizontalListSortingStrategy}>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{chips.map((chip, idx) => (
|
||||
<ChipItem
|
||||
key={`${chip}-${idx}`}
|
||||
id={chip}
|
||||
chip={chip}
|
||||
index={idx}
|
||||
isEditing={editingIndex === idx}
|
||||
onEdit={handleEdit}
|
||||
onRemove={removeChip}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import type { MessageDescriptor } from "@lingui/core";
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import { useLingui } from "@lingui/react";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { PencilSimpleLineIcon, PlusIcon } from "@phosphor-icons/react";
|
||||
import { useForm, useFormContext } from "react-hook-form";
|
||||
import type z from "zod";
|
||||
import { useResumeStore } from "@/components/resume/store/resume";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Combobox } from "@/components/ui/combobox";
|
||||
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -18,21 +22,21 @@ const formSchema = customSectionSchema;
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
|
||||
const SECTION_TYPE_OPTIONS: { value: CustomSectionType; label: string }[] = [
|
||||
{ value: "summary", label: "Summary" },
|
||||
{ value: "experience", label: "Experience" },
|
||||
{ value: "education", label: "Education" },
|
||||
{ value: "projects", label: "Projects" },
|
||||
{ value: "profiles", label: "Profiles" },
|
||||
{ value: "skills", label: "Skills" },
|
||||
{ value: "languages", label: "Languages" },
|
||||
{ value: "interests", label: "Interests" },
|
||||
{ value: "awards", label: "Awards" },
|
||||
{ value: "certifications", label: "Certifications" },
|
||||
{ value: "publications", label: "Publications" },
|
||||
{ value: "volunteer", label: "Volunteer" },
|
||||
{ value: "references", label: "References" },
|
||||
{ value: "cover-letter", label: "Cover Letter" },
|
||||
const SECTION_TYPE_OPTIONS: { value: CustomSectionType; label: MessageDescriptor }[] = [
|
||||
{ value: "summary", label: msg`Summary` },
|
||||
{ value: "experience", label: msg`Experience` },
|
||||
{ value: "education", label: msg`Education` },
|
||||
{ value: "projects", label: msg`Projects` },
|
||||
{ value: "profiles", label: msg`Profiles` },
|
||||
{ value: "skills", label: msg`Skills` },
|
||||
{ value: "languages", label: msg`Languages` },
|
||||
{ value: "interests", label: msg`Interests` },
|
||||
{ value: "awards", label: msg`Awards` },
|
||||
{ value: "certifications", label: msg`Certifications` },
|
||||
{ value: "publications", label: msg`Publications` },
|
||||
{ value: "volunteer", label: msg`Volunteer` },
|
||||
{ value: "references", label: msg`References` },
|
||||
{ value: "cover-letter", label: msg`Cover Letter` },
|
||||
];
|
||||
|
||||
export function CreateCustomSectionDialog({ data }: DialogProps<"resume.sections.custom.create">) {
|
||||
@@ -150,6 +154,7 @@ export function UpdateCustomSectionDialog({ data }: DialogProps<"resume.sections
|
||||
}
|
||||
|
||||
function CustomSectionForm({ isUpdate = false }: { isUpdate?: boolean }) {
|
||||
const { i18n } = useLingui();
|
||||
const form = useFormContext<FormValues>();
|
||||
|
||||
return (
|
||||
@@ -179,17 +184,16 @@ function CustomSectionForm({ isUpdate = false }: { isUpdate?: boolean }) {
|
||||
<Trans>Section Type</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<select
|
||||
<Combobox
|
||||
{...field}
|
||||
value={field.value}
|
||||
disabled={isUpdate}
|
||||
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{SECTION_TYPE_OPTIONS.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
onValueChange={field.onChange}
|
||||
options={SECTION_TYPE_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: i18n.t(option.label),
|
||||
}))}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -16,18 +16,14 @@ import { cn } from "@/utils/style";
|
||||
export const Route = createFileRoute("/$username/$slug")({
|
||||
component: RouteComponent,
|
||||
loader: async ({ context, params: { username, slug } }) => {
|
||||
try {
|
||||
// Ignore .well-known requests
|
||||
if (username === ".well-known") throw notFound();
|
||||
// Ignore .well-known requests
|
||||
if (username === ".well-known") throw notFound();
|
||||
|
||||
const resume = await context.queryClient.ensureQueryData(
|
||||
orpc.resume.getBySlug.queryOptions({ input: { username, slug } }),
|
||||
);
|
||||
const resume = await context.queryClient.ensureQueryData(
|
||||
orpc.resume.getBySlug.queryOptions({ input: { username, slug } }),
|
||||
);
|
||||
|
||||
return { resume };
|
||||
} catch {
|
||||
throw notFound();
|
||||
}
|
||||
return { resume };
|
||||
},
|
||||
head: ({ loaderData }) => ({
|
||||
meta: [{ title: loaderData ? `${loaderData.resume.name} - Reactive Resume` : "Reactive Resume" }],
|
||||
@@ -86,7 +82,7 @@ function RouteComponent() {
|
||||
size="lg"
|
||||
variant="secondary"
|
||||
disabled={isPrinting}
|
||||
className="fixed end-4 bottom-4 z-50 hidden rounded-full px-4 md:inline-flex print:hidden"
|
||||
className="fixed inset-e-4 bottom-4 z-50 hidden rounded-full px-4 md:inline-flex print:hidden"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
{isPrinting ? <Spinner /> : <DownloadSimpleIcon />}
|
||||
|
||||
Reference in New Issue
Block a user