diff --git a/.gitignore b/.gitignore index 2c7f28e..ff32fa6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,11 @@ /.next/ /out/ +# nuxt +.nuxt +.nitro +.output + # production /build @@ -47,3 +52,17 @@ next-env.d.ts # wrangler files .wrangler .dev.vars + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Logs +logs +*.log + +# Cache +.cache +.parcel-cache diff --git a/README.md b/README.md index 46b19c1..30317af 100644 --- a/README.md +++ b/README.md @@ -33,19 +33,19 @@ Try it online: [cloudmark.site](https://cloudmark.site) ### Prerequisites -- Node.js 15+ and pnpm +- Node.js 18+ and npm/yarn - Cloudflare account (for preview and deployment) ### Install Dependencies ```bash -pnpm install +npm install ``` ### Development Mode ```bash -pnpm dev +npm run dev ``` Visit [http://localhost:3000](http://localhost:3000) to see the result. @@ -53,13 +53,13 @@ Visit [http://localhost:3000](http://localhost:3000) to see the result. ### Local Preview with Cloudflare Pages ```bash -pnpm preview +npm run preview ``` ### Build and Deploy ```bash -pnpm deploy +npm run deploy ``` ## Cloudflare Configuration @@ -85,11 +85,27 @@ Cloudmark uses Cloudflare KV to store bookmark data. You need to: ## Technology Stack -- [Next.js](https://nextjs.org/) - React framework +- [Nuxt 3](https://nuxt.com/) - Vue.js framework +- [Vue 3](https://vuejs.org/) - Progressive JavaScript framework - [Cloudflare Pages](https://pages.cloudflare.com/) - Hosting and serverless functions - [Cloudflare KV](https://developers.cloudflare.com/workers/runtime-apis/kv/) - Data storage - [Tailwind CSS](https://tailwindcss.com/) - Styling -- [Next-Intl](https://next-intl-docs.vercel.app/) - Internationalization +- [Vue i18n](https://vue-i18n.intlify.dev/) - Internationalization +- [TypeScript](https://www.typescriptlang.org/) - Type safety + +## Migration from Next.js + +This project has been migrated from Next.js + React to Nuxt 3 + Vue 3. Key changes include: + +- **Framework**: Next.js → Nuxt 3 +- **UI Library**: React → Vue 3 with Composition API +- **Routing**: Next.js Router → Vue Router (via Nuxt) +- **State Management**: React hooks → Vue Composition API +- **Server**: Next.js API Routes → Nuxt 3 Server API +- **Internationalization**: next-intl → Vue i18n +- **Build**: Next.js build → Nitro (Nuxt's build engine) + +All functionality has been preserved while modernizing the tech stack. ## License diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..b58c4d4 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,209 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96%; + --secondary-foreground: 222.2 84% 4.9%; + --muted: 210 40% 96%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96%; + --accent-foreground: 222.2 84% 4.9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.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; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 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%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +/* Custom animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0.8); + } + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-fadeIn { + animation: fadeIn 0.6s ease-out forwards; +} + +.animate-fadeUp { + animation: fadeUp 0.6s ease-out forwards; +} + +.animate-scaleIn { + animation: scaleIn 0.6s ease-out forwards; +} + +.animate-slideIn { + animation: slideIn 0.6s ease-out forwards; +} + +/* Animation delays */ +.animation-delay-200 { + animation-delay: 200ms; +} + +.animation-delay-400 { + animation-delay: 400ms; +} + +.animation-delay-600 { + animation-delay: 600ms; +} + +.animation-delay-700 { + animation-delay: 700ms; +} + +.animation-delay-800 { + animation-delay: 800ms; +} + +.animation-delay-900 { + animation-delay: 900ms; +} + +/* Stagger animations */ +.stagger-container { + --stagger-delay: 100ms; +} + +.stagger-item { + opacity: 0; + animation: fadeIn 0.6s ease-out forwards; +} + +.stagger-item:nth-child(1) { animation-delay: calc(1 * var(--stagger-delay)); } +.stagger-item:nth-child(2) { animation-delay: calc(2 * var(--stagger-delay)); } +.stagger-item:nth-child(3) { animation-delay: calc(3 * var(--stagger-delay)); } +.stagger-item:nth-child(4) { animation-delay: calc(4 * var(--stagger-delay)); } +.stagger-item:nth-child(5) { animation-delay: calc(5 * var(--stagger-delay)); } +.stagger-item:nth-child(6) { animation-delay: calc(6 * var(--stagger-delay)); } +.stagger-item:nth-child(7) { animation-delay: calc(7 * var(--stagger-delay)); } +.stagger-item:nth-child(8) { animation-delay: calc(8 * var(--stagger-delay)); } +.stagger-item:nth-child(9) { animation-delay: calc(9 * var(--stagger-delay)); } + +/* Interactive elements */ +.hover-scale { + transition: transform 0.2s ease-in-out; +} + +.hover-scale:hover { + transform: scale(1.05); +} + +.active-scale:active { + transform: scale(0.95); +} + +/* Feature card animations */ +.feature-card { + transition: all 0.3s ease; +} + +.feature-card:hover { + transform: translateY(-4px); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); +} + +/* Delay classes for animations */ +.delay-100 { animation-delay: 100ms; } +.delay-200 { animation-delay: 200ms; } +.delay-300 { animation-delay: 300ms; } +.delay-400 { animation-delay: 400ms; } +.delay-500 { animation-delay: 500ms; } +.delay-600 { animation-delay: 600ms; } +.delay-700 { animation-delay: 700ms; } +.delay-800 { animation-delay: 800ms; } +.delay-900 { animation-delay: 900ms; } \ No newline at end of file diff --git a/components/AppFooter.vue b/components/AppFooter.vue new file mode 100644 index 0000000..541e12c --- /dev/null +++ b/components/AppFooter.vue @@ -0,0 +1,24 @@ + + + \ No newline at end of file diff --git a/components/AppHeader.vue b/components/AppHeader.vue new file mode 100644 index 0000000..93398c5 --- /dev/null +++ b/components/AppHeader.vue @@ -0,0 +1,52 @@ + + + \ No newline at end of file diff --git a/components/BookmarkCard.vue b/components/BookmarkCard.vue new file mode 100644 index 0000000..dd5cc47 --- /dev/null +++ b/components/BookmarkCard.vue @@ -0,0 +1,130 @@ + + + + + \ No newline at end of file diff --git a/components/BookmarkUI.vue b/components/BookmarkUI.vue new file mode 100644 index 0000000..e3ef6f2 --- /dev/null +++ b/components/BookmarkUI.vue @@ -0,0 +1,182 @@ + + + \ No newline at end of file diff --git a/components/BookmarkletButton.vue b/components/BookmarkletButton.vue new file mode 100644 index 0000000..f3e2d0e --- /dev/null +++ b/components/BookmarkletButton.vue @@ -0,0 +1,60 @@ + + + \ No newline at end of file diff --git a/components/DemoBanner.vue b/components/DemoBanner.vue new file mode 100644 index 0000000..7624c53 --- /dev/null +++ b/components/DemoBanner.vue @@ -0,0 +1,45 @@ + + + \ No newline at end of file diff --git a/components/DialogAdd.vue b/components/DialogAdd.vue new file mode 100644 index 0000000..ab94b71 --- /dev/null +++ b/components/DialogAdd.vue @@ -0,0 +1,198 @@ +