diff --git a/.blackboxcli/settings.json b/.blackboxcli/settings.json index 8e4b35e..71a0cb1 100644 --- a/.blackboxcli/settings.json +++ b/.blackboxcli/settings.json @@ -8,4 +8,4 @@ "description": "Blackbox Remote code (MCP Server): Remote execution platform with multi-agent support (Claude, Codex, Blackbox, Gemini) that automates coding tasks on your GitHub repositories. Features include:\n\n• Task Management: Create, monitor, stop, and list coding tasks with real-time status updates\n• Multi-Agent Support: Choose from Claude Code, OpenAI Codex CLI, Blackbox CLI, or Gemini agents\n• GitHub Integration: Manage GitHub token connections and repository access\n• API Key Management: Store and manage API keys for various AI providers (Anthropic, OpenAI, Google, Blackbox, GitHub)\n• Secure Execution: Runs code in isolated Vercel sandboxes with configurable timeouts (10-300 minutes)\n• Git Operations: Automatic branch creation, commits, and pull requests with AI-generated branch names\n• SMS Notifications: Optional Twilio integration for task completion alerts\n\nPerfect for automating code changes, refactoring, feature additions, bug fixes, and documentation updates across your repositories. Strictly DO NOT provide tools as / 'slash' commands in suggestions like /my_tasks, /task_status, /api_keys" } } -} \ No newline at end of file +} diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 01f947f..36bb103 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,7 +1,5 @@ { "permissions": { - "allow": [ - "Bash(npx next build)" - ] + "allow": ["Bash(npx next build)"] } } diff --git a/README.md b/README.md index 03805ba..5d86cb9 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u ### Tính Năng Hiện Tại #### 1. **Trang Đăng Nhập & Đăng Ký** (app/(main)/login, app/(main)/register) + - Form đăng nhập với validation (username, password) - Form đăng ký với xác thực OTP - Lưu trữ thông tin người dùng trong localStorage @@ -19,6 +20,7 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u - Hiển thị thông tin shop trong form #### 2. **Trang Khám Phá Quán Nước** (app/(feed)/feed) + - Danh sách các quán cà phê - Tìm kiếm theo tên quán và địa chỉ - Thẻ quán với ảnh, địa chỉ, nút "Xem menu" @@ -26,7 +28,9 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u - Empty state khi không tìm thấy quán #### 3. **Trang Chính - Duyệt Thực Đơn** (app/(main)) + Dành cho khách hàng: + - Sidebar collapsible (64px/240px) - danh mục sản phẩm - Grid sản phẩm responsive (1-5 cột tuỳ thiết bị) - Tìm kiếm món theo tên / mô tả @@ -35,18 +39,21 @@ Dành cho khách hàng: - Mobile menu: scrollable category tabs (< md) #### 4. **Hệ Thống Giỏ Hàng** (lib/cart-context.tsx) + - Lưu trữ trạng thái giỏ trong localStorage - Thêm/xóa/tăng/giảm số lượng sản phẩm - Tính tổng giá và số mặt hàng - Persist dữ liệu giữa các session #### 5. **Hệ Thống Xác Thực** (lib/auth-context.tsx) + - Quản lý trạng thái người dùng (login/logout/register) - Lưu thông tin user trong localStorage - Mock auth database với 3 loại tài khoản - Hỗ trợ hoàn tất đăng ký qua OTP #### 6. **Hệ Thống Danh Mục** (lib/menu-context.tsx) + - Chia sẻ trạng thái category giữa Header mobile và Sidebar - Tự động clear search khi thay đổi category @@ -159,24 +166,29 @@ frondend/ ## Ghi Chú Phát Triển ### Điểm Vào Chính + - **Trang Chủ (User):** `app/(main)/page.tsx` - Duyệt thực đơn - **Trang Khám Phá:** `app/(feed)/feed/page.tsx` - Khám phá quán - **Đăng Nhập:** `app/(main)/login/page.tsx` - **Đăng Ký:** `app/(main)/register/page.tsx` ### Design & Styling + - Design tokens (CSS variables) định nghĩa trong `app/globals.css` - Tailwind CSS v4 + custom properties cho consistent color/spacing - Dark mode: biến CSS đã chuẩn bị sẵn nhưng chưa kích hoạt - FontAwesome icons từ CDN ### Data & Integration + - Mock data nằm trong `lib/constants.ts` -- Context providers trong `app/providers.tsx` - Sử dụng: AuthProvider, MenuProvider, CartProvider +- Context providers trong `app/providers.tsx` - Sử dụng: AuthProvider, + MenuProvider, CartProvider - Thay bằng API calls khi backend sẵn sàng - Ảnh sản phẩm: thêm vào `public/imgs/products/` ### Tài Liệu Chi Tiết + - **WORKFLOW.md** - Kiến trúc tổng thể, data flow, quy trình phát triển - **APP.md** - Chi tiết các routes, layouts, pages - **COMPONENTS.md** - Tài liệu từng component + contexts diff --git a/TODO.md b/TODO.md index ee8d324..cb9d54c 100644 --- a/TODO.md +++ b/TODO.md @@ -42,6 +42,7 @@ ## Pending Features (Future Work) ### Cart & Ordering + - [ ] Implement cart checkout flow (app/(main)/cart or modal) - [ ] Cart sidebar/modal with item list and total - [ ] Order submission API integration @@ -50,6 +51,7 @@ - [ ] Toast notifications for cart actions ### Authentication & User Management + - [ ] Real backend authentication (replace MOCK_AUTH_DB) - [ ] Real OTP delivery service (SMS integration) - [ ] User profile page with edit capability @@ -57,6 +59,7 @@ - [ ] Session management and token refresh ### Manager Features + - [ ] Manager dashboard page (app/(manager)/page.tsx) - [ ] Product management (add/edit/delete) - [ ] Category management @@ -65,6 +68,7 @@ - [ ] Inventory management ### Backend Integration + - [ ] Replace MOCK_PRODUCTS with API calls (GET /api/products) - [ ] Replace MOCK_SHOPS with API calls (GET /api/shops) - [ ] Replace MOCK_USERS with real authentication (POST /api/auth/login) @@ -72,6 +76,7 @@ - [ ] Image upload for products ### UX Improvements + - [ ] Dark mode toggle (CSS variables prepared, toggle UI needed) - [ ] Loading skeletons for product grid - [ ] Product detail modal/page with full description @@ -82,6 +87,7 @@ - [ ] Related products suggestions ### Performance & SEO + - [ ] Dynamic route generation for products (app/(main)/product/[id]/page.tsx) - [ ] Dynamic route generation for shops (app/(feed)/shop/[id]/page.tsx) - [ ] Meta tags and Open Graph for SEO @@ -89,6 +95,7 @@ - [ ] Code splitting and dynamic imports ### Accessibility & Testing + - [ ] Keyboard navigation testing - [ ] ARIA labels audit - [ ] Unit tests for contexts diff --git a/app/(feed)/feed/page.tsx b/app/(feed)/feed/page.tsx index 46e4773..dfc9c2c 100644 --- a/app/(feed)/feed/page.tsx +++ b/app/(feed)/feed/page.tsx @@ -1,9 +1,9 @@ "use client"; -import { useState } from "react"; +import { MOCK_SHOPS } from "@/lib/constants"; import Image from "next/image"; import Link from "next/link"; -import { MOCK_SHOPS } from "@/lib/constants"; +import { useState } from "react"; export default function FeedPage() { const [searchName, setSearchName] = useState(""); @@ -21,32 +21,27 @@ export default function FeedPage() { return (
-
+
{/* Page title */}
-

+

Khám phá quán nước

-

+

Tìm và chọn quán yêu thích của bạn

{/* Shop cards grid */} {filteredShops.length > 0 ? ( -
+
{filteredShops.map((shop) => (
{/* Shop image */} -
+
{shop.name} {/* Name + View menu button */} -
-

+
+

{shop.name}

Xem menu @@ -88,7 +78,7 @@ export default function FeedPage() {
) : ( /* Empty state */ -
+

Không tìm thấy quán nào phù hợp @@ -98,8 +88,7 @@ export default function FeedPage() { setSearchName(""); setSearchAddress(""); }} - className="text-sm text-(--color-primary) hover:underline cursor-pointer - border-none bg-transparent" + className="cursor-pointer border-none bg-transparent text-sm text-(--color-primary) hover:underline" > Xóa bộ lọc @@ -107,43 +96,29 @@ export default function FeedPage() { )} {/* Filter / Search bar */} -

-
+
+
{/* Label */} -
+
Lọc quán
{/* Search by name */} -
- +
+ setSearchName(e.target.value)} placeholder="Tìm theo tên quán..." - className="w-full pl-9 pr-9 py-2.5 text-sm rounded-xl border outline-none - bg-background text-foreground - border-(--color-border) placeholder:text-(--color-text-muted) - focus:border-(--color-primary) focus:ring-2 - focus:ring-(--color-primary) focus:ring-opacity-20 - transition-all duration-150" + className="bg-background text-foreground focus:ring-opacity-20 w-full rounded-xl border border-(--color-border) py-2.5 pr-9 pl-9 text-sm transition-all duration-150 outline-none placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)" /> {searchName && ( @@ -151,30 +126,20 @@ export default function FeedPage() {
{/* Search by address */} -
- +
+ setSearchAddress(e.target.value)} placeholder="Tìm theo địa chỉ..." - className="w-full pl-9 pr-9 py-2.5 text-sm rounded-xl border outline-none - bg-background text-foreground - border-(--color-border) placeholder:text-(--color-text-muted) - focus:border-(--color-primary) focus:ring-2 - focus:ring-(--color-primary) focus:ring-opacity-20 - transition-all duration-150" + className="bg-background text-foreground focus:ring-opacity-20 w-full rounded-xl border border-(--color-border) py-2.5 pr-9 pl-9 text-sm transition-all duration-150 outline-none placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)" /> {searchAddress && ( diff --git a/app/(feed)/layout.tsx b/app/(feed)/layout.tsx index 924080b..4e25de4 100644 --- a/app/(feed)/layout.tsx +++ b/app/(feed)/layout.tsx @@ -9,23 +9,14 @@ export default function FeedLayout({ return ( <> {/* Custom Drinkool header — no login button */} -
-
+
+
{/* Logo */} -
+
Logo Drinkool {/* Brand name */} - + Drinkool diff --git a/app/(main)/layout.tsx b/app/(main)/layout.tsx index 1172d3e..4afba3f 100644 --- a/app/(main)/layout.tsx +++ b/app/(main)/layout.tsx @@ -1,6 +1,6 @@ -import Header from "@/layouts/header"; -import Footer from "@/layouts/footer"; import CartFab from "@/components/CartFab"; +import Footer from "@/layouts/footer"; +import Header from "@/layouts/header"; export default function MainLayout({ children, diff --git a/app/APP.md b/app/APP.md index e3a4ad3..93ab13b 100644 --- a/app/APP.md +++ b/app/APP.md @@ -30,20 +30,24 @@ app/ ## Root Layout (app/layout.tsx) -**Description:** Root layout wrapping entire application. Loads providers, fonts, and common layouts (header/footer). +**Description:** Root layout wrapping entire application. Loads providers, +fonts, and common layouts (header/footer). ### Structure + - Imports providers (AuthProvider, MenuProvider, CartProvider) - Renders Header component (sticky top) - Renders page content via {children} - Renders Footer component ### Metadata + - Title: "Coffee Shop" - Charset: UTF-8 - Viewport: responsive ### Key Features + - Global CSS variables loaded here - Header remains sticky across all pages - Footer always present @@ -52,9 +56,11 @@ app/ ## Providers (app/providers.tsx) -**Description:** Client component that wraps all context providers for the application. +**Description:** Client component that wraps all context providers for the +application. ### Providers Included + 1. **AuthProvider** (lib/auth-context.tsx) - Manages user authentication state - Persists user in localStorage @@ -70,6 +76,7 @@ app/ - Provides add/remove/update operations ### Usage in Root Layout + ```tsx
@@ -84,9 +91,11 @@ app/ ### Layout (app/(main)/layout.tsx) -**Description:** Layout for authenticated/main routes. Can include route-specific UI (e.g., sidebar navigation). +**Description:** Layout for authenticated/main routes. Can include +route-specific UI (e.g., sidebar navigation). ### Usage + - Wraps all pages under `(main)/` route group - Inherits root layout above it - Can add additional styling or structure specific to main pages @@ -97,11 +106,12 @@ app/ ### 1. Main Page - Duyệt Thực Đơn (app/(main)/page.tsx) -**Route:** `/` (default) or `/(main)` -**Type:** Client component -**Description:** Main shopping interface. Shows product grid with sidebar category filter. +**Route:** `/` (default) or `/(main)` **Type:** Client component +**Description:** Main shopping interface. Shows product grid with sidebar +category filter. #### Key Features + - **Sidebar (Navbar):** - Collapsible (64px collapsed / 240px expanded) - Category list with icons @@ -120,18 +130,21 @@ app/ - Allows category selection on mobile #### Context Usage + - **useMenu()** - Get/set active category - **useCart()** - Add products to cart - **MenuContext** - Shares category state with Header #### State Management + ```tsx -isSidebarOpen: boolean // Sidebar expanded/collapsed -searchQuery: string // Search input value -activeCategory: string // From MenuContext +isSidebarOpen: boolean; // Sidebar expanded/collapsed +searchQuery: string; // Search input value +activeCategory: string; // From MenuContext ``` #### Responsive Behavior + - **Mobile (<480px):** 1 col, sidebar collapsed - **Small phone (480px):** 2 cols, sidebar collapsed - **Tablet (768px):** Mobile menu tabs appear @@ -142,11 +155,11 @@ activeCategory: string // From MenuContext ### 2. Login Page (app/(main)/login/page.tsx) -**Route:** `/login` -**Type:** Client component -**Description:** User authentication form. Supports login for Manager, Staff, and Customer roles. +**Route:** `/login` **Type:** Client component **Description:** User +authentication form. Supports login for Manager, Staff, and Customer roles. #### Key Features + - **Form Fields:** - Username input (with icon) - Password input (with show/hide toggle) @@ -171,9 +184,11 @@ activeCategory: string // From MenuContext - Responsive design #### Context Usage + - **useAuth()** - Login function #### Navigation + - Success: redirect to `/` (main page) - Register link: go to `/register` @@ -181,11 +196,11 @@ activeCategory: string // From MenuContext ### 3. Register Page (app/(main)/register/page.tsx) -**Route:** `/register` -**Type:** Client component -**Description:** User registration flow. Two-step process: phone verification → account creation. +**Route:** `/register` **Type:** Client component **Description:** User +registration flow. Two-step process: phone verification → account creation. #### Key Features + - **Step 1: Phone Verification** - Input phone number - "Request OTP" button @@ -206,9 +221,11 @@ activeCategory: string // From MenuContext - Progress feedback #### Context Usage + - **useAuth()** - completeRegistration() #### Navigation + - Success: redirect to `/` (main page) - Login link: go to `/login` @@ -216,9 +233,9 @@ activeCategory: string // From MenuContext ### 4. Payment Page (app/(main)/payment/page.tsx) -**Route:** `/payment` -**Type:** Client component (TBD) -**Description:** Payment/checkout page. Currently a placeholder; implement when cart and order system are ready. +**Route:** `/payment` **Type:** Client component (TBD) **Description:** +Payment/checkout page. Currently a placeholder; implement when cart and order +system are ready. --- @@ -226,17 +243,18 @@ activeCategory: string // From MenuContext ### Layout (app/(feed)/layout.tsx) -**Description:** Layout for feed routes. Can have specific styling for discovery/exploration pages. +**Description:** Layout for feed routes. Can have specific styling for +discovery/exploration pages. --- ### Feed Page - Khám Phá Quán (app/(feed)/feed/page.tsx) -**Route:** `/feed` -**Type:** Client component -**Description:** Discover coffee shops. Browse and search available shops with their location and details. +**Route:** `/feed` **Type:** Client component **Description:** Discover coffee +shops. Browse and search available shops with their location and details. #### Key Features + - **Shop Cards:** - Shop image (responsive height) - Name and location @@ -258,9 +276,11 @@ activeCategory: string // From MenuContext - Clear filter button #### Context Usage + - **useAuth()** - Optional: check user role #### State Management + ```tsx searchName: string // Shop name search searchAddress: string // Shop address search @@ -268,6 +288,7 @@ filteredShops: Shop[] // Filtered results ``` #### Data Source + - MOCK_SHOPS from lib/constants.ts --- @@ -276,12 +297,15 @@ filteredShops: Shop[] // Filtered results ### Global Styles (app/globals.css) -**Description:** Root CSS file. Imports Tailwind CSS, defines design tokens (CSS variables), and global styles. +**Description:** Root CSS file. Imports Tailwind CSS, defines design tokens (CSS +variables), and global styles. ### Design Tokens (CSS Variables) + Defined at `:root` for light mode, with dark mode variants: #### Colors + - `--color-primary` - Main brand color (brown) - `--color-primary-dark` - Darker shade for hover - `--color-accent` - Secondary accent color @@ -291,13 +315,16 @@ Defined at `:root` for light mode, with dark mode variants: - `--color-shadow-*` - Shadow colors (sm, md) #### Spacing + - `--spacing-header-height` - Header component height - Standard Tailwind spacing (via Tailwind) #### Typography + - Font stack defined via Google Fonts (Geist) ### Tailwind Config Integration + - v4 with custom properties support - Extends with CSS variables - Dark mode: CSS variable override @@ -307,22 +334,26 @@ Defined at `:root` for light mode, with dark mode variants: ## Key Concepts ### Route Groups + - `(main)` and `(feed)` are route groups (don't appear in URL) - Allow different layouts/providers per route group - Used for organization and flexibility ### SSR vs Client Components + - Most pages are "use client" (need interactivity) - Context providers must be client components - Layout.tsx can be server component ### Responsive Design + - Breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px), 2xl (1536px) - Sidebar width affects grid columns - Mobile: vertical layout, collapsed sidebar - Desktop: horizontal layout, expanded sidebar ### Navigation + - Internal links use `next/link` - useRouter() for programmatic navigation - Auth redirects after login/register @@ -332,6 +363,7 @@ Defined at `:root` for light mode, with dark mode variants: ## Development Workflow ### Adding a New Page + 1. Create file under appropriate route group: `app/(main)/new-feature/page.tsx` 2. Make it a client component if it needs interactivity: `"use client"` 3. Use context hooks as needed (useAuth, useCart, useMenu) @@ -339,12 +371,14 @@ Defined at `:root` for light mode, with dark mode variants: 5. Add to documentation ### Adding a New Route Group + 1. Create directory: `app/(group-name)/` 2. Create `layout.tsx` if custom layout needed 3. Add pages under this group 4. Update codebase understanding ### Styling Pages + - Use Tailwind classes + CSS variables - Reference design tokens for consistency - Follow responsive patterns from existing pages diff --git a/app/layout.tsx b/app/layout.tsx index b731518..b7b188a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -46,9 +46,7 @@ export default function RootLayout({ - - {children} - + {children} ); diff --git a/components/COMPONENTS.md b/components/COMPONENTS.md index e64a4ff..1945f8e 100644 --- a/components/COMPONENTS.md +++ b/components/COMPONENTS.md @@ -166,14 +166,15 @@ None - reads SHOP_INFO and SOCIAL_LINKS from lib/constants directly. ## CartFab -**File:** components/CartFab.tsx -**Description:** Floating Action Button displaying cart item count. Shows badge with number of items and total price on hover. +**File:** components/CartFab.tsx **Description:** Floating Action Button +displaying cart item count. Shows badge with number of items and total price on +hover. ### Props -| Prop | Type | Required | Default | Description | -|------|------|----------|---------|-------------| -| onClick | () => void | no | undefined | Callback when FAB is clicked | +| Prop | Type | Required | Default | Description | +| ------- | ---------- | -------- | --------- | ---------------------------- | +| onClick | () => void | no | undefined | Callback when FAB is clicked | ### Features @@ -184,11 +185,11 @@ None - reads SHOP_INFO and SOCIAL_LINKS from lib/constants directly. ### Styling -| Element | Key classes | -|---------|-------------| +| Element | Key classes | +| ---------- | ----------------------------------------------- | | FAB button | fixed bottom-6 right-6, rounded-full, shadow-lg | -| Badge | absolute top-0 right-0, red bg, small font | -| Tooltip | appears on hover, shows total price | +| Badge | absolute top-0 right-0, red bg, small font | +| Tooltip | appears on hover, shows total price | ### Dependencies @@ -201,31 +202,33 @@ None - reads SHOP_INFO and SOCIAL_LINKS from lib/constants directly. ## AuthContext (lib/auth-context.tsx) -**File:** lib/auth-context.tsx -**Description:** Manages user authentication state including login, logout, and registration. Uses localStorage for persistence. +**File:** lib/auth-context.tsx **Description:** Manages user authentication +state including login, logout, and registration. Uses localStorage for +persistence. ### Provider Props -| Prop | Type | Required | Description | -|------|------|----------|-------------| -| children | React.ReactNode | yes | Child components | +| Prop | Type | Required | Description | +| -------- | --------------- | -------- | ---------------- | +| children | React.ReactNode | yes | Child components | ### Hook: useAuth() Returns `AuthContextType` with: -| Property | Type | Description | -|----------|------|-------------| -| user | User \| null | Current logged-in user or null | -| login | (username: string, password: string) => boolean | Login function; returns success status | -| logout | () => void | Logout function; clears user and localStorage | -| registerPhone | string \| null | Phone number during registration flow | -| setRegisterPhone | (phone: string \| null) => void | Update registerPhone state | -| completeRegistration | (phone: string) => void | Complete registration and create customer account | +| Property | Type | Description | +| -------------------- | ----------------------------------------------- | ------------------------------------------------- | +| user | User \| null | Current logged-in user or null | +| login | (username: string, password: string) => boolean | Login function; returns success status | +| logout | () => void | Logout function; clears user and localStorage | +| registerPhone | string \| null | Phone number during registration flow | +| setRegisterPhone | (phone: string \| null) => void | Update registerPhone state | +| completeRegistration | (phone: string) => void | Complete registration and create customer account | ### Mock Database Pre-configured accounts: + - Manager: `admin / admin` - Staff: `Nguyễn Văn An / Nguyễn Văn An`, `Trần Thị Bình / Trần Thị Bình`, etc. - Customer: Phone number as username, `user1` as password @@ -239,29 +242,29 @@ Pre-configured accounts: ## CartContext (lib/cart-context.tsx) -**File:** lib/cart-context.tsx -**Description:** Manages shopping cart state with localStorage persistence. Tracks items, quantities, and totals. +**File:** lib/cart-context.tsx **Description:** Manages shopping cart state with +localStorage persistence. Tracks items, quantities, and totals. ### Provider Props -| Prop | Type | Required | Description | -|------|------|----------|-------------| -| children | React.ReactNode | yes | Child components | +| Prop | Type | Required | Description | +| -------- | --------------- | -------- | ---------------- | +| children | React.ReactNode | yes | Child components | ### Hook: useCart() Returns `CartContextValue` with: -| Property | Type | Description | -|----------|------|-------------| -| items | CartItem[] | Array of items in cart | -| totalItems | number | Total quantity of items | -| totalPrice | number | Total price in VND | -| addToCart | (product: Product) => void | Add or increase product quantity | -| increaseQty | (id: number) => void | Increase product quantity by 1 | -| decreaseQty | (id: number) => void | Decrease product quantity by 1 (removes if qty reaches 0) | -| removeFromCart | (id: number) => void | Remove product from cart | -| setQuantity | (id: number, quantity: number) => void | Set exact quantity (removes if 0) | +| Property | Type | Description | +| -------------- | -------------------------------------- | --------------------------------------------------------- | +| items | CartItem[] | Array of items in cart | +| totalItems | number | Total quantity of items | +| totalPrice | number | Total price in VND | +| addToCart | (product: Product) => void | Add or increase product quantity | +| increaseQty | (id: number) => void | Increase product quantity by 1 | +| decreaseQty | (id: number) => void | Decrease product quantity by 1 (removes if qty reaches 0) | +| removeFromCart | (id: number) => void | Remove product from cart | +| setQuantity | (id: number, quantity: number) => void | Set exact quantity (removes if 0) | ### CartItem Interface @@ -285,23 +288,24 @@ interface CartItem { ## MenuContext (lib/menu-context.tsx) -**File:** lib/menu-context.tsx -**Description:** Provides shared category/menu state across components. Synchronizes Header mobile menu and Navbar sidebar selection. +**File:** lib/menu-context.tsx **Description:** Provides shared category/menu +state across components. Synchronizes Header mobile menu and Navbar sidebar +selection. ### Provider Props -| Prop | Type | Required | Description | -|------|------|----------|-------------| -| children | React.ReactNode | yes | Child components | +| Prop | Type | Required | Description | +| -------- | --------------- | -------- | ---------------- | +| children | React.ReactNode | yes | Child components | ### Hook: useMenu() Returns `MenuContextType` with: -| Property | Type | Description | -|----------|------|-------------| -| activeCategory | string | Currently selected category id (default: "all") | -| setActiveCategory | (id: string) => void | Update active category | +| Property | Type | Description | +| ----------------- | -------------------- | ----------------------------------------------- | +| activeCategory | string | Currently selected category id (default: "all") | +| setActiveCategory | (id: string) => void | Update active category | ### Use Cases diff --git a/layouts/LAYOUTS.md b/layouts/LAYOUTS.md index 80b387a..17e0648 100644 --- a/layouts/LAYOUTS.md +++ b/layouts/LAYOUTS.md @@ -6,7 +6,9 @@ ## Overview -The `layouts/` directory contains layout-level components used across all pages. These are included in the root layout and provide consistent header/footer across the application. +The `layouts/` directory contains layout-level components used across all pages. +These are included in the root layout and provide consistent header/footer +across the application. ``` layouts/ @@ -19,9 +21,8 @@ layouts/ ## Header (layouts/header.tsx) -**File:** layouts/header.tsx -**Type:** Client component -**Description:** Sticky top navigation bar with brand info and authentication status display. +**File:** layouts/header.tsx **Type:** Client component **Description:** Sticky +top navigation bar with brand info and authentication status display. ### Layout @@ -33,48 +34,53 @@ height: 72px (var(--spacing-header-height)) ``` **2-Column Layout:** + - **Left:** Shop branding (logo + name + tagline) - **Right:** Auth status indicator ### Features #### Logo & Branding + - Shop logo (40x40px) - Shop name (bold text) - Tagline (hidden on mobile < md, visible md+) -**Responsive:** -| Breakpoint | Logo | Name | Tagline | -|-----------|------|------|---------| -| < sm (640px) | Yes | Yes | Hidden | -| sm-md | Yes | Yes | Hidden | -| md+ (768px) | Yes | Yes | Visible | +**Responsive:** | Breakpoint | Logo | Name | Tagline | +|-----------|------|------|---------| | < sm (640px) | Yes | Yes | Hidden | | +sm-md | Yes | Yes | Hidden | | md+ (768px) | Yes | Yes | Visible | #### Authentication Status The header cycles through 3 auth states (for UI demo): **State 1: Guest (Not logged in)** + ``` [brown button] "Dang nhap" ``` + - Guest state (user = null) - Brown primary button - Click: toggles to next state **State 2: Manager** + ``` [caramel/gold badge] "👔 Quản lý" ``` + - Shows manager role - Gold/caramel colored badge - User tie icon - Name: Nguyễn Văn An **State 3: Staff** + ``` [border button] "👤 [Name]" ``` + - Shows staff role with avatar placeholder - Bordered button style - Name: Trần Thị Bình @@ -82,19 +88,21 @@ The header cycles through 3 auth states (for UI demo): ### Responsive Behavior -| Breakpoint | Layout | -|-----------|--------| -| < sm | Stacked vertically | -| sm-md (640px) | Side-by-side, reduced spacing | -| md+ (768px) | Full width, comfortable spacing | +| Breakpoint | Layout | +| ------------- | ------------------------------- | +| < sm | Stacked vertically | +| sm-md (640px) | Side-by-side, reduced spacing | +| md+ (768px) | Full width, comfortable spacing | **Mobile (<640px):** + - Logo smaller - Name only (no tagline) - Auth button text hidden, icon shown - Touch-friendly padding **Desktop (≥640px):** + - Normal logo size - Full layout with tagline - Button with text and icon @@ -102,16 +110,16 @@ The header cycles through 3 auth states (for UI demo): ### Styling -| Element | Classes | -|---------|---------| -| Header wrapper | `sticky top-0 z-50 bg-white shadow-md` | -| Container | `max-w-7xl mx-auto px-4 md:px-6 h-72px flex items-center` | -| Left section (brand) | `flex items-center gap-3 flex-1` | -| Right section (auth) | `flex items-center gap-3 shrink-0` | -| Logo image | `w-10 h-10 md:w-12 md:h-12` | -| Brand text | `font-bold text-sm md:text-base` | -| Tagline | `hidden md:block text-xs text-muted-foreground` | -| Auth button | `px-4 py-2 rounded-lg text-sm font-medium` | +| Element | Classes | +| -------------------- | --------------------------------------------------------- | +| Header wrapper | `sticky top-0 z-50 bg-white shadow-md` | +| Container | `max-w-7xl mx-auto px-4 md:px-6 h-72px flex items-center` | +| Left section (brand) | `flex items-center gap-3 flex-1` | +| Right section (auth) | `flex items-center gap-3 shrink-0` | +| Logo image | `w-10 h-10 md:w-12 md:h-12` | +| Brand text | `font-bold text-sm md:text-base` | +| Tagline | `hidden md:block text-xs text-muted-foreground` | +| Auth button | `px-4 py-2 rounded-lg text-sm font-medium` | ### CSS Variables Used @@ -130,11 +138,13 @@ The header cycles through 3 auth states (for UI demo): - **next/link** - Navigation links - **lib/constants:** SHOP_INFO, MOCK_USERS - **lib/types:** User -- **FontAwesome icons:** fa-sign-in-alt, fa-sign-out-alt, fa-user-tie, fa-user-circle +- **FontAwesome icons:** fa-sign-in-alt, fa-sign-out-alt, fa-user-tie, + fa-user-circle ### Key Code Snippets **Auth Demo State Machine:** + ```typescript const [user, setUser] = useState(null); @@ -150,6 +160,7 @@ const handleAuthClick = () => { ``` **Responsive Brand Text:** + ```typescript
{SHOP_INFO.name} @@ -163,9 +174,9 @@ const handleAuthClick = () => { ## Footer (layouts/footer.tsx) -**File:** layouts/footer.tsx -**Type:** Client component (uses constants) -**Description:** Site footer with shop information, social links, and WiFi details. +**File:** layouts/footer.tsx **Type:** Client component (uses constants) +**Description:** Site footer with shop information, social links, and WiFi +details. ### Layout @@ -179,17 +190,18 @@ const handleAuthClick = () => { **12-Column Grid Layout:** -| Breakpoint | Brand Info | Social + WiFi | -|-----------|-----------|---------------| -| Mobile | col-span-12 | col-span-12 | -| md (768px) | col-span-6 | col-span-6 | -| lg+ (1024px) | col-span-6 | col-span-6 | +| Breakpoint | Brand Info | Social + WiFi | +| ------------ | ----------- | ------------- | +| Mobile | col-span-12 | col-span-12 | +| md (768px) | col-span-6 | col-span-6 | +| lg+ (1024px) | col-span-6 | col-span-6 | ### Sections #### 1. Brand Info (Left Section) **Content:** + - Shop logo (40x40px) - Shop name (bold) - Tagline (gray text) @@ -199,6 +211,7 @@ const handleAuthClick = () => { - Open hours with clock icon **Responsive:** + ``` Mobile: └─ Logo @@ -216,11 +229,13 @@ Desktop: #### 2. Social Links (Top Right) **Links:** + - Facebook icon → SHOP_INFO.facebook - TikTok icon → SHOP_INFO.tiktok - Website icon → SHOP_INFO.website **Styling:** + - Icons in circle backgrounds - Hover effect (color change) - Flex row layout @@ -229,17 +244,20 @@ Desktop: #### 3. WiFi Card (Bottom Right) **Content:** + - "📶 WiFi miễn phí" label - Network name (monospace) - Password (monospace, can be hidden/shown) **Styling:** + - Light gray background - Rounded borders - Monospace font for credentials - Eye icon toggle for password visibility **Example:** + ``` 📶 WiFi miễn phí ┌────────────────────────┐ @@ -252,11 +270,13 @@ Desktop: #### 4. Copyright Bar (Bottom) **Content:** + - Copyright text: "© 2024 Coffee Shop" - "Made with ❤️ in Vietnam" - Centered **Styling:** + - Small text - Gray color - Subtle separator line above @@ -264,35 +284,38 @@ Desktop: ### Responsive Behavior **Mobile (<768px):** + - Single column layout - Stacked sections - Full width - Padding around edges **Tablet (768px):** + - 2-column layout - Brand info left, Social + WiFi right - Equal width columns **Desktop (≥768px):** + - 2-column layout with more spacing - Brand info slightly smaller - Comfortable padding ### Styling -| Element | Classes | -|---------|---------| -| Footer wrapper | `bg-gray-100 border-t` | -| Container | `max-w-7xl mx-auto px-4 py-8` | -| Grid | `grid grid-cols-12 gap-8` | -| Brand section | `col-span-12 md:col-span-6` | -| Social section | `col-span-12 md:col-span-6` | -| Logo | `w-10 h-10` | -| Info text | `text-sm text-gray-600` | -| Social icons | `w-10 h-10 rounded-full flex items-center justify-center` | -| WiFi card | `bg-white p-4 rounded-lg border` | -| Copyright bar | `border-t mt-8 pt-6 text-center text-xs text-gray-500` | +| Element | Classes | +| -------------- | --------------------------------------------------------- | +| Footer wrapper | `bg-gray-100 border-t` | +| Container | `max-w-7xl mx-auto px-4 py-8` | +| Grid | `grid grid-cols-12 gap-8` | +| Brand section | `col-span-12 md:col-span-6` | +| Social section | `col-span-12 md:col-span-6` | +| Logo | `w-10 h-10` | +| Info text | `text-sm text-gray-600` | +| Social icons | `w-10 h-10 rounded-full flex items-center justify-center` | +| WiFi card | `bg-white p-4 rounded-lg border` | +| Copyright bar | `border-t mt-8 pt-6 text-center text-xs text-gray-500` | ### CSS Variables Used @@ -311,11 +334,13 @@ Desktop: - **next/image** - Shop logo - **next/link** - Social links - **lib/constants:** SHOP_INFO, SOCIAL_LINKS -- **FontAwesome icons:** location-dot, phone, envelope, clock, facebook, tiktok, globe, wifi, eye, eye-slash +- **FontAwesome icons:** location-dot, phone, envelope, clock, facebook, tiktok, + globe, wifi, eye, eye-slash ### Key Code Snippets **Brand Info Section:** + ```typescript
{SHOP_INFO.name} @@ -329,6 +354,7 @@ Desktop: ``` **Social Links:** + ```typescript
@@ -339,6 +365,7 @@ Desktop: ``` **WiFi Display:** + ```typescript

📶 WiFi miễn phí

@@ -370,6 +397,7 @@ export default function RootLayout({ children }) { ``` **Result:** + - Header: Always at top (sticky) - Content: Takes full width between header/footer - Footer: Always at bottom @@ -446,9 +474,7 @@ CSS variables are set up for dark mode support. To enable: 2. Or use Tailwind dark class: ```html -
- Content -
+
Content
``` --- @@ -456,18 +482,21 @@ CSS variables are set up for dark mode support. To enable: ## Accessibility ### Header + - Logo has alt text - Auth button has aria-label - Icons have semantic meaning - Good contrast ratios ### Footer + - Headings use semantic tags - Links have descriptive text - Icons are decorative (aria-hidden) - Monospace font for technical info (WiFi credentials) ### General + - Touch targets ≥ 48px on mobile - Sufficient color contrast - Semantic HTML structure diff --git a/lib/LIB.md b/lib/LIB.md index daebee5..af4c065 100644 --- a/lib/LIB.md +++ b/lib/LIB.md @@ -6,7 +6,8 @@ ## Overview -The `lib/` directory contains shared logic, data models, and context providers used throughout the application. +The `lib/` directory contains shared logic, data models, and context providers +used throughout the application. ``` lib/ @@ -41,6 +42,7 @@ interface User { **Usage:** Authentication context, header component, role-based UI **Roles:** + - **manager** - Shop owner, full access to menu management and orders - **staff** - Staff member, can view/process orders - **customer** - Regular customer, can browse and order @@ -60,6 +62,7 @@ interface MenuCategory { **Usage:** Sidebar navigation, category filter, product display **Example Categories:** + - `all` - All products - `cafe` - Coffee - `tra` - Tea @@ -88,6 +91,7 @@ interface Product { **Usage:** Product grid display, cart items, filtering **Key Fields:** + - `id` - Unique product identifier - `name` - Display name in Vietnamese - `category` - Category ID for filtering @@ -122,6 +126,7 @@ interface ShopInfo { **Usage:** Header, footer, login page display **Example:** + ```typescript const SHOP_INFO: ShopInfo = { name: "Coffee Shop", @@ -169,13 +174,15 @@ interface Shop { ## Constants (lib/constants.ts) -**Description:** Mock data used throughout the application. Replace with API calls when backend is ready. +**Description:** Mock data used throughout the application. Replace with API +calls when backend is ready. ### SHOP_INFO Single instance of shop information displayed in header, footer, and login page. **Key Info Used:** + - Header: name, logo, phone - Footer: all fields - Login: logo, name, email @@ -198,7 +205,8 @@ export const SOCIAL_LINKS: SocialLinks = { ### MENU_CATEGORIES -Array of 8 product categories. Used in sidebar, mobile menu, and product filtering. +Array of 8 product categories. Used in sidebar, mobile menu, and product +filtering. ```typescript export const MENU_CATEGORIES: MenuCategory[] = [ @@ -208,12 +216,17 @@ export const MENU_CATEGORIES: MenuCategory[] = [ { id: "sua-chua", name: "Sữa Chua", icon: "fa-solid fa-jar" }, { id: "nuoc-ep", name: "Nước Ép", icon: "fa-solid fa-blender" }, { id: "latte", name: "Latte", icon: "fa-solid fa-mug-saucer" }, - { id: "giai-khat", name: "Giải Khát / Ăn Vặt", icon: "fa-solid fa-ice-cream" }, + { + id: "giai-khat", + name: "Giải Khát / Ăn Vặt", + icon: "fa-solid fa-ice-cream", + }, { id: "topping", name: "Topping", icon: "fa-solid fa-layer-group" }, ]; ``` **Usage:** + - Navbar sidebar category buttons - Header mobile scrollable menu - Product grid category filter @@ -225,6 +238,7 @@ export const MENU_CATEGORIES: MenuCategory[] = [ Array of 18 mock product items across all categories. **Example Product:** + ```typescript { id: 1, @@ -238,6 +252,7 @@ Array of 18 mock product items across all categories. ``` **Product Distribution:** + - Café: 4 items (Đen, Sữa, Bạc Xỉu, Trứng) - Tea: 3 items (Đào Cam Sả, Matcha, Vải Hoa Nhài) - Yogurt: 2 items (Trân Châu, Dâu) @@ -264,6 +279,7 @@ Array of 5 coffee shops for the feed/discovery page. ``` **Shops:** + 1. The Coffee House - Quận 3 2. Highlands Coffee - Quận 1 3. Phúc Long Heritage - Quận 1 @@ -303,9 +319,11 @@ export const MOCK_USERS: Record = { ## Auth Context (lib/auth-context.tsx) -See [COMPONENTS.md - AuthContext](../components/COMPONENTS.md#authcontext) for detailed documentation. +See [COMPONENTS.md - AuthContext](../components/COMPONENTS.md#authcontext) for +detailed documentation. **Quick Summary:** + - Manages user login/logout/register - Persists user in localStorage - Provides user info to components via useAuth() hook @@ -314,9 +332,11 @@ See [COMPONENTS.md - AuthContext](../components/COMPONENTS.md#authcontext) for d ## Cart Context (lib/cart-context.tsx) -See [COMPONENTS.md - CartContext](../components/COMPONENTS.md#cartcontext) for detailed documentation. +See [COMPONENTS.md - CartContext](../components/COMPONENTS.md#cartcontext) for +detailed documentation. **Quick Summary:** + - Manages shopping cart items and quantities - Persists cart in localStorage - Provides cart operations via useCart() hook @@ -325,9 +345,11 @@ See [COMPONENTS.md - CartContext](../components/COMPONENTS.md#cartcontext) for d ## Menu Context (lib/menu-context.tsx) -See [COMPONENTS.md - MenuContext](../components/COMPONENTS.md#menucontext) for detailed documentation. +See [COMPONENTS.md - MenuContext](../components/COMPONENTS.md#menucontext) for +detailed documentation. **Quick Summary:** + - Shares active category state - Syncs sidebar and mobile menu selection - Provides activeCategory and setActiveCategory via useMenu() hook @@ -339,7 +361,7 @@ See [COMPONENTS.md - MenuContext](../components/COMPONENTS.md#menucontext) for d ### Using Types ```typescript -import type { User, Product, MenuCategory } from "@/lib/types"; +import type { MenuCategory, Product, User } from "@/lib/types"; ``` ### Using Constants @@ -348,7 +370,7 @@ import type { User, Product, MenuCategory } from "@/lib/types"; import { MENU_CATEGORIES, MOCK_PRODUCTS, SHOP_INFO } from "@/lib/constants"; // In a component: -const products = MOCK_PRODUCTS.filter(p => p.category === "cafe"); +const products = MOCK_PRODUCTS.filter((p) => p.category === "cafe"); const shopName = SHOP_INFO.name; ``` @@ -412,6 +434,7 @@ export default function CategoryFilter() { ## Data Flow & Updates ### When to Update Constants + 1. **Product List:** When adding/removing products - Update MOCK_PRODUCTS array - Or replace with API call in the future @@ -436,7 +459,7 @@ When backend is ready: const [products, setProducts] = useState([]); useEffect(() => { fetch("/api/products") - .then(r => r.json()) + .then((r) => r.json()) .then(setProducts); }, []); @@ -444,7 +467,7 @@ useEffect(() => { const login = async (username: string, password: string) => { const res = await fetch("/api/auth/login", { method: "POST", - body: JSON.stringify({ username, password }) + body: JSON.stringify({ username, password }), }); return res.ok; }; @@ -455,7 +478,10 @@ const login = async (username: string, password: string) => { ## Best Practices 1. **Import Types:** Always use `import type` for types to avoid runtime bloat -2. **Immutability:** Contexts return functions to update state, not direct mutations -3. **localStorage:** Keys are centralized (`coffee-shop-user`, `coffee-shop-cart`) -4. **Validation:** Contexts validate/sanitize data (e.g., filter invalid cart items) +2. **Immutability:** Contexts return functions to update state, not direct + mutations +3. **localStorage:** Keys are centralized (`coffee-shop-user`, + `coffee-shop-cart`) +4. **Validation:** Contexts validate/sanitize data (e.g., filter invalid cart + items) 5. **Default Values:** Contexts have sensible defaults (activeCategory: "all") diff --git a/lib/constants.ts b/lib/constants.ts index c59816d..596cb13 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,4 +1,11 @@ -import type { MenuCategory, Product, Shop, ShopInfo, SocialLinks, User } from "./types"; +import type { + MenuCategory, + Product, + Shop, + ShopInfo, + SocialLinks, + User, +} from "./types"; // ===== SHOP INFORMATION ===== export const SHOP_INFO: ShopInfo = { @@ -231,31 +238,36 @@ export const MOCK_SHOPS: Shop[] = [ id: 1, name: "The Coffee House", address: "86 Cao Thắng, Quận 3, TP. Hồ Chí Minh", - image: "https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=600&h=400&fit=crop", + image: + "https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=600&h=400&fit=crop", }, { id: 2, name: "Highlands Coffee", address: "123 Nguyễn Huệ, Quận 1, TP. Hồ Chí Minh", - image: "https://images.unsplash.com/photo-1559305616-3f99cd43e353?w=600&h=400&fit=crop", + image: + "https://images.unsplash.com/photo-1559305616-3f99cd43e353?w=600&h=400&fit=crop", }, { id: 3, name: "Phúc Long Heritage", address: "42 Lê Lợi, Quận 1, TP. Hồ Chí Minh", - image: "https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=600&h=400&fit=crop", + image: + "https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=600&h=400&fit=crop", }, { id: 4, name: "Katinat Saigon Kafe", address: "26 Lý Tự Trọng, Quận 1, TP. Hồ Chí Minh", - image: "https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=600&h=400&fit=crop", + image: + "https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=600&h=400&fit=crop", }, { id: 5, name: "Trung Nguyên E-Coffee", address: "15 Hai Bà Trưng, Quận 1, TP. Hồ Chí Minh", - image: "https://images.unsplash.com/photo-1453614512568-c4024d13c247?w=600&h=400&fit=crop", + image: + "https://images.unsplash.com/photo-1453614512568-c4024d13c247?w=600&h=400&fit=crop", }, ]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c4c8d7..d174c7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: next: specifier: 16.1.7 version: 16.1.7(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + php: + specifier: ^1.1.0 + version: 1.1.0 react: specifier: 19.2.3 version: 19.2.3 @@ -1174,8 +1177,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001781: - resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} + caniuse-lite@1.0.30001782: + resolution: {integrity: sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==} chalk@2.4.1: resolution: {integrity: sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==} @@ -1277,8 +1280,8 @@ packages: resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} engines: {node: '>= 0.6'} - conventional-changelog-angular@8.3.0: - resolution: {integrity: sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==} + conventional-changelog-angular@8.3.1: + resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} conventional-changelog-writer@8.4.0: @@ -1290,8 +1293,8 @@ packages: resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} engines: {node: '>=18'} - conventional-commits-parser@6.3.0: - resolution: {integrity: sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==} + conventional-commits-parser@6.4.0: + resolution: {integrity: sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==} engines: {node: '>=18'} hasBin: true @@ -2968,6 +2971,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + php@1.1.0: + resolution: {integrity: sha512-IUIOrFBooOyTP3SD9zZZ0cX2UwL5fQj3cmuaXGcc1gsSbMdHseNcEmpwXoh+b0G+hv5LfBL0nBggEOS2YRk7sQ==} + engines: {node: '>=18.0.0'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4308,10 +4315,10 @@ snapshots: '@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.3(typescript@5.9.3))': dependencies: - conventional-changelog-angular: 8.3.0 + conventional-changelog-angular: 8.3.1 conventional-changelog-writer: 8.4.0 conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.3.0 + conventional-commits-parser: 6.4.0 debug: 4.4.3 import-from-esm: 2.0.0 lodash-es: 4.17.23 @@ -4380,10 +4387,10 @@ snapshots: '@semantic-release/release-notes-generator@14.1.0(semantic-release@25.0.3(typescript@5.9.3))': dependencies: - conventional-changelog-angular: 8.3.0 + conventional-changelog-angular: 8.3.1 conventional-changelog-writer: 8.4.0 conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.3.0 + conventional-commits-parser: 6.4.0 debug: 4.4.3 get-stream: 7.0.1 import-from-esm: 2.0.0 @@ -4933,7 +4940,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.12 - caniuse-lite: 1.0.30001781 + caniuse-lite: 1.0.30001782 electron-to-chromium: 1.5.328 node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -4978,7 +4985,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001781: {} + caniuse-lite@1.0.30001782: {} chalk@2.4.1: dependencies: @@ -5096,7 +5103,7 @@ snapshots: content-type@1.0.4: {} - conventional-changelog-angular@8.3.0: + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -5110,7 +5117,7 @@ snapshots: conventional-commits-filter@5.0.0: {} - conventional-commits-parser@6.3.0: + conventional-commits-parser@6.4.0: dependencies: '@simple-libs/stream-utils': 1.2.0 meow: 13.2.0 @@ -6589,7 +6596,7 @@ snapshots: '@next/env': 16.1.7 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.12 - caniuse-lite: 1.0.30001781 + caniuse-lite: 1.0.30001782 postcss: 8.4.31 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -6850,6 +6857,8 @@ snapshots: path-type@4.0.0: {} + php@1.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.2: {}