diff --git a/frontend/.gitignore b/frontend/.gitignore
index 5ef6a520..a547bf36 100644
--- a/frontend/.gitignore
+++ b/frontend/.gitignore
@@ -1,41 +1,24 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.*
-.yarn/*
-!.yarn/patches
-!.yarn/plugins
-!.yarn/releases
-!.yarn/versions
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# misc
-.DS_Store
-*.pem
-
-# debug
+# Logs
+logs
+*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-.pnpm-debug.log*
-
-# env files (can opt-in for committing if needed)
-.env*
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/frontend/README.md b/frontend/README.md
index e215bc4c..a36934d8 100644
--- a/frontend/README.md
+++ b/frontend/README.md
@@ -1,36 +1,16 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+# React + Vite
-## Getting Started
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-First, run the development server:
+Currently, two official plugins are available:
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+## React Compiler
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+## Expanding the ESLint configuration
-## Learn More
-
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js
new file mode 100644
index 00000000..ea36dd3d
--- /dev/null
+++ b/frontend/eslint.config.js
@@ -0,0 +1,21 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{js,jsx}'],
+ extends: [
+ js.configs.recommended,
+ reactHooks.configs.flat.recommended,
+ reactRefresh.configs.vite,
+ ],
+ languageOptions: {
+ globals: globals.browser,
+ parserOptions: { ecmaFeatures: { jsx: true } },
+ },
+ },
+])
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 00000000..e7006852
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Daily Sushi
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
index 72b917d9..f3287994 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,27 +1,33 @@
{
"name": "frontend",
- "version": "0.1.0",
"private": true,
+ "version": "0.0.0",
+ "type": "module",
"scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
+ "dev": "vite --host 0.0.0.0",
+ "build": "vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
},
"dependencies": {
- "react": "^19.0.0",
- "react-dom": "^19.0.0",
- "next": "15.2.4"
+ "gsap": "^3.15.0",
+ "lucide-react": "^1.17.0",
+ "react": "^19.2.6",
+ "react-dom": "^19.2.6"
},
"devDependencies": {
- "typescript": "^5",
- "@types/node": "^20",
- "@types/react": "^19",
- "@types/react-dom": "^19",
- "@tailwindcss/postcss": "^4",
- "tailwindcss": "^4",
- "eslint": "^9",
- "eslint-config-next": "15.2.4",
- "@eslint/eslintrc": "^3"
+ "@eslint/js": "^10.0.1",
+ "@tailwindcss/vite": "^4.3.0",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.1",
+ "autoprefixer": "^10.5.0",
+ "eslint": "^10.3.0",
+ "eslint-plugin-react-hooks": "^7.1.1",
+ "eslint-plugin-react-refresh": "^0.5.2",
+ "globals": "^17.6.0",
+ "postcss": "^8.5.15",
+ "tailwindcss": "^4.3.0",
+ "vite": "^8.0.12"
}
}
diff --git a/frontend/postcss.config.mjs b/frontend/postcss.config.mjs
index c7bcb4b1..7738160a 100644
--- a/frontend/postcss.config.mjs
+++ b/frontend/postcss.config.mjs
@@ -1,5 +1,5 @@
-const config = {
- plugins: ["@tailwindcss/postcss"],
+export default {
+ plugins: {
+ autoprefixer: {},
+ },
};
-
-export default config;
diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg
new file mode 100644
index 00000000..6893eb13
--- /dev/null
+++ b/frontend/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/icons.svg b/frontend/public/icons.svg
new file mode 100644
index 00000000..e9522193
--- /dev/null
+++ b/frontend/public/icons.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
new file mode 100644
index 00000000..ac89c08c
--- /dev/null
+++ b/frontend/src/App.jsx
@@ -0,0 +1,44 @@
+import { useEffect, useState } from "react";
+import Landing from "./landing/Landing.jsx";
+import Login from "./login/Login.jsx";
+
+function getRouteFromHash() {
+ return window.location.hash.replace("#", "") || "/";
+}
+
+function App() {
+ const [route, setRoute] = useState(getRouteFromHash);
+
+ useEffect(() => {
+ function handleHashChange() {
+ setRoute(getRouteFromHash());
+ }
+
+ window.addEventListener("hashchange", handleHashChange);
+ return () => window.removeEventListener("hashchange", handleHashChange);
+ }, []);
+
+ function handleLoginClick() {
+ window.location.hash = "/login";
+ }
+
+ function handleHomeClick() {
+ window.location.hash = "/";
+ }
+
+ if (route === "/login") {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+export default App;
diff --git a/frontend/src/app/favicon.ico b/frontend/src/app/favicon.ico
deleted file mode 100644
index 718d6fea..00000000
Binary files a/frontend/src/app/favicon.ico and /dev/null differ
diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
deleted file mode 100644
index a2dc41ec..00000000
--- a/frontend/src/app/globals.css
+++ /dev/null
@@ -1,26 +0,0 @@
-@import "tailwindcss";
-
-:root {
- --background: #ffffff;
- --foreground: #171717;
-}
-
-@theme inline {
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
-}
-
-body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
-}
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
deleted file mode 100644
index f7fa87eb..00000000
--- a/frontend/src/app/layout.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "./globals.css";
-
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
-});
-
-export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
-
-export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
-}>) {
- return (
-
-
- {children}
-
-
- );
-}
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
deleted file mode 100644
index e68abe6b..00000000
--- a/frontend/src/app/page.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import Image from "next/image";
-
-export default function Home() {
- return (
-
-
-
-
-
- Get started by editing{" "}
-
- src/app/page.tsx
-
- .
-
-
- Save and see your changes instantly.
-
-
-
-
-
-
-
- );
-}
diff --git a/frontend/src/assets/Logo.png b/frontend/src/assets/Logo.png
new file mode 100644
index 00000000..7c8523ce
Binary files /dev/null and b/frontend/src/assets/Logo.png differ
diff --git a/frontend/src/assets/bg-1.jpg b/frontend/src/assets/bg-1.jpg
new file mode 100644
index 00000000..4fd8e469
Binary files /dev/null and b/frontend/src/assets/bg-1.jpg differ
diff --git a/frontend/src/assets/cheesy-baked-sushi.jpg b/frontend/src/assets/cheesy-baked-sushi.jpg
new file mode 100644
index 00000000..3d4d22ef
Binary files /dev/null and b/frontend/src/assets/cheesy-baked-sushi.jpg differ
diff --git a/frontend/src/assets/hero-section.jpg b/frontend/src/assets/hero-section.jpg
new file mode 100644
index 00000000..7a724bb0
Binary files /dev/null and b/frontend/src/assets/hero-section.jpg differ
diff --git a/frontend/src/assets/icon.jpg b/frontend/src/assets/icon.jpg
new file mode 100644
index 00000000..3160469c
Binary files /dev/null and b/frontend/src/assets/icon.jpg differ
diff --git a/frontend/src/assets/japanese-bg.jpg b/frontend/src/assets/japanese-bg.jpg
new file mode 100644
index 00000000..fd8e31f4
Binary files /dev/null and b/frontend/src/assets/japanese-bg.jpg differ
diff --git a/frontend/src/assets/product-1.jpg b/frontend/src/assets/product-1.jpg
new file mode 100644
index 00000000..8a21cb8f
Binary files /dev/null and b/frontend/src/assets/product-1.jpg differ
diff --git a/frontend/src/assets/product-2.jpg b/frontend/src/assets/product-2.jpg
new file mode 100644
index 00000000..7275885c
Binary files /dev/null and b/frontend/src/assets/product-2.jpg differ
diff --git a/frontend/src/assets/product-3.jpg b/frontend/src/assets/product-3.jpg
new file mode 100644
index 00000000..61fd5d18
Binary files /dev/null and b/frontend/src/assets/product-3.jpg differ
diff --git a/frontend/src/assets/review-1.jpg b/frontend/src/assets/review-1.jpg
new file mode 100644
index 00000000..35c4d699
Binary files /dev/null and b/frontend/src/assets/review-1.jpg differ
diff --git a/frontend/src/assets/review-2.jpg b/frontend/src/assets/review-2.jpg
new file mode 100644
index 00000000..5a2e8912
Binary files /dev/null and b/frontend/src/assets/review-2.jpg differ
diff --git a/frontend/src/assets/review-3.jpg b/frontend/src/assets/review-3.jpg
new file mode 100644
index 00000000..ee4e9595
Binary files /dev/null and b/frontend/src/assets/review-3.jpg differ
diff --git a/frontend/src/assets/review-4.jpg b/frontend/src/assets/review-4.jpg
new file mode 100644
index 00000000..cda3e4a2
Binary files /dev/null and b/frontend/src/assets/review-4.jpg differ
diff --git a/frontend/src/assets/review-5.jpg b/frontend/src/assets/review-5.jpg
new file mode 100644
index 00000000..2212adf3
Binary files /dev/null and b/frontend/src/assets/review-5.jpg differ
diff --git a/frontend/src/components/ThemeComponents.jsx b/frontend/src/components/ThemeComponents.jsx
new file mode 100644
index 00000000..cb9ec38e
--- /dev/null
+++ b/frontend/src/components/ThemeComponents.jsx
@@ -0,0 +1,189 @@
+const shared = {
+ layout: {
+ shell: "mx-auto w-full max-w-7xl px-5 sm:px-6 lg:px-10",
+ section: "py-16 sm:py-20 lg:py-24",
+ eyebrow: "text-xs font-bold uppercase tracking-[0.26em]",
+ navLink: "text-sm font-semibold transition",
+ rounded: "rounded-[1.75rem]",
+ },
+};
+
+export const themeComponents = {
+ dailySushi: {
+ ...shared,
+ page: "bg-[#FFF8F0] text-[#1F2937]",
+ sections: {
+ cream: "bg-[#FFF8F0]",
+ white: "bg-white",
+ charcoal: "bg-[#1F2937] text-white",
+ beige: "bg-[#F5E6D3]",
+ red: "bg-[#E63946] text-white",
+ },
+ text: {
+ primary: "text-[#1F2937]",
+ secondary: "text-[#1F2937]/68",
+ body: "text-[#1F2937]/78",
+ muted: "text-[#1F2937]/48",
+ accent: "text-[#E63946]",
+ gold: "text-[#D4A017]",
+ cream: "text-[#F5E6D3]",
+ inverted: "text-white",
+ invertedMuted: "text-white/60",
+ invertedSecondary: "text-white/70",
+ heroBody: "text-white/84",
+ footerMuted: "text-white/48",
+ hoverInverted: "hover:text-white",
+ online: "text-emerald-700",
+ },
+ nav: {
+ bar: "border-slate-200 bg-[#FFF8F0]/88 backdrop-blur-xl",
+ brand: "text-[#1F2937]",
+ link: "text-[#1F2937]/70 hover:text-[#E63946]",
+ mobileButton: "border-[#1F2937]/10 bg-white text-[#1F2937]",
+ mobilePanel: "border-[#1F2937]/10 bg-[#FFF8F0]",
+ mobileLink: "text-[#1F2937]/75 hover:bg-white",
+ },
+ buttons: {
+ primary: "bg-[#E63946] text-white shadow-lg shadow-[#E63946]/25 hover:bg-[#c92d39]",
+ primarySoftShadow: "bg-[#E63946] text-white shadow-xl shadow-[#E63946]/30 hover:bg-[#c92d39]",
+ primaryPlain: "bg-[#E63946] text-white hover:bg-[#c92d39]",
+ secondaryOnDark: "border-white/30 bg-white/12 text-white backdrop-blur-md hover:bg-white hover:text-[#1F2937]",
+ outlineOnDark: "border-white/20 text-white hover:bg-white hover:text-[#1F2937]",
+ lightOnRed: "bg-white text-[#E63946] shadow-xl shadow-[#1F2937]/15 hover:bg-[#FFF8F0]",
+ iconLight: "border-[#1F2937]/10 bg-white text-[#1F2937] shadow-sm hover:bg-[#E63946] hover:text-white disabled:hover:bg-white disabled:hover:text-[#1F2937]",
+ chatSocial: "border-white/15 transition hover:bg-white hover:text-[#1F2937]",
+ quickReply: "border-[#E63946]/20 bg-white text-[#E63946] hover:bg-[#E63946] hover:text-white",
+ },
+ cards: {
+ menu: "border-[#F5E6D3] bg-white shadow-sm hover:border-[#D4A017]/55 hover:shadow-2xl hover:shadow-[#E63946]/10",
+ menuImage: "bg-[#F5E6D3]",
+ price: "bg-[#F5E6D3] text-[#E63946]",
+ reason: "border-[#F5E6D3] bg-[#FFF8F0]/90 hover:border-[#E63946]/35",
+ dark: "border-white/10 bg-white/[0.06] hover:border-[#D4A017]/50 hover:bg-white/[0.09]",
+ reviewShell: "border-[#F5E6D3] bg-white shadow-2xl shadow-[#D4A017]/10",
+ reviewDivider: "border-[#F5E6D3]",
+ chatIncoming: "bg-[#FFF8F0] text-[#1F2937] shadow-sm",
+ chatOutgoing: "bg-[#E63946] text-white shadow-lg shadow-[#E63946]/20",
+ contact: "bg-[#1F2937] text-white shadow-2xl shadow-[#1F2937]/18",
+ contactItem: "bg-white/8 hover:bg-white/14",
+ step: "bg-[#FFF8F0]",
+ chatbot: "border-[#F5E6D3] bg-[#FFF8F0] shadow-2xl shadow-[#1F2937]/25",
+ chatbotFooter: "border-[#F5E6D3] bg-white/70",
+ chatbotBot: "bg-white text-[#1F2937] shadow-sm",
+ logoDisc: "bg-white",
+ },
+ accents: {
+ redFill: "bg-[#E63946] text-white",
+ goldFill: "bg-[#D4A017] text-[#1F2937]",
+ creamFill: "bg-[#F5E6D3] text-[#E63946]",
+ goldIcon: "text-[#D4A017]",
+ redIcon: "text-[#E63946]",
+ dotActive: "bg-[#E63946]",
+ dotIdle: "bg-[#D4A017]/35",
+ dotCream: "bg-[#F5E6D3]",
+ onlinePill: "bg-emerald-50 text-emerald-700",
+ decorCream: "border-[#D4A017]/35 bg-[#FFF8F0]/10",
+ decorRed: "border-white/25 bg-[#E63946]/20",
+ decorWhite: "border-white/25 bg-white/10",
+ socialFooter: "border-white/15 text-white/70 hover:border-[#D4A017] hover:bg-[#D4A017] hover:text-[#1F2937]",
+ },
+ borders: {
+ whiteSubtle: "border-white/20",
+ whiteSoft: "border-white/15",
+ whiteMuted: "border-white/10",
+ darkSubtle: "border-[#1F2937]/10",
+ beige: "border-[#F5E6D3]",
+ redSoft: "border-[#E63946]/20",
+ },
+ hero: {
+ background: "bg-[#1F2937] text-white",
+ overlay: "bg-[linear-gradient(90deg,rgba(31,41,55,0.88)_0%,rgba(31,41,55,0.66)_42%,rgba(31,41,55,0.18)_100%)]",
+ eyebrow: "border-white/20 bg-white/12 text-[#F5E6D3]",
+ },
+ footer: "bg-[#1F2937] text-white",
+ input:
+ "border-[#F5E6D3] bg-white text-[#1F2937] placeholder:text-[#1F2937]/35 focus:border-[#E63946]",
+ surface: {
+ translucentWhite: "bg-white/15",
+ closeButton: "bg-white/10 hover:bg-white/20",
+ },
+ },
+ light: {
+ ...shared,
+ page: "bg-white text-slate-950",
+ heroBackdrop:
+ "bg-[radial-gradient(circle_at_top_right,rgba(124,58,237,0.16),transparent_34%),linear-gradient(180deg,#ffffff_0%,#f8fafc_100%)]",
+ nav: "border-slate-200/80 bg-white/85 text-slate-950 shadow-sm shadow-slate-200/70 backdrop-blur-xl",
+ navLinkHover: "hover:text-slate-950",
+ text: {
+ primary: "text-slate-950",
+ secondary: "text-slate-600",
+ muted: "text-slate-500",
+ accent: "text-violet-700",
+ positive: "text-emerald-600",
+ inverted: "text-white",
+ },
+ border: "border-slate-200",
+ divider: "border-slate-200",
+ card: "border-slate-200 bg-white shadow-sm shadow-slate-200/70",
+ cardHover: "hover:border-violet-200 hover:shadow-lg hover:shadow-violet-100/80",
+ panel: "border-slate-200 bg-slate-50",
+ elevatedPanel: "border-slate-200 bg-white shadow-2xl shadow-slate-200/80",
+ glassPanel: "border-white/70 bg-white/85 shadow-2xl shadow-slate-950/10 backdrop-blur-xl",
+ metricPanel: "border-slate-200 bg-white",
+ input:
+ "border-slate-300 bg-white text-slate-950 placeholder:text-slate-400 focus:border-violet-600 focus:ring-violet-600/20",
+ primaryButton:
+ "bg-violet-700 text-white shadow-lg shadow-violet-700/25 hover:bg-violet-800",
+ secondaryButton: "border-slate-300 bg-white text-slate-950 hover:bg-slate-100",
+ ghostButton: "text-slate-700 hover:bg-slate-100",
+ tabTrack: "border-slate-200 bg-slate-100",
+ activeTab: "bg-violet-700 text-white shadow-lg shadow-violet-700/20",
+ inactiveTab: "text-slate-500 hover:text-slate-950",
+ badge: "bg-violet-100 text-violet-700",
+ iconBox: "border-violet-100 bg-violet-50 text-violet-700",
+ heroOverlay: "bg-slate-950/55",
+ cta: "border-slate-200 bg-[linear-gradient(135deg,#ffffff_0%,#f5f3ff_58%,#ede9fe_100%)]",
+ },
+ dark: {
+ ...shared,
+ page: "bg-[#08080d] text-white",
+ heroBackdrop:
+ "bg-[radial-gradient(circle_at_72%_16%,rgba(124,58,237,0.28),transparent_30%),linear-gradient(180deg,#08080d_0%,#0b0b12_54%,#08080d_100%)]",
+ nav: "border-white/10 bg-[#08080d]/86 text-white shadow-lg shadow-black/20 backdrop-blur-xl",
+ navLinkHover: "hover:text-white",
+ text: {
+ primary: "text-white",
+ secondary: "text-zinc-300",
+ muted: "text-zinc-400",
+ accent: "text-violet-400",
+ positive: "text-emerald-400",
+ inverted: "text-[#08080d]",
+ },
+ border: "border-white/10",
+ divider: "border-white/10",
+ card: "border-white/10 bg-white/[0.045] shadow-none",
+ cardHover: "hover:border-violet-400/35 hover:bg-white/[0.07]",
+ panel: "border-white/10 bg-white/[0.04]",
+ elevatedPanel: "border-white/10 bg-white/[0.065] shadow-2xl shadow-black/35",
+ glassPanel: "border-white/10 bg-[#101018]/86 shadow-2xl shadow-black/45 backdrop-blur-xl",
+ metricPanel: "border-white/10 bg-[#111119]",
+ input:
+ "border-white/15 bg-[#12121a] text-white placeholder:text-zinc-500 focus:border-violet-400 focus:ring-violet-400/20",
+ primaryButton:
+ "bg-violet-600 text-white shadow-lg shadow-violet-700/25 hover:bg-violet-500",
+ secondaryButton: "border-white/15 bg-white/[0.04] text-white hover:bg-white/[0.08]",
+ ghostButton: "text-zinc-200 hover:bg-white/[0.08]",
+ tabTrack: "border-white/10 bg-white/[0.045]",
+ activeTab: "bg-violet-600 text-white shadow-lg shadow-violet-700/25",
+ inactiveTab: "text-zinc-400 hover:text-white",
+ badge: "bg-violet-500/12 text-violet-300",
+ iconBox: "border-violet-400/20 bg-violet-500/10 text-violet-300",
+ heroOverlay: "bg-black/64",
+ cta: "border-white/10 bg-[linear-gradient(135deg,#14141d_0%,#15111f_54%,#3b1265_100%)]",
+ },
+};
+
+export function getThemeComponents(theme) {
+ return themeComponents[theme] ?? themeComponents.dark;
+}
diff --git a/frontend/src/index.css b/frontend/src/index.css
new file mode 100644
index 00000000..3c0740ea
--- /dev/null
+++ b/frontend/src/index.css
@@ -0,0 +1,70 @@
+@import "tailwindcss";
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ margin: 0;
+ min-width: 320px;
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
+ "Segoe UI", sans-serif;
+ background: #fff8f0;
+ color: #1f2937;
+}
+
+a,
+button {
+ -webkit-tap-highlight-color: transparent;
+}
+
+@keyframes float {
+ 0%,
+ 100% {
+ transform: translateY(0) rotate(0deg);
+ }
+
+ 50% {
+ transform: translateY(-16px) rotate(3deg);
+ }
+}
+
+@keyframes hero-title-shimmer {
+ 0%,
+ 100% {
+ text-shadow: 0 0 0 rgba(245, 230, 211, 0);
+ }
+
+ 50% {
+ text-shadow: 0 10px 36px rgba(245, 230, 211, 0.34);
+ }
+}
+
+.hero-title-animated {
+ animation: hero-title-shimmer 3.8s ease-in-out infinite;
+}
+
+@keyframes sushi-drift {
+ 0%,
+ 100% {
+ filter: drop-shadow(0 22px 28px rgba(0, 0, 0, 0.24));
+ }
+
+ 35% {
+ filter: drop-shadow(-18px 34px 34px rgba(0, 0, 0, 0.3));
+ }
+
+ 70% {
+ filter: drop-shadow(14px 18px 30px rgba(0, 0, 0, 0.28));
+ }
+}
+
+.floating-sushi {
+ animation: sushi-drift 3.2s ease-in-out infinite;
+ transform-origin: center;
+ will-change: transform, filter;
+}
diff --git a/frontend/src/landing/Landing.jsx b/frontend/src/landing/Landing.jsx
new file mode 100644
index 00000000..ee89985b
--- /dev/null
+++ b/frontend/src/landing/Landing.jsx
@@ -0,0 +1,67 @@
+import { useEffect, useRef, useState } from "react";
+import { gsap } from "gsap";
+import { ScrollTrigger } from "gsap/ScrollTrigger";
+import BestSellersSection from "./components/BestSellersSection.jsx";
+import Chatbot from "./components/Chatbot.jsx";
+import DeliverySection from "./components/DeliverySection.jsx";
+import FeaturedProductsSection from "./components/FeaturedProductsSection.jsx";
+import FinalCtaSection from "./components/FinalCtaSection.jsx";
+import Footer from "./components/Footer.jsx";
+import HeroSection from "./components/HeroSection.jsx";
+import Navbar from "./components/Navbar.jsx";
+import ReviewsSection from "./components/ReviewsSection.jsx";
+import WhyChooseSection from "./components/WhyChooseSection.jsx";
+import { getThemeComponents } from "../components/ThemeComponents.jsx";
+
+gsap.registerPlugin(ScrollTrigger);
+
+function Landing() {
+ const rootRef = useRef(null);
+ const [menuOpen, setMenuOpen] = useState(false);
+ const [chatOpen, setChatOpen] = useState(false);
+ const ui = getThemeComponents("dailySushi");
+
+ useEffect(() => {
+ const ctx = gsap.context(() => {
+ gsap.utils.toArray("[data-reveal]").forEach((item) => {
+ gsap.from(item, {
+ y: 38,
+ opacity: 0,
+ duration: 0.85,
+ ease: "power3.out",
+ scrollTrigger: {
+ trigger: item,
+ start: "top 84%",
+ },
+ });
+ });
+ }, rootRef);
+
+ return () => ctx.revert();
+ }, []);
+
+ return (
+
+ setMenuOpen(false)}
+ onMenuToggle={() => setMenuOpen((value) => !value)}
+ />
+
+
+
+
+
+ setChatOpen(true)} />
+
+
+ setChatOpen(false)}
+ onOpen={() => setChatOpen(true)}
+ />
+
+ );
+}
+
+export default Landing;
diff --git a/frontend/src/landing/components/BestSellersSection.jsx b/frontend/src/landing/components/BestSellersSection.jsx
new file mode 100644
index 00000000..5f227724
--- /dev/null
+++ b/frontend/src/landing/components/BestSellersSection.jsx
@@ -0,0 +1,69 @@
+import { Star } from "lucide-react";
+import bakedSushiImg from "../../assets/product-1.jpg";
+import jellyImg from "../../assets/product-2.jpg";
+import makiImg from "../../assets/product-3.jpg";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const bestSellers = [
+ {
+ name: "Signature Baked Sushi Tray",
+ description: "The rich, creamy crowd favorite for parties, merienda, and weekend cravings.",
+ rating: "4.9",
+ orders: "1.8k orders",
+ image: bakedSushiImg,
+ },
+ {
+ name: "California Maki Party Box",
+ description: "Fresh rolls with mango and kani, made for sharing and easy gifting.",
+ rating: "4.8",
+ orders: "1.2k orders",
+ image: makiImg,
+ },
+ {
+ name: "Mango Jelly Cups",
+ description: "A cool, creamy dessert that turns every sushi order into a full treat.",
+ rating: "4.9",
+ orders: "980 orders",
+ image: jellyImg,
+ },
+];
+
+function BestSellersSection() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+
+
+
+
Best Sellers
+
The orders customers come back for
+
+
+
+
+ {bestSellers.map((item) => (
+
+
+
+
+
+
+ {Array.from({ length: 5 }).map((_, index) => (
+
+ ))}
+ {item.rating}
+
+
{item.name}
+
{item.description}
+
{item.orders}
+
+
+ ))}
+
+
+
+ );
+}
+
+export default BestSellersSection;
diff --git a/frontend/src/landing/components/Chatbot.jsx b/frontend/src/landing/components/Chatbot.jsx
new file mode 100644
index 00000000..71a6e62b
--- /dev/null
+++ b/frontend/src/landing/components/Chatbot.jsx
@@ -0,0 +1,144 @@
+import { useEffect, useRef, useState } from "react";
+import { MessageCircle, Send, X } from "lucide-react";
+import Logo from "../../assets/Logo.png";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const quickReplies = [
+ "Menu and prices",
+ "How to order",
+ "Delivery areas",
+ "Store hours",
+];
+
+function getBotReply(message) {
+ const text = message.toLowerCase();
+
+ if (text.includes("menu") || text.includes("price")) {
+ return "Our favorites are Baked Sushi, California Maki, Salmon Maki, Crabstick California Roll, Mango Jelly, and Lychee Jelly. Send your preferred items and quantity so we can prepare your order.";
+ }
+
+ if (text.includes("deliver") || text.includes("area") || text.includes("location")) {
+ return "We serve Baras, Tanay, and Pililia, Rizal. Share your exact location so we can confirm delivery availability.";
+ }
+
+ if (text.includes("hour") || text.includes("open") || text.includes("time")) {
+ return "We are open Monday to Friday, 3:00 PM - 11:00 PM.";
+ }
+
+ if (text.includes("order") || text.includes("how")) {
+ return "To order, send your name, chosen items, quantity, delivery location, and preferred delivery time. You can also call or text 09667889034.";
+ }
+
+ return "Thanks for messaging Daily Sushi. Please send your order details, location, and preferred delivery time. We will confirm availability shortly.";
+}
+
+function Chatbot({ isOpen, onClose, onOpen }) {
+ const ui = getThemeComponents("dailySushi");
+ const [messages, setMessages] = useState([
+ {
+ author: "bot",
+ text: "Hi! Welcome to Daily Sushi. What would you like to order today?",
+ },
+ ]);
+ const [draft, setDraft] = useState("");
+ const messagesEndRef = useRef(null);
+
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ }, [messages, isOpen]);
+
+ function sendMessage(text) {
+ const trimmed = text.trim();
+
+ if (!trimmed) {
+ return;
+ }
+
+ setMessages((current) => [
+ ...current,
+ { author: "user", text: trimmed },
+ { author: "bot", text: getBotReply(trimmed) },
+ ]);
+ setDraft("");
+ }
+
+ function handleSubmit(event) {
+ event.preventDefault();
+ sendMessage(draft);
+ }
+
+ if (!isOpen) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
Daily Sushi
+
Auto-replies instantly
+
+
+
+
+
+
+
+
+ {messages.map((message, index) => {
+ const isBot = message.author === "bot";
+
+ return (
+
+ );
+ })}
+
+
+
+
+
+ {quickReplies.map((reply) => (
+ sendMessage(reply)}
+ type="button"
+ >
+ {reply}
+
+ ))}
+
+
+
+
+ );
+}
+
+export default Chatbot;
diff --git a/frontend/src/landing/components/DeliverySection.jsx b/frontend/src/landing/components/DeliverySection.jsx
new file mode 100644
index 00000000..70bc3ef4
--- /dev/null
+++ b/frontend/src/landing/components/DeliverySection.jsx
@@ -0,0 +1,59 @@
+import { Clock, MapPin, MessageCircle, Phone } from "lucide-react";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const orderingSteps = [
+ "Choose your favorite sushi trays, rolls, and desserts.",
+ "Send your order through chat, call, or social media.",
+ "Receive it freshly packed at your doorstep.",
+];
+
+function DeliverySection({ onChatOpen }) {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+ );
+}
+
+export default DeliverySection;
diff --git a/frontend/src/landing/components/FeaturedProductsSection.jsx b/frontend/src/landing/components/FeaturedProductsSection.jsx
new file mode 100644
index 00000000..69b88b73
--- /dev/null
+++ b/frontend/src/landing/components/FeaturedProductsSection.jsx
@@ -0,0 +1,71 @@
+import { ChevronRight } from "lucide-react";
+import product1 from "../../assets/product-1.jpg";
+import product2 from "../../assets/product-2.jpg";
+import product3 from "../../assets/product-3.jpg";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const products = [
+ {
+ name: "Baked Sushi",
+ description: "Creamy, savory baked sushi tray layered with rice, seafood, kani, and toasted toppings.",
+ price: "PHP 110",
+ image: product1,
+ },
+ {
+ name: "California Maki",
+ description: "Classic maki rolls with kani, cucumber, mango, and a clean sesame finish.",
+ price: "PHP 180",
+ image: product3,
+ },
+ {
+ name: "Mango Jelly",
+ description: "Refreshing mango jelly dessert with silky cream and juicy fruit notes.",
+ price: "PHP 95",
+ image: product2,
+ },
+];
+
+function FeaturedProductsSection() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+ );
+}
+
+export default FeaturedProductsSection;
diff --git a/frontend/src/landing/components/FinalCtaSection.jsx b/frontend/src/landing/components/FinalCtaSection.jsx
new file mode 100644
index 00000000..dec55d18
--- /dev/null
+++ b/frontend/src/landing/components/FinalCtaSection.jsx
@@ -0,0 +1,26 @@
+import { CheckCircle2, ShoppingBag } from "lucide-react";
+import japaneseBgImg from "../../assets/japanese-bg.jpg";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+function FinalCtaSection() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+ );
+}
+
+export default FinalCtaSection;
diff --git a/frontend/src/landing/components/Footer.jsx b/frontend/src/landing/components/Footer.jsx
new file mode 100644
index 00000000..dd44813f
--- /dev/null
+++ b/frontend/src/landing/components/Footer.jsx
@@ -0,0 +1,93 @@
+import { Clock, MapPin, Phone } from "lucide-react";
+import Logo from "../../assets/Logo.png";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const navLinks = [
+ { label: "Home", href: "#home" },
+ { label: "Menu", href: "#menu" },
+ { label: "Reviews", href: "#reviews" },
+ { label: "Contacts", href: "#contacts" },
+];
+
+function FacebookIcon() {
+ return (
+
+
+
+ );
+}
+
+function InstagramIcon() {
+ return (
+
+
+
+
+
+ );
+}
+
+function Footer() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+ );
+}
+
+export default Footer;
diff --git a/frontend/src/landing/components/HeroSection.jsx b/frontend/src/landing/components/HeroSection.jsx
new file mode 100644
index 00000000..6f3e35c6
--- /dev/null
+++ b/frontend/src/landing/components/HeroSection.jsx
@@ -0,0 +1,154 @@
+import { useEffect, useRef } from "react";
+import { ShoppingBag, Sparkles } from "lucide-react";
+import { gsap } from "gsap";
+import { ScrollTrigger } from "gsap/ScrollTrigger";
+import heroImg from "../../assets/hero-section.jpg";
+import logoImg from "../../assets/Logo.png";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+gsap.registerPlugin(ScrollTrigger);
+
+function HeroSection() {
+ const heroRef = useRef(null);
+ const ui = getThemeComponents("dailySushi");
+
+ useEffect(() => {
+ const ctx = gsap.context(() => {
+ const timeline = gsap.timeline({ defaults: { ease: "power3.out" } });
+
+ timeline
+ .from("[data-hero-media]", {
+ scale: 1.14,
+ opacity: 0.72,
+ duration: 1.45,
+ })
+ .from("[data-hero-copy]", {
+ y: 44,
+ opacity: 0,
+ duration: 0.9,
+ stagger: 0.13,
+ }, "-=0.85")
+ .from("[data-hero-badge]", {
+ y: -18,
+ opacity: 0,
+ scale: 0.82,
+ duration: 0.7,
+ ease: "back.out(1.8)",
+ }, "-=0.35");
+
+ timeline.from("[data-floating-sushi]", {
+ x: 120,
+ y: 28,
+ opacity: 0,
+ rotate: 18,
+ scale: 0.78,
+ duration: 1,
+ ease: "back.out(1.6)",
+ }, "-=0.55");
+
+ gsap.to("[data-hero-media]", {
+ yPercent: 12,
+ scale: 1.08,
+ ease: "none",
+ scrollTrigger: {
+ trigger: heroRef.current,
+ start: "top top",
+ end: "bottom top",
+ scrub: true,
+ },
+ });
+
+ gsap.to("[data-hero-deco]", {
+ y: "random(-18, 18)",
+ x: "random(-8, 8)",
+ rotate: "random(-8, 8)",
+ duration: "random(3.2, 5.4)",
+ ease: "sine.inOut",
+ repeat: -1,
+ yoyo: true,
+ stagger: 0.18,
+ });
+
+ gsap.to("[data-hero-badge]", {
+ y: -8,
+ duration: 1.6,
+ ease: "sine.inOut",
+ repeat: -1,
+ yoyo: true,
+ });
+
+ gsap.to("[data-floating-sushi]", {
+ y: -24,
+ x: -10,
+ rotate: -5,
+ duration: 2.8,
+ ease: "sine.inOut",
+ repeat: -1,
+ yoyo: true,
+ });
+
+ gsap.to("[data-floating-sushi-ring]", {
+ rotate: 360,
+ duration: 13,
+ ease: "none",
+ repeat: -1,
+ });
+
+ gsap.to("[data-hero-cta]", {
+ y: -5,
+ duration: 1.8,
+ ease: "sine.inOut",
+ repeat: -1,
+ yoyo: true,
+ });
+ }, heroRef);
+
+ return () => ctx.revert();
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Wrap Up Your Day with Sushi.
+
+
+ Freshly Made Sushi, Crafted Daily
+
+
+ Enjoy delicious baked sushi, flavorful maki rolls, classic California rolls, and sweet jelly treats delivered fresh to your doorstep.
+
+
+
+
+
+ );
+}
+
+export default HeroSection;
diff --git a/frontend/src/landing/components/Navbar.jsx b/frontend/src/landing/components/Navbar.jsx
new file mode 100644
index 00000000..7a79517a
--- /dev/null
+++ b/frontend/src/landing/components/Navbar.jsx
@@ -0,0 +1,63 @@
+import { Menu, X } from "lucide-react";
+import Logo from "../../assets/Logo.png";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const navLinks = [
+ { label: "Home", href: "#home" },
+ { label: "Menu", href: "#menu" },
+ { label: "Reviews", href: "#reviews" },
+ { label: "Contacts", href: "#contacts" },
+];
+
+function Navbar({ menuOpen, onMenuToggle, onMenuClose }) {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+
+
+ {menuOpen ? (
+
+ ) : null}
+
+ );
+}
+
+export default Navbar;
diff --git a/frontend/src/landing/components/ReviewsSection.jsx b/frontend/src/landing/components/ReviewsSection.jsx
new file mode 100644
index 00000000..44b44949
--- /dev/null
+++ b/frontend/src/landing/components/ReviewsSection.jsx
@@ -0,0 +1,79 @@
+import { Star } from "lucide-react";
+import review1 from "../../assets/review-1.jpg";
+import review2 from "../../assets/review-2.jpg";
+import review3 from "../../assets/review-3.jpg";
+import review4 from "../../assets/review-4.jpg";
+import review5 from "../../assets/review-5.jpg";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const reviews = [
+ {
+ name: "Customer 1",
+ detail: "Ordered for family dinner",
+ image: review1,
+ },
+ {
+ name: "Customer 2",
+ detail: "Repeat customer",
+ image: review2,
+ },
+ {
+ name: "Customer 3",
+ detail: "Team snack order",
+ image: review3,
+ },
+ {
+ name: "Customer 4",
+ detail: "Birthday spread",
+ image: review4,
+ },
+ {
+ name: "Customer 5",
+ detail: "Weekend order",
+ image: review5,
+ },
+];
+
+function ReviewsSection() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+
+
+
Customer Reviews
+
Real messages from happy customers
+
+ We deliver happiness to your doorstep, and our customers can't help but share their joy. Read what they have to say about their experience with Daily Sushi.
+
+
+
+
+ {reviews.map((review) => (
+
+
+
+
+
+
+ {Array.from({ length: 5 }).map((_, starIndex) => (
+
+ ))}
+ 5.0
+
+
+
+
{review.name}
+
{review.detail}
+
+
+
+
+ ))}
+
+
+
+ );
+}
+
+export default ReviewsSection;
diff --git a/frontend/src/landing/components/WhyChooseSection.jsx b/frontend/src/landing/components/WhyChooseSection.jsx
new file mode 100644
index 00000000..6de338ea
--- /dev/null
+++ b/frontend/src/landing/components/WhyChooseSection.jsx
@@ -0,0 +1,43 @@
+import { HeartHandshake, ShieldCheck, Sparkles, Truck, Wallet } from "lucide-react";
+import japaneseBgImg from "../../assets/japanese-bg.jpg";
+import { getThemeComponents } from "../../components/ThemeComponents.jsx";
+
+const reasons = [
+ { title: "Fresh Ingredients Daily", text: "Rice, seafood, fruit, and toppings are prepared in small batches.", icon: Sparkles },
+ { title: "Handmade with Care", text: "Every tray and roll is assembled by hand for consistent flavor.", icon: HeartHandshake },
+ { title: "Fast Delivery", text: "Packed neatly and sent out quickly while flavors stay fresh.", icon: Truck },
+ { title: "Affordable Prices", text: "Premium comfort food with bundles that work for cravings and gatherings.", icon: Wallet },
+ { title: "Premium Quality", text: "Clean presentation, balanced flavors, and reliable daily preparation.", icon: ShieldCheck },
+];
+
+function WhyChooseSection() {
+ const ui = getThemeComponents("dailySushi");
+
+ return (
+
+
+
+
+
Why Choose Daily Sushi
+
Small-batch quality, polished for everyday delivery
+
+
+ {reasons.map((reason) => {
+ const Icon = reason.icon;
+ return (
+
+
+
+
+ {reason.title}
+ {reason.text}
+
+ );
+ })}
+
+
+
+ );
+}
+
+export default WhyChooseSection;
diff --git a/frontend/src/login/Login.jsx b/frontend/src/login/Login.jsx
new file mode 100644
index 00000000..e2c4f551
--- /dev/null
+++ b/frontend/src/login/Login.jsx
@@ -0,0 +1,84 @@
+import { getThemeComponents } from "../components/ThemeComponents.jsx";
+
+function Login({ onBackHome }) {
+ const ui = getThemeComponents("light");
+
+ return (
+
+
+
+ );
+}
+
+export default Login;
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
new file mode 100644
index 00000000..b9a1a6de
--- /dev/null
+++ b/frontend/src/main.jsx
@@ -0,0 +1,10 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import './index.css'
+import App from './App.jsx'
+
+createRoot(document.getElementById('root')).render(
+
+
+ ,
+)
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 00000000..3ae59ba6
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,14 @@
+import { defineConfig } from "vite"
+import react from "@vitejs/plugin-react"
+import tailwindcss from "@tailwindcss/vite"
+
+export default defineConfig({
+ plugins: [
+ react(),
+ tailwindcss(),
+ ],
+ server: {
+ host: "0.0.0.0",
+ port: 5173,
+ },
+})