Refactor README and component documentation for clarity and consistency; update layout and formatting across various components; enhance analytics charts and payment summary card functionality; improve login form imports and structure; optimize product card button implementation; ensure consistent styling and spacing in manager products tab.

This commit is contained in:
Thanh Quy - wolf
2026-04-17 18:31:33 +07:00
parent c99323ff9e
commit 2875d39f2c
18 changed files with 495 additions and 267 deletions
+97 -101
View File
@@ -5,7 +5,8 @@ description: Create modern, responsive frontend components and layouts using ato
# Atomic Design Frontend System with Tailwind CSS
A comprehensive guide for building modern, responsive frontend applications using atomic design principles and Tailwind CSS.
A comprehensive guide for building modern, responsive frontend applications
using atomic design principles and Tailwind CSS.
## Core Principles
@@ -14,20 +15,25 @@ A comprehensive guide for building modern, responsive frontend applications usin
Atomic Design breaks UI into five distinct levels:
#### **Atoms**
Smallest, indivisible UI elements that cannot be broken down without losing functionality.
Smallest, indivisible UI elements that cannot be broken down without losing
functionality.
- Buttons, input fields, labels, icons, text styles
- Color variables, spacing units, typography scales
- Simple, pure, reusable building blocks
```jsx
// Example: Button Atom
<button className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
<button className="rounded-lg bg-blue-600 px-4 py-2 text-white transition-colors hover:bg-blue-700">
Click me
</button>
```
#### **Molecules**
Groups of atoms bonded together, forming simple functional units.
- Search bars (input + button + icon)
- Form fields (label + input + error message)
- Card headers (avatar + title + subtitle)
@@ -35,18 +41,16 @@ Groups of atoms bonded together, forming simple functional units.
```jsx
// Example: Search Molecule
<div className="flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-lg">
<SearchIcon className="w-5 h-5 text-gray-500" />
<input
type="text"
placeholder="Search..."
className="flex-1 outline-none"
/>
<div className="flex items-center gap-2 rounded-lg border border-gray-300 px-4 py-2">
<SearchIcon className="h-5 w-5 text-gray-500" />
<input type="text" placeholder="Search..." className="flex-1 outline-none" />
</div>
```
#### **Organisms**
Complex functional units made of groups of molecules and/or atoms.
- Header/Navigation bars
- Form sections (multiple form molecules)
- Card layouts with multiple sections
@@ -55,28 +59,33 @@ Complex functional units made of groups of molecules and/or atoms.
```jsx
// Example: Product Card Organism
<div className="border border-gray-200 rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow">
<img src="image.jpg" className="w-full h-48 object-cover" />
<div className="overflow-hidden rounded-lg border border-gray-200 shadow-sm transition-shadow hover:shadow-md">
<img src="image.jpg" className="h-48 w-full object-cover" />
<div className="p-4">
<h3 className="font-semibold text-lg">Product Name</h3>
<p className="text-gray-600 text-sm mt-1">Description</p>
<div className="flex justify-between items-center mt-4">
<span className="text-blue-600 font-bold">$99</span>
<button className="px-3 py-1 bg-blue-600 text-white rounded">Add</button>
<h3 className="text-lg font-semibold">Product Name</h3>
<p className="mt-1 text-sm text-gray-600">Description</p>
<div className="mt-4 flex items-center justify-between">
<span className="font-bold text-blue-600">$99</span>
<button className="rounded bg-blue-600 px-3 py-1 text-white">Add</button>
</div>
</div>
</div>
```
#### **Templates**
Page-level wireframes showing layout and component placement without final content.
Page-level wireframes showing layout and component placement without final
content.
- Single-column layouts
- Two-column layouts (sidebar + main)
- Grid-based layouts
- Hero + content sections
#### **Pages**
Specific instances of templates populated with real content and data.
- Homepage with actual products
- User profile with real user data
- Dashboard with live metrics
@@ -86,6 +95,7 @@ Specific instances of templates populated with real content and data.
## Design System Variables (Reusable Values)
### Color Palette
```css
/* Define in Tailwind config or use CSS variables */
Primary: #2563eb (blue-600)
@@ -97,6 +107,7 @@ Neutral: #6b7280 (gray-500)
```
### Typography Scale
```css
H1: 32px (2rem) - font-bold
H2: 24px (1.5rem) - font-bold
@@ -107,6 +118,7 @@ Tiny: 12px (0.75rem) - font-normal
```
### Spacing Scale
```css
xs: 4px (0.25rem)
sm: 8px (0.5rem)
@@ -117,6 +129,7 @@ xl: 32px (2rem)
```
### Border Radius
```css
Subtle: 4px (rounded-sm)
Standard: 8px (rounded-lg)
@@ -125,6 +138,7 @@ Full: 9999px (rounded-full)
```
### Box Shadows
```css
Subtle: 0 1px 2px rgba(0,0,0,0.05)
Soft: 0 4px 6px rgba(0,0,0,0.07)
@@ -137,6 +151,7 @@ Strong: 0 20px 25px rgba(0,0,0,0.15)
## Responsive Design Strategy
### Breakpoints (Tailwind Default)
```
Mobile: < 640px (sm)
Tablet: 640px (md, lg)
@@ -144,15 +159,17 @@ Desktop: 1024px+ (xl, 2xl)
```
### Mobile-First Approach
1. **Start with mobile styles** (default, no prefix)
2. **Layer tablet styles** (md: prefix)
3. **Layer desktop styles** (lg:, xl: prefix)
### Example: Responsive Layout
```jsx
// Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{items.map(item => (
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{items.map((item) => (
<Card key={item.id} {...item} />
))}
</div>
@@ -161,39 +178,42 @@ Desktop: 1024px+ (xl, 2xl)
### Common Responsive Patterns
**Responsive Typography**
```jsx
<h1 className="text-2xl md:text-3xl lg:text-4xl font-bold">
<h1 className="text-2xl font-bold md:text-3xl lg:text-4xl">
Responsive Heading
</h1>
```
**Responsive Padding/Margins**
```jsx
<div className="p-4 md:p-6 lg:p-8">
Content with responsive spacing
</div>
<div className="p-4 md:p-6 lg:p-8">Content with responsive spacing</div>
```
**Responsive Grid**
```jsx
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-6">
<div className="grid grid-cols-2 gap-4 md:grid-cols-3 md:gap-6 lg:grid-cols-4">
{/* Grid items */}
</div>
```
**Responsive Flexbox**
```jsx
<div className="flex flex-col md:flex-row gap-4">
<div className="flex flex-col gap-4 md:flex-row">
<aside className="w-full md:w-64">Sidebar</aside>
<main className="flex-1">Main content</main>
</div>
```
**Responsive Images**
```jsx
<img
src="image.jpg"
className="w-full h-auto object-cover"
<img
src="image.jpg"
className="h-auto w-full object-cover"
alt="Responsive image"
/>
```
@@ -203,6 +223,7 @@ Desktop: 1024px+ (xl, 2xl)
## Modern Design Patterns
### 1. Consistency & Visual Hierarchy
- **Use consistent spacing**: Apply spacing scale uniformly
- **Establish clear hierarchy**: Size, weight, color for emphasis
- **Group related content**: Use whitespace to separate sections
@@ -211,16 +232,15 @@ Desktop: 1024px+ (xl, 2xl)
```jsx
<section className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-2">Section Title</h2>
<h2 className="mb-2 text-2xl font-bold">Section Title</h2>
<p className="text-gray-600">Description text</p>
</div>
<div className="space-y-4">
{/* Related items with consistent spacing */}
</div>
<div className="space-y-4">{/* Related items with consistent spacing */}</div>
</section>
```
### 2. Interactive Feedback
- **Hover states**: Subtle color/shadow changes
- **Active states**: Indicate current selection
- **Focus states**: Keyboard navigation support
@@ -228,35 +248,26 @@ Desktop: 1024px+ (xl, 2xl)
- **Transitions**: Smooth animations (200-300ms)
```jsx
<button className="
px-4 py-2 bg-blue-600 text-white rounded-lg
hover:bg-blue-700
active:scale-95
focus:outline-none focus:ring-2 focus:ring-blue-500
transition-all duration-200
disabled:opacity-50 disabled:cursor-not-allowed
">
<button className="rounded-lg bg-blue-600 px-4 py-2 text-white transition-all duration-200 hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:outline-none active:scale-95 disabled:cursor-not-allowed disabled:opacity-50">
Actionable Button
</button>
```
### 3. Depth & Layering
- **Subtle shadows**: Create depth without heaviness
- **Elevation levels**: Consistent shadow progression
- **Overlays**: Semi-transparent backgrounds for modals
- **Z-index strategy**: Clear layering hierarchy
```jsx
<div className="
border border-gray-200 rounded-lg
shadow-sm hover:shadow-md
transition-shadow duration-300
">
<div className="rounded-lg border border-gray-200 shadow-sm transition-shadow duration-300 hover:shadow-md">
Card content
</div>
```
### 4. Color Usage
- **Primary action**: Most frequent call-to-action
- **Secondary action**: Alternative actions
- **Semantic colors**: Status indicators (success, warning, danger)
@@ -264,16 +275,15 @@ Desktop: 1024px+ (xl, 2xl)
- **Limited palette**: 3-5 colors maximum in most designs
### 5. Whitespace & Breathing Room
- Don't crowd elements
- Use consistent gap values (gap-4, gap-6, gap-8)
- Separate sections with vertical rhythm
- Generous padding in cards and containers
```jsx
<div className="max-w-4xl mx-auto px-4 md:px-6 py-8 md:py-12">
<div className="space-y-8">
{/* Sections with good breathing room */}
</div>
<div className="mx-auto max-w-4xl px-4 py-8 md:px-6 md:py-12">
<div className="space-y-8">{/* Sections with good breathing room */}</div>
</div>
```
@@ -282,6 +292,7 @@ Desktop: 1024px+ (xl, 2xl)
## Tailwind CSS Best Practices
### 1. Use Utility Classes Effectively
```jsx
// Good: Semantic, reusable, organized
<button className="
@@ -300,16 +311,17 @@ Desktop: 1024px+ (xl, 2xl)
```
### 2. Extract Reusable Components
```jsx
// Create a Button component to avoid repetition
const Button = ({ children, variant = 'primary', ...props }) => {
const baseStyles = 'px-4 py-2 rounded-lg font-medium transition-colors';
const Button = ({ children, variant = "primary", ...props }) => {
const baseStyles = "px-4 py-2 rounded-lg font-medium transition-colors";
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
danger: 'bg-red-600 text-white hover:bg-red-700',
primary: "bg-blue-600 text-white hover:bg-blue-700",
secondary: "bg-gray-200 text-gray-900 hover:bg-gray-300",
danger: "bg-red-600 text-white hover:bg-red-700",
};
return (
<button className={`${baseStyles} ${variants[variant]}`} {...props}>
{children}
@@ -319,39 +331,25 @@ const Button = ({ children, variant = 'primary', ...props }) => {
```
### 3. Organize Utility Classes
```jsx
// Organize by category: layout → sizing → colors → effects → responsive
<div className="
/* Layout */
flex flex-col gap-4
/* Sizing */
w-full max-w-2xl
/* Spacing */
p-6 my-8
/* Colors & text */
bg-white text-gray-900
/* Borders & shadows */
border border-gray-200 rounded-lg shadow-sm
/* Effects */
hover:shadow-md transition-shadow
/* Responsive */
md:flex-row lg:gap-6
">
</div>
<div className="/* Layout */ /* Sizing */ /* Spacing */ /* Colors & text */ /* Borders & shadows */ /* Effects */ /* Responsive */ my-8 flex w-full max-w-2xl flex-col gap-4 rounded-lg border border-gray-200 bg-white p-6 text-gray-900 shadow-sm transition-shadow hover:shadow-md md:flex-row lg:gap-6"></div>
```
### 4. Use Tailwind Config for Consistency
```js
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: '#2563eb',
secondary: '#7c3aed',
primary: "#2563eb",
secondary: "#7c3aed",
},
spacing: {
gutter: '1rem',
gutter: "1rem",
},
},
},
@@ -367,26 +365,20 @@ Use this template when building atomic components:
```jsx
/**
* {Component Name}
*
*
* Atoms/Molecules/Organisms level component
* Purpose: [Brief description]
*
*
* Props:
* - prop1: type - description
* - prop2: type - description
*/
export const ComponentName = ({ prop1, prop2, className = '' }) => {
export const ComponentName = ({ prop1, prop2, className = "" }) => {
return (
<div className={`
/* Base styles */
flex flex-col gap-4 p-6
bg-white border border-gray-200 rounded-lg
/* Responsive */
md:flex-row lg:p-8
/* Custom className */
${className}
`}>
<div
className={`/* Base styles */ /* Responsive */ /* Custom className */ flex flex-col gap-4 rounded-lg border border-gray-200 bg-white p-6 md:flex-row lg:p-8 ${className} `}
>
{/* Component content */}
</div>
);
@@ -398,42 +390,46 @@ export const ComponentName = ({ prop1, prop2, className = '' }) => {
## Layout Patterns
### Container + Padding
```jsx
<div className="max-w-6xl mx-auto px-4 md:px-6 lg:px-8">
<div className="mx-auto max-w-6xl px-4 md:px-6 lg:px-8">
{/* Content constrained to max width with responsive padding */}
</div>
```
### Two-Column Sidebar Layout
```jsx
<div className="flex flex-col lg:flex-row gap-6">
<aside className="w-full lg:w-64 flex-shrink-0">
<div className="flex flex-col gap-6 lg:flex-row">
<aside className="w-full flex-shrink-0 lg:w-64">
{/* Sidebar: full width on mobile, fixed on desktop */}
</aside>
<main className="flex-1 min-w-0">
<main className="min-w-0 flex-1">
{/* Main content: takes remaining space */}
</main>
</div>
```
### Responsive Grid
```jsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{/* Items automatically stack on mobile, 2 columns on tablet, 3 on desktop */}
</div>
```
### Hero Section
```jsx
<section className="relative bg-gradient-to-r from-blue-600 to-violet-600 text-white overflow-hidden py-12 md:py-20 lg:py-32">
<div className="max-w-6xl mx-auto px-4 md:px-6 relative z-10">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold mb-4">
<section className="relative overflow-hidden bg-gradient-to-r from-blue-600 to-violet-600 py-12 text-white md:py-20 lg:py-32">
<div className="relative z-10 mx-auto max-w-6xl px-4 md:px-6">
<h1 className="mb-4 text-4xl font-bold md:text-5xl lg:text-6xl">
Hero Title
</h1>
<p className="text-lg md:text-xl opacity-90 mb-8 max-w-2xl">
<p className="mb-8 max-w-2xl text-lg opacity-90 md:text-xl">
Hero subtitle or description
</p>
<button className="px-8 py-3 bg-white text-blue-600 rounded-lg font-semibold hover:bg-gray-100 transition-colors">
<button className="rounded-lg bg-white px-8 py-3 font-semibold text-blue-600 transition-colors hover:bg-gray-100">
Call to Action
</button>
</div>
@@ -452,8 +448,8 @@ export const ComponentName = ({ prop1, prop2, className = '' }) => {
6. **Touch targets**: Minimum 44x44px for interactive elements
```jsx
<button
className="px-4 py-3 min-h-[44px] focus:outline-none focus:ring-2 focus:ring-offset-2"
<button
className="min-h-[44px] px-4 py-3 focus:ring-2 focus:ring-offset-2 focus:outline-none"
aria-label="Close modal"
>
@@ -475,6 +471,7 @@ export const ComponentName = ({ prop1, prop2, className = '' }) => {
## Quick Reference Checklist
When building a component, ensure:
- [ ] Follows atomic design hierarchy (Atom/Molecule/Organism)
- [ ] Uses design system variables (colors, spacing, typography)
- [ ] Responsive across mobile, tablet, desktop
@@ -484,4 +481,3 @@ When building a component, ensure:
- [ ] Accessible (contrast, focus, labels)
- [ ] Mobile-first approach
- [ ] No hardcoded values (use Tailwind config)
@@ -4,4 +4,4 @@
"description": "Create modern, responsive frontend components and layouts using atomic design methodology with Tailwind CSS",
"author": "Claude",
"created": "2026-04-12"
}
}
+34 -10
View File
@@ -1,6 +1,11 @@
---
name: prompt-optimizer
description: Help users rewrite and improve AI/LLM prompts by adding specificity, context, and constraints. Trigger this skill whenever users ask to improve, rewrite, optimize, or refine prompts for AI models. Focus on making prompts clearer, more specific, and more likely to produce better AI results. Present suggestions interactively so users can choose which improvements to apply.
description:
Help users rewrite and improve AI/LLM prompts by adding specificity, context,
and constraints. Trigger this skill whenever users ask to improve, rewrite,
optimize, or refine prompts for AI models. Focus on making prompts clearer,
more specific, and more likely to produce better AI results. Present
suggestions interactively so users can choose which improvements to apply.
---
# Prompt Optimizer
@@ -9,32 +14,42 @@ A beginner-friendly skill for improving AI/LLM prompts to get better results.
## What This Skill Does
This skill helps you rewrite prompts to work better with AI models like Claude. Instead of just giving you a rewritten prompt, it shows you specific improvement suggestions that you can choose to apply or skip.
This skill helps you rewrite prompts to work better with AI models like Claude.
Instead of just giving you a rewritten prompt, it shows you specific improvement
suggestions that you can choose to apply or skip.
## Key Improvements
When optimizing a prompt, focus on three main areas:
### 1. **Specificity** — Making the Request Clear
Good prompts are specific about what you want. Vague prompts get vague results.
**Example improvements:**
- Add details about format: "Give me a bullet list of 5 items" instead of "tell me about X"
- Add details about format: "Give me a bullet list of 5 items" instead of "tell
me about X"
- Be clear about length: "Write 200 words" instead of "Write something short"
- Define who the audience is: "Explain this for a 10-year-old" or "Use technical language"
- Define who the audience is: "Explain this for a 10-year-old" or "Use technical
language"
### 2. **Context** — Giving the AI Background Information
More context helps the AI make better decisions.
**Example improvements:**
- Explain the goal: "I'm writing a resume, so focus on professional language"
- Share constraints: "We only have $500 budget" or "It needs to work on mobile"
- Provide background: "I already know Python but not JavaScript"
### 3. **Constraints** — Setting Boundaries
Constraints prevent unwanted outputs.
**Example improvements:**
- Set length limits: "Keep it under 100 words"
- Specify format: "Use JSON format" or "Write as a numbered list"
- Define tone: "Be casual and friendly, not formal"
@@ -45,16 +60,20 @@ Constraints prevent unwanted outputs.
1. **Share your prompt** — Give me the original prompt you want to improve
2. **Review suggestions** — I'll show you specific improvements in each area
3. **Choose what you like** — Pick which suggestions to apply
4. **Get the final version** — I'll rewrite your prompt with your chosen improvements
4. **Get the final version** — I'll rewrite your prompt with your chosen
improvements
## Interactive Selection Process
When you use this skill, you'll see:
- **Original prompt** — Your starting point
- **Improvement suggestions** — Specific changes grouped by category (Specificity, Context, Constraints)
- **Preview examples** — What each change would look like with the improvement applied
- **Your choices** — You pick which suggestions help most (you can apply all, some, or none)
- **Improvement suggestions** — Specific changes grouped by category
(Specificity, Context, Constraints)
- **Preview examples** — What each change would look like with the improvement
applied
- **Your choices** — You pick which suggestions help most (you can apply all,
some, or none)
Then you get a rewritten prompt combining all your choices.
@@ -63,14 +82,18 @@ Then you get a rewritten prompt combining all your choices.
**Original:** "Write me a blog post"
**Suggestions I might offer:**
- **Specificity**: Add a topic (e.g., "about sustainable living")
- **Context**: Explain your goal (e.g., "to build authority on my website")
- **Constraints**: Set a word count (e.g., "800-1000 words")
**Your choice:** "I want all three — add topic, goal, and word count"
**Final rewritten prompt:**
"Write an 800-1000 word blog post about sustainable living for my website. The goal is to establish my authority on eco-friendly practices. Target an audience of people interested in reducing their carbon footprint. Include 3-4 practical tips they can implement immediately, and end with a call-to-action encouraging them to sign up for my newsletter."
**Final rewritten prompt:** "Write an 800-1000 word blog post about sustainable
living for my website. The goal is to establish my authority on eco-friendly
practices. Target an audience of people interested in reducing their carbon
footprint. Include 3-4 practical tips they can implement immediately, and end
with a call-to-action encouraging them to sign up for my newsletter."
## Tips for Best Results
@@ -82,6 +105,7 @@ Then you get a rewritten prompt combining all your choices.
## What Makes a Good Prompt
A prompt becomes "good" when:
- The AI understands exactly what you want ✓
- You've given enough context to explain why ✓
- You've set boundaries to prevent bad outputs ✓
+61 -33
View File
@@ -1,6 +1,13 @@
---
name: ui-ux-testing
description: Automated visual regression testing and UI/UX analysis for web applications. Use this skill whenever developers mention "test this UI", "visual regression", "test the UI", "check this interface", "UI testing", or want to create automated tests for web pages. Analyzes URLs and generates comprehensive test strategies including Playwright/Cypress test scripts, manual testing checklists, visual regression detection, and detailed reports with findings and recommendations.
description:
Automated visual regression testing and UI/UX analysis for web applications.
Use this skill whenever developers mention "test this UI", "visual
regression", "test the UI", "check this interface", "UI testing", or want to
create automated tests for web pages. Analyzes URLs and generates
comprehensive test strategies including Playwright/Cypress test scripts,
manual testing checklists, visual regression detection, and detailed reports
with findings and recommendations.
compatibility:
tools: Claude in Chrome browser automation
frameworks: Playwright, Cypress, Selenium
@@ -8,21 +15,28 @@ compatibility:
# UI/UX Testing Skill
This skill helps developers create automated visual regression tests and comprehensive UI/UX testing strategies for web applications.
This skill helps developers create automated visual regression tests and
comprehensive UI/UX testing strategies for web applications.
## Overview
When a developer asks you to test a UI or create visual regression tests, this skill guides you through:
When a developer asks you to test a UI or create visual regression tests, this
skill guides you through:
1. **Analyzing the target URL** - Inspect the web page structure and components
2. **Generating test strategies** - Create both automated and manual testing approaches
3. **Writing test code** - Generate Playwright/Cypress test scripts or Selenium code
4. **Creating test checklists** - Manual testing steps for visual regression and UX flows
5. **Generating reports** - Detailed findings, issues, and recommendations in markdown/HTML
2. **Generating test strategies** - Create both automated and manual testing
approaches
3. **Writing test code** - Generate Playwright/Cypress test scripts or Selenium
code
4. **Creating test checklists** - Manual testing steps for visual regression and
UX flows
5. **Generating reports** - Detailed findings, issues, and recommendations in
markdown/HTML
## When to Trigger
Trigger this skill when the user:
- Provides a URL and asks to "test this UI"
- Requests "visual regression testing" for a web page
- Wants to "check accessibility" or test a component
@@ -35,6 +49,7 @@ Trigger this skill when the user:
### Step 1: Inspect the Target URL
Use Claude in Chrome to:
- Navigate to the provided URL
- Take screenshots of different viewport sizes (desktop, tablet, mobile)
- Inspect the DOM structure using `read_page` tool
@@ -44,6 +59,7 @@ Use Claude in Chrome to:
### Step 2: Create a Test Strategy
Based on your inspection, identify:
- **Visual elements** to regression test (buttons, forms, headers, layouts)
- **Interactive flows** to test (hover states, click handlers, form submission)
- **Responsive breakpoints** to validate (mobile, tablet, desktop)
@@ -55,48 +71,51 @@ Based on your inspection, identify:
**For Automated Testing (Choose one or more):**
#### Playwright (Recommended)
```javascript
// Example structure
import { test, expect } from '@playwright/test';
import { expect, test } from "@playwright/test";
test("visual regression - homepage", async ({ page }) => {
await page.goto("https://example.com");
test('visual regression - homepage', async ({ page }) => {
await page.goto('https://example.com');
// Capture baseline screenshot
await expect(page).toHaveScreenshot('homepage.png');
await expect(page).toHaveScreenshot("homepage.png");
// Test interactive elements
await page.hover('button.primary');
await expect(page).toHaveScreenshot('button-hover.png');
await page.hover("button.primary");
await expect(page).toHaveScreenshot("button-hover.png");
});
test('responsive layout - mobile', async ({ page }) => {
test("responsive layout - mobile", async ({ page }) => {
await page.setViewportSize({ width: 375, height: 812 });
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('mobile-layout.png');
await page.goto("https://example.com");
await expect(page).toHaveScreenshot("mobile-layout.png");
});
```
#### Cypress
```javascript
describe('Visual Regression Tests', () => {
describe("Visual Regression Tests", () => {
beforeEach(() => {
cy.visit('https://example.com');
cy.visit("https://example.com");
});
it('captures baseline screenshot', () => {
cy.screenshot('homepage');
cy.get('[data-testid="header"]').should('be.visible');
it("captures baseline screenshot", () => {
cy.screenshot("homepage");
cy.get('[data-testid="header"]').should("be.visible");
});
it('tests button hover state', () => {
cy.get('button.primary').trigger('mouseenter');
cy.screenshot('button-hover-state');
it("tests button hover state", () => {
cy.get("button.primary").trigger("mouseenter");
cy.screenshot("button-hover-state");
});
});
```
#### Selenium
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
@@ -156,6 +175,7 @@ Create an HTML/Markdown report with:
# UI/UX Testing Report
## Executive Summary
- URL tested: [URL]
- Viewports tested: Desktop (1920x1080), Tablet (768x1024), Mobile (375x667)
- Testing date: [Date]
@@ -164,6 +184,7 @@ Create an HTML/Markdown report with:
## Issues Found
### Critical (Breaks functionality)
1. **Issue Title**
- Severity: Critical
- Location: [Element/Component]
@@ -173,12 +194,14 @@ Create an HTML/Markdown report with:
- Screenshot: [If applicable]
### Major (Significant visual/UX impact)
1. **Issue Title**
- Severity: Major
- Location: [Element/Component]
- Impact: [User impact]
### Minor (Polish/optimization)
1. **Issue Title**
- Severity: Minor
- Location: [Element/Component]
@@ -187,22 +210,25 @@ Create an HTML/Markdown report with:
## Visual Regression Analysis
### Desktop (1920x1080)
- [List observations]
- [List changes from baseline if available]
### Tablet (768x1024)
- [List observations]
- [Responsive issues found]
### Mobile (375x667)
- [List observations]
- [Mobile-specific issues]
## Accessibility Assessment
| Element | Issue | WCAG Level | Recommendation |
|---------|-------|-----------|-----------------|
| [Element] | [Issue] | [AA/AAA] | [Fix] |
| Element | Issue | WCAG Level | Recommendation |
| --------- | ------- | ---------- | -------------- |
| [Element] | [Issue] | [AA/AAA] | [Fix] |
## Recommendations
@@ -223,6 +249,7 @@ Create an HTML/Markdown report with:
- Regression risk: [High/Medium/Low]
---
Generated using UI/UX Testing Skill
```
@@ -237,12 +264,14 @@ Based on what the developer needs, generate:
## Best Practices
- **Multiple viewports:** Always test at least mobile (375px), tablet (768px), and desktop (1920px)
- **Multiple viewports:** Always test at least mobile (375px), tablet (768px),
and desktop (1920px)
- **Visual baselines:** Save baseline screenshots before making changes
- **Critical paths:** Prioritize testing main user workflows first
- **Accessibility first:** Include WCAG AA compliance checks
- **Clear assertions:** Make test assertions explicit and meaningful
- **Maintainability:** Use data attributes (data-testid) for reliable element selection
- **Maintainability:** Use data attributes (data-testid) for reliable element
selection
## Example: Complete Testing Session
@@ -270,5 +299,4 @@ Based on what the developer needs, generate:
---
**Last Updated:** 2024
**Skill Version:** 1.0
**Last Updated:** 2024 **Skill Version:** 1.0
@@ -1,8 +1,16 @@
---
name: website-creation-automation
description: Automate end-to-end website creation with AI-powered optimization, design, and testing. Trigger this skill whenever the user wants to create a new website, build a landing page, design a web application, or automatically generate a complete website from a description. This skill takes a user's website idea or prompt, optimizes it for clarity, designs a modern responsive website, and automatically tests it for quality issues. Use this skill for any "create a website" or "build a web application" request, including landing pages, portfolio sites, e-commerce pages, dashboards, or any web-based project.
description:
Automate end-to-end website creation with AI-powered optimization, design, and
testing. Trigger this skill whenever the user wants to create a new website,
build a landing page, design a web application, or automatically generate a
complete website from a description. This skill takes a user's website idea or
prompt, optimizes it for clarity, designs a modern responsive website, and
automatically tests it for quality issues. Use this skill for any "create a
website" or "build a web application" request, including landing pages,
portfolio sites, e-commerce pages, dashboards, or any web-based project.
compatibility:
models:
models:
- claude-sonnet-4-20250514 (design and testing)
- claude-haiku-4.5-20251001 (bug fixes)
required_skills:
@@ -13,44 +21,53 @@ compatibility:
# Website Creation Automation Skill
An intelligent, end-to-end automation workflow for creating complete, tested websites from simple prompts.
An intelligent, end-to-end automation workflow for creating complete, tested
websites from simple prompts.
## What This Skill Does
This skill orchestrates a complete website creation pipeline:
1. **Prompt Optimization** — Takes your website description and optimizes it into a detailed, structured prompt
2. **Website Design** — Uses the optimized prompt to design and build a modern, responsive website
3. **Automated Testing**Tests the generated website for visual, interactive, and responsive issues
1. **Prompt Optimization** — Takes your website description and optimizes it
into a detailed, structured prompt
2. **Website Design**Uses the optimized prompt to design and build a modern,
responsive website
3. **Automated Testing** — Tests the generated website for visual, interactive,
and responsive issues
4. **Auto-Fix** — Detects and fixes any issues found during testing
The entire workflow is automated, so you just provide a simple description of what you want, and the skill handles the rest.
The entire workflow is automated, so you just provide a simple description of
what you want, and the skill handles the rest.
## Core Workflow
### Step 1: Optimize Your Website Prompt
Your initial description (e.g., "Create a portfolio website for a freelance designer") is passed to the **prompt-optimizer** skill, which:
Your initial description (e.g., "Create a portfolio website for a freelance
designer") is passed to the **prompt-optimizer** skill, which:
- Adds specific details about layout, features, and target audience
- Clarifies design preferences and functionality requirements
- Structures the request to guide high-quality website generation
- Returns a detailed, optimized prompt ready for design
**Example transformation:**
```
Input: "Create a portfolio website for a freelance designer"
Output: "Create a modern portfolio website for a freelance graphic designer.
Include: hero section with featured work, project showcase grid (6-8 projects),
about section, services list, client testimonials, contact form, and footer.
Target audience: potential clients and collaborators. Design should be minimalist
with emphasis on visual work. Mobile-responsive. Use modern sans-serif typography
Output: "Create a modern portfolio website for a freelance graphic designer.
Include: hero section with featured work, project showcase grid (6-8 projects),
about section, services list, client testimonials, contact form, and footer.
Target audience: potential clients and collaborators. Design should be minimalist
with emphasis on visual work. Mobile-responsive. Use modern sans-serif typography
and white space. Include smooth scroll animations."
```
### Step 2: Design the Website
The **frontend-atomic-design** skill uses the optimized prompt to:
- Break down the website into atomic components (atoms, molecules, organisms)
- Create a responsive layout that works on desktop, tablet, and mobile
- Apply modern design patterns using Tailwind CSS
@@ -58,6 +75,7 @@ The **frontend-atomic-design** skill uses the optimized prompt to:
- Generate a complete, production-ready HTML file (or React component)
**Outputs:**
- Full HTML file with embedded CSS and JavaScript
- All assets (icons, fonts) are self-contained
- Responsive design with mobile-first approach
@@ -66,6 +84,7 @@ The **frontend-atomic-design** skill uses the optimized prompt to:
### Step 3: Test the Website
The **ui-ux-testing** skill performs comprehensive testing:
- Visual regression testing (captures baseline screenshots)
- Responsive layout validation (mobile, tablet, desktop)
- Interactive element testing (buttons, forms, links)
@@ -74,6 +93,7 @@ The **ui-ux-testing** skill performs comprehensive testing:
- User flow validation
**Testing output includes:**
- Screenshots from multiple viewport sizes
- Detailed findings and issues detected
- Visual regression comparison
@@ -82,12 +102,14 @@ The **ui-ux-testing** skill performs comprehensive testing:
### Step 4: Auto-Fix Detected Issues
Any issues detected in testing are automatically fixed:
- **Using Haiku 4.5** — A faster model optimized for targeted fixes
- **HTML-only fixes** — Modifications to structure, styling, or interactivity
- **Preserves design intent** — Fixes maintain the original design aesthetic
- **Re-validates** — Quick verification that fixes resolved the issues
**Common fixes include:**
- Correcting responsive behavior issues
- Fixing accessibility problems
- Adjusting spacing, alignment, or colors
@@ -111,23 +133,30 @@ Use this skill whenever you want to:
## How to Trigger This Skill
Simply provide:
1. **Website description** — What kind of website you want (e.g., "e-commerce store for handmade jewelry", "SaaS landing page", "restaurant menu website")
2. **Optional details** — Any specific requirements (colors, features, tone, audience)
1. **Website description** — What kind of website you want (e.g., "e-commerce
store for handmade jewelry", "SaaS landing page", "restaurant menu website")
2. **Optional details** — Any specific requirements (colors, features, tone,
audience)
The skill handles everything else automatically.
## Example Usage
**User prompt:** "Create a landing page for a sustainable fashion startup called EcoStitch. Include a hero section, features of our eco-friendly materials, pricing plans, customer testimonials, and a newsletter signup."
**User prompt:** "Create a landing page for a sustainable fashion startup called
EcoStitch. Include a hero section, features of our eco-friendly materials,
pricing plans, customer testimonials, and a newsletter signup."
**Skill processes:**
1. Optimizes prompt with specific design details and layout structure
2. Designs a modern, responsive landing page with all requested sections
3. Tests layout across mobile/tablet/desktop, forms, links, and visual design
4. Fixes any responsive or interactive issues found
5. Returns production-ready HTML file
**Final output:** A complete, tested, bug-free website ready to deploy or customize further.
**Final output:** A complete, tested, bug-free website ready to deploy or
customize further.
---
@@ -135,7 +164,8 @@ The skill handles everything else automatically.
### Model Usage
- **Sonnet 4.6** — Used for optimization, design, and testing (high-quality complex tasks)
- **Sonnet 4.6** — Used for optimization, design, and testing (high-quality
complex tasks)
- **Haiku 4.5** — Used for bug fixes only (fast, targeted improvements)
### Skill Integration
@@ -159,6 +189,7 @@ Final Website (Ready to Use)
### Output Format
The final website is delivered as:
- **HTML file** — Self-contained with CSS and JavaScript embedded
- **Screenshots** — Before/after testing comparison
- **Test report** — Issues found and fixes applied
@@ -168,20 +199,28 @@ The final website is delivered as:
## Limitations & Notes
- **Single-page output** — Generates one complete page (though can be expanded to multi-page)
- **Single-page output** — Generates one complete page (though can be expanded
to multi-page)
- **Static by default** — Returns HTML; can generate React components if needed
- **Database-free** — Forms are functional but don't store data without backend integration
- **Rapid iteration** — If you want to modify the result, you can iterate by running the skill again with updated requirements
- **Database-free** — Forms are functional but don't store data without backend
integration
- **Rapid iteration** — If you want to modify the result, you can iterate by
running the skill again with updated requirements
---
## Tips for Best Results
1. **Be descriptive** — More detail in your initial prompt leads to better results
2. **Specify audience** — Who is this website for? (target customers, users, etc.)
3. **Include features** — What should the website do? (e.g., showcase products, collect emails, etc.)
4. **Mention style** — Any aesthetic preferences? (minimalist, colorful, corporate, playful, etc.)
5. **Test thoroughly** — Review the testing results to ensure the site meets your needs
1. **Be descriptive** — More detail in your initial prompt leads to better
results
2. **Specify audience** — Who is this website for? (target customers, users,
etc.)
3. **Include features** — What should the website do? (e.g., showcase products,
collect emails, etc.)
4. **Mention style** — Any aesthetic preferences? (minimalist, colorful,
corporate, playful, etc.)
5. **Test thoroughly** — Review the testing results to ensure the site meets
your needs
---
@@ -216,6 +255,7 @@ COMPLETE: Return Website + Test Report
## Future Enhancements
Potential expansions to this skill:
- Multi-page website generation (homepage, about, services, contact, etc.)
- CMS integration (connect to content management systems)
- Backend API scaffolding (Node.js/Express templates)
+29 -23
View File
@@ -67,13 +67,15 @@ Dành cho khách hàng:
Dành cho quản lý:
- Sidebar desktop: Brand, tab navigation (Thực đơn / Combo / Danh mục), link tới Analytics
- Sidebar desktop: Brand, tab navigation (Thực đơn / Combo / Danh mục), link tới
Analytics
- CRUD sản phẩm, combo, danh mục qua modals
- Auth guard: tự động redirect non-manager về `/`
#### 9. **Trang Phân Tích Tài Chính** (`app/(manager)/manager/analytics`)
- Summary cards: Doanh thu, đơn hàng, lợi nhuận, giá trị đơn trung bình (so sánh kỳ trước)
- Summary cards: Doanh thu, đơn hàng, lợi nhuận, giá trị đơn trung bình (so sánh
kỳ trước)
- Bộ chọn kỳ: Ngày / Tuần / Tháng / Năm
- Biểu đồ SVG thuần: Line, Bar, Pie — hover tooltips tương tác
- Bảng top 5 sản phẩm và bảng chi tiết có thể sắp xếp
@@ -196,18 +198,18 @@ frondend/
## Công Nghệ Sử Dụng
| Công nghệ | Phiên bản | Mục đích |
| ------------ | --------- | ------------------------------------- |
| Next.js | 16.1.7 | React Framework (App Router) |
| React | 19.2.3 | Thư viện UI |
| TypeScript | ^5 | Kiểu dữ liệu tĩnh |
| Tailwind CSS | ^4.2.2 | Utility-first CSS framework |
| Geist Font | - | Font chữ (Google Fonts via next/font) |
| FontAwesome | 6.7.2 | Icon library (CDN) |
| pnpm | - | Package manager |
| ESLint | ^9 | Linting |
| Prettier | ^3 | Code formatting |
| semantic-release | ^25 | Automated versioning & release |
| Công nghệ | Phiên bản | Mục đích |
| ---------------- | --------- | ------------------------------------- |
| Next.js | 16.1.7 | React Framework (App Router) |
| React | 19.2.3 | Thư viện UI |
| TypeScript | ^5 | Kiểu dữ liệu tĩnh |
| Tailwind CSS | ^4.2.2 | Utility-first CSS framework |
| Geist Font | - | Font chữ (Google Fonts via next/font) |
| FontAwesome | 6.7.2 | Icon library (CDN) |
| pnpm | - | Package manager |
| ESLint | ^9 | Linting |
| Prettier | ^3 | Code formatting |
| semantic-release | ^25 | Automated versioning & release |
---
@@ -225,11 +227,11 @@ frondend/
### Tài Khoản Demo
| Loại tài khoản | Tên đăng nhập | Mật khẩu |
| -------------- | -------------- | -------------- |
| Manager | admin | admin |
| Staff | Nguyễn Văn An | Nguyễn Văn An |
| Customer | 0987654321 | user1 |
| Loại tài khoản | Tên đăng nhập | Mật khẩu |
| -------------- | ------------- | ------------- |
| Manager | admin | admin |
| Staff | Nguyễn Văn An | Nguyễn Văn An |
| Customer | 0987654321 | user1 |
### Design & Styling
@@ -243,14 +245,18 @@ frondend/
Dự án tuân theo **Atomic Design** pattern — chi tiết tại `Atomic.md`:
- **Atoms** - Nguyên tố cơ bản: Button, Input, Badge, Text, Heading, Divider
- **Molecules** - Nhóm atoms: ProductCard, ShopCard, SearchBar, PaymentSummaryCard
- **Organisms** - Phần UI phức tạp: CategorySidebar, CartFab, ProductGrid, ShopGrid, ReviewModal, analytics charts, manager tabs/modals
- **Templates** - Bố cục trang: MainLayout, AuthLayout, FeedLayout, ManagerLayout
- **Molecules** - Nhóm atoms: ProductCard, ShopCard, SearchBar,
PaymentSummaryCard
- **Organisms** - Phần UI phức tạp: CategorySidebar, CartFab, ProductGrid,
ShopGrid, ReviewModal, analytics charts, manager tabs/modals
- **Templates** - Bố cục trang: MainLayout, AuthLayout, FeedLayout,
ManagerLayout
### Data & Integration
- Mock data nằm trong `lib/constants.ts`
- Context providers trong `app/providers.tsx`: AuthProvider, MenuProvider, CartProvider
- Context providers trong `app/providers.tsx`: AuthProvider, MenuProvider,
CartProvider
- ManagerProvider được thêm bởi `app/(manager)/layout.tsx`
- Thay bằng API calls khi backend sẵn sàng
- Ảnh sản phẩm: thêm vào `public/imgs/products/`
+2 -2
View File
@@ -1,7 +1,7 @@
"use client";
import { SHOP_INFO } from "@/lib/constants";
import LoginForm from "@/components/organisms/forms/LoginForm";
import { SHOP_INFO } from "@/lib/constants";
import Image from "next/image";
export default function LoginPage() {
@@ -28,7 +28,7 @@ export default function LoginPage() {
Đăng nhập vào hệ thống
</p>
</div>
{/* Login Form */}
<LoginForm />
+3 -6
View File
@@ -1,10 +1,10 @@
"use client";
import { SearchBar } from "@/components/molecules/search-bar";
import { CategorySidebar } from "@/components/organisms/navigation";
import { ProductGrid } from "@/components/organisms/product-grid";
import { SearchBar } from "@/components/molecules/search-bar";
import { useMenu } from "@/lib/menu-context";
import { MENU_CATEGORIES } from "@/lib/constants";
import { useMenu } from "@/lib/menu-context";
import { useEffect, useState } from "react";
/**
@@ -75,10 +75,7 @@ export default function Home() {
</div>
{/* ── Product grid (organism handles mobile category menu + grid) ── */}
<ProductGrid
searchQuery={searchQuery}
isSidebarOpen={isSidebarOpen}
/>
<ProductGrid searchQuery={searchQuery} isSidebarOpen={isSidebarOpen} />
</main>
</div>
);
+15 -6
View File
@@ -48,10 +48,19 @@ export default function PaymentPage() {
<th scope="col" className="px-4 py-3 font-semibold">
Tên sản phẩm
</th>
<th scope="col" className="px-4 py-3 font-semibold">Giá tiền</th>
<th scope="col" className="px-4 py-3 font-semibold"> tả</th>
<th scope="col" className="px-4 py-3 font-semibold">Số lượng</th>
<th scope="col" className="px-4 py-3 text-right font-semibold">
<th scope="col" className="px-4 py-3 font-semibold">
Giá tiền
</th>
<th scope="col" className="px-4 py-3 font-semibold">
tả
</th>
<th scope="col" className="px-4 py-3 font-semibold">
Số lượng
</th>
<th
scope="col"
className="px-4 py-3 text-right font-semibold"
>
Xóa
</th>
</tr>
@@ -75,7 +84,7 @@ export default function PaymentPage() {
<div className="flex items-center gap-2">
<button
onClick={() => decreaseQty(item.id)}
className="inline-flex items-center justify-center h-8 w-8 rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
aria-label={`Giảm số lượng ${item.name}`}
>
-
@@ -92,7 +101,7 @@ export default function PaymentPage() {
/>
<button
onClick={() => increaseQty(item.id)}
className="inline-flex items-center justify-center h-8 w-8 rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
aria-label={`Tăng số lượng ${item.name}`}
>
+
+42 -25
View File
@@ -1,7 +1,7 @@
# Components Documentation
> This project follows **Atomic Design** pattern.
> See `Atomic.md` at project root for full structure guide.
> This project follows **Atomic Design** pattern. See `Atomic.md` at project
> root for full structure guide.
## Directory Structure
@@ -19,17 +19,21 @@ components/
### ProductCard (`molecules/cards/ProductCard.tsx`)
**Description:** Product card molecule. Displays product image, name, description, formatted price, and a Buy button. Width is controlled by the parent grid (w-full).
**Description:** Product card molecule. Displays product image, name,
description, formatted price, and a Buy button. Width is controlled by the
parent grid (w-full).
**Atomic level:** Molecule (composed of Button, Caption, Text atoms)
### ShopCard (`molecules/cards/ShopCard.tsx`)
**Description:** Shop discovery card. Displays shop image, name, address, and a link to the menu.
**Description:** Shop discovery card. Displays shop image, name, address, and a
link to the menu.
### SearchBar (`molecules/search-bar/SearchBar.tsx`)
**Description:** Search input with clear button. Controlled component — value and onChange come from parent.
**Description:** Search input with clear button. Controlled component — value
and onChange come from parent.
---
@@ -37,35 +41,41 @@ components/
### CategorySidebar (`organisms/navigation/CategorySidebar.tsx`)
**Description:** Left sidebar with collapsible category filter. Sticky below header, full viewport height minus header.
**Description:** Left sidebar with collapsible category filter. Sticky below
header, full viewport height minus header.
### CartFab (`organisms/cart/CartFab.tsx`)
**Description:** Floating Action Button displaying cart item count. Links to /payment page.
**Description:** Floating Action Button displaying cart item count. Links to
/payment page.
### ProductGrid (`organisms/product-grid/ProductGrid.tsx`)
**Description:** Full product grid organism with mobile category tabs, filtering, and empty state. Uses useCart and useMenu contexts.
**Description:** Full product grid organism with mobile category tabs,
filtering, and empty state. Uses useCart and useMenu contexts.
### ShopGrid (`organisms/shop-grid/ShopGrid.tsx`)
**Description:** Responsive grid of ShopCard molecules for the feed/discovery page.
**Description:** Responsive grid of ShopCard molecules for the feed/discovery
page.
### ReviewModal (`organisms/modals/ReviewModal.tsx`)
**Description:** Modal for customer reviews. Shows 5-star rating and textarea. After submission, displays thank-you message.
**Description:** Modal for customer reviews. Shows 5-star rating and textarea.
After submission, displays thank-you message.
### Analytics Charts (`organisms/analytics/`)
**Description:** Pure-SVG chart and table components for the Financial Analytics dashboard. All components are interactive with hover tooltips.
**Description:** Pure-SVG chart and table components for the Financial Analytics
dashboard. All components are interactive with hover tooltips.
| Component | File | Description |
|-----------|------|-------------|
| LineChart | LineChart.tsx | Revenue trend line chart with area fill and hover tooltips |
| BarChart | BarChart.tsx | Grouped bar chart comparing current vs previous period |
| PieChart | PieChart.tsx | Pie chart with interactive legend for category breakdown |
| SummaryCard | SummaryCard.tsx | Metric card with period-over-period comparison indicator |
| ProductTable | ProductTable.tsx | Sortable product sales table with profit margin badges |
| Component | File | Description |
| ------------ | ---------------- | ---------------------------------------------------------- |
| LineChart | LineChart.tsx | Revenue trend line chart with area fill and hover tooltips |
| BarChart | BarChart.tsx | Grouped bar chart comparing current vs previous period |
| PieChart | PieChart.tsx | Pie chart with interactive legend for category breakdown |
| SummaryCard | SummaryCard.tsx | Metric card with period-over-period comparison indicator |
| ProductTable | ProductTable.tsx | Sortable product sales table with profit margin badges |
**Usage:** Imported via `@/components/organisms/analytics` barrel index.
@@ -75,11 +85,13 @@ components/
### MainLayout (`templates/main-layout/MainLayout.tsx`)
**Description:** Main layout template — wraps content with Header, Footer, and CartFab. Used by (main) route group.
**Description:** Main layout template — wraps content with Header, Footer, and
CartFab. Used by (main) route group.
### AuthLayout (`templates/auth-layout/AuthLayout.tsx`)
**Description:** Auth layout template — centers content in screen. Used by login/register pages.
**Description:** Auth layout template — centers content in screen. Used by
login/register pages.
### FeedLayout (`templates/feed-layout/FeedLayout.tsx`)
@@ -87,7 +99,8 @@ components/
### ManagerLayout (`templates/manager-layout/ManagerLayout.tsx`)
**Description:** Manager layout template — auth guard + ManagerProvider. Used by the manager route group.
**Description:** Manager layout template — auth guard + ManagerProvider. Used by
the manager route group.
---
@@ -95,16 +108,20 @@ components/
### AuthContext (`lib/auth-context.tsx`)
Manages user authentication state including login, logout, and registration. Uses localStorage for persistence.
Manages user authentication state including login, logout, and registration.
Uses localStorage for persistence.
### CartContext (`lib/cart-context.tsx`)
Manages shopping cart state with localStorage persistence. Tracks items, quantities, and totals.
Manages shopping cart state with localStorage persistence. Tracks items,
quantities, and totals.
### MenuContext (`lib/menu-context.tsx`)
Provides shared activeCategory state across components. Synchronizes Header mobile menu and CategorySidebar selection.
Provides shared activeCategory state across components. Synchronizes Header
mobile menu and CategorySidebar selection.
### ManagerContext (`lib/manager-context.tsx`)
Manages menu CRUD state (products, combos, categories) for the manager dashboard.
Manages menu CRUD state (products, combos, categories) for the manager
dashboard.
+19
View File
@@ -42,6 +42,7 @@ Main interactive button component with multiple variants and sizes.
- All standard HTML button attributes
**Usage:**
```tsx
import { Button } from "@/components/atoms";
@@ -59,6 +60,7 @@ import { Button } from "@/components/atoms";
```
**Styling:**
- Primary: Branded color with dark hover
- Secondary: Border style with light background on hover
- Danger: Red for destructive actions
@@ -78,6 +80,7 @@ Button designed specifically for icon-only interactions.
- All standard HTML button attributes
**Usage:**
```tsx
import { IconButton } from "@/components/atoms";
@@ -102,6 +105,7 @@ General text input field with optional label, error, and icon.
- All standard HTML input attributes
**Usage:**
```tsx
import { TextInput } from "@/components/atoms";
@@ -135,6 +139,7 @@ Search input with built-in search icon and clear button.
- All standard HTML input attributes
**Usage:**
```tsx
import { SearchInput } from "@/components/atoms";
@@ -161,6 +166,7 @@ Multi-line text input with optional label and error.
- All standard HTML textarea attributes
**Usage:**
```tsx
import { Textarea } from "@/components/atoms";
@@ -188,6 +194,7 @@ Semantic heading component with level-based sizing.
- All standard HTML heading attributes
**Sizing:**
- Level 1: text-3xl font-bold
- Level 2: text-2xl font-bold
- Level 3: text-xl font-bold
@@ -196,6 +203,7 @@ Semantic heading component with level-based sizing.
- Level 6: text-sm font-semibold
**Usage:**
```tsx
import { Heading } from "@/components/atoms";
@@ -217,12 +225,14 @@ Paragraph text with semantic variants.
- All standard HTML paragraph attributes
**Variants:**
- body1: text-base (main content)
- body2: text-sm (secondary content)
- caption: text-xs (smallest text)
- label: text-sm font-medium (form labels)
**Usage:**
```tsx
import { Text } from "@/components/atoms";
@@ -244,6 +254,7 @@ Small caption/note text component.
- All standard HTML span attributes
**Usage:**
```tsx
import { Caption } from "@/components/atoms";
@@ -268,6 +279,7 @@ Labeled badge component for highlighting information.
- All standard HTML span attributes
**Variants:**
- primary: Branded color
- secondary: Light gray
- success: Green
@@ -275,6 +287,7 @@ Labeled badge component for highlighting information.
- warning: Yellow
**Usage:**
```tsx
import { Badge } from "@/components/atoms";
@@ -296,6 +309,7 @@ Specialized badge for displaying formatted prices.
- All standard HTML span attributes
**Usage:**
```tsx
import { PriceBadge } from "@/components/atoms";
@@ -304,6 +318,7 @@ import { PriceBadge } from "@/components/atoms";
```
**Output:**
- VND: "50.000 ₫"
- USD: "$99.99"
@@ -321,6 +336,7 @@ Visual separator element.
- All standard HTML hr attributes
**Usage:**
```tsx
import { Divider } from "@/components/atoms";
@@ -414,6 +430,7 @@ import type {
```
### Product Card
```tsx
<div className="rounded-lg border p-4">
<Heading level={3}>Product Name</Heading>
@@ -426,6 +443,7 @@ import type {
```
### Rating Display
```tsx
<div>
<Heading level={4}>Reviews</Heading>
@@ -439,6 +457,7 @@ import type {
## 🧪 Testing Atoms
### Props Validation
```tsx
// ✅ Valid
<Button variant="primary" size="sm">Click</Button>
@@ -13,14 +13,13 @@ export default function PaymentSummaryCard({
isCustomer = false,
backHref,
}: PaymentSummaryCardProps) {
const [isReviewOpen, setIsReviewOpen] = useState(false);
const handlePayment = () => {
const [isReviewOpen, setIsReviewOpen] = useState(false);
const handlePayment = () => {
// UI-only: open review modal after "payment"
if (isCustomer) {
setIsReviewOpen(true);
}
};
setIsReviewOpen(true);
}
};
return (
<aside className="shrink-0 xl:w-85">
<div className="bg-card sticky top-[calc(var(--spacing-header-height)+1rem)] rounded-2xl border border-(--color-border-light) p-4 md:p-5">
+7 -1
View File
@@ -62,7 +62,13 @@ export default function ProductCard({
<Text variant="body2" className="font-bold">
{formattedPrice}
</Text>
<Button onClick={onBuy} variant="primary" size="sm" icon="fa-cart-plus" aria-label={`Mua ${productName}`}>
<Button
onClick={onBuy}
variant="primary"
size="sm"
icon="fa-cart-plus"
aria-label={`Mua ${productName}`}
>
Mua
</Button>
</div>
+8 -2
View File
@@ -16,10 +16,16 @@ interface BarChartProps {
* Tooltip auto-flips above/below bar top to stay inside the viewBox.
*/
export function BarChart({ current, previous, height = 200 }: BarChartProps) {
const [hovered, setHovered] = useState<{ set: "cur" | "prev"; idx: number } | null>(null);
const [hovered, setHovered] = useState<{
set: "cur" | "prev";
idx: number;
} | null>(null);
const W = 800;
const H = height;
const padL = 56, padR = 16, padT = 16, padB = 40;
const padL = 56,
padR = 16,
padT = 16,
padB = 40;
const chartW = W - padL - padR;
const chartH = H - padT - padB;
+100 -22
View File
@@ -18,7 +18,10 @@ export function LineChart({ data, height = 200 }: LineChartProps) {
const [hovered, setHovered] = useState<number | null>(null);
const W = 800;
const H = height;
const padL = 56, padR = 16, padT = 16, padB = 40;
const padL = 56,
padR = 16,
padT = 16,
padB = 40;
const chartW = W - padL - padR;
const chartH = H - padT - padB;
@@ -66,47 +69,122 @@ export function LineChart({ data, height = 200 }: LineChartProps) {
{gridLines.map((g, i) => (
<g key={i}>
<line x1={padL} y1={g.y} x2={W - padR} y2={g.y} stroke="#E2C9A8" strokeWidth="1" strokeDasharray={i === yTicks ? "0" : "4 3"} />
<text x={padL - 6} y={g.y + 4} textAnchor="end" fontSize="10" fill="#A08060">{formatCurrency(g.val)}</text>
<line
x1={padL}
y1={g.y}
x2={W - padR}
y2={g.y}
stroke="#E2C9A8"
strokeWidth="1"
strokeDasharray={i === yTicks ? "0" : "4 3"}
/>
<text
x={padL - 6}
y={g.y + 4}
textAnchor="end"
fontSize="10"
fill="#A08060"
>
{formatCurrency(g.val)}
</text>
</g>
))}
<path d={areaD} fill="url(#areaGrad)" />
<path d={pathD} fill="none" stroke="#6F4E37" strokeWidth="2.5" strokeLinejoin="round" strokeLinecap="round" />
<path
d={pathD}
fill="none"
stroke="#6F4E37"
strokeWidth="2.5"
strokeLinejoin="round"
strokeLinecap="round"
/>
{points.map((p, i) =>
i % step === 0 ? (
<text key={i} x={p.x} y={H - 8} textAnchor="middle" fontSize="10" fill="#A08060">{p.data.label}</text>
<text
key={i}
x={p.x}
y={H - 8}
textAnchor="middle"
fontSize="10"
fill="#A08060"
>
{p.data.label}
</text>
) : null,
)}
{points.map((p) => (
<circle
key={p.index}
cx={p.x} cy={p.y}
cx={p.x}
cy={p.y}
r={hovered === p.index ? 5 : 3}
fill={hovered === p.index ? "#C8973A" : "#6F4E37"}
stroke="#FDF6EC" strokeWidth="2"
stroke="#FDF6EC"
strokeWidth="2"
style={{ cursor: "pointer", transition: "r 150ms" }}
onMouseEnter={() => setHovered(p.index)}
/>
))}
{hovered !== null && (() => {
const p = points[hovered];
const tipW = 120, tipH = 48;
const tipX = Math.min(Math.max(p.x - tipW / 2, padL), W - padR - tipW);
const aboveY = p.y - tipH - 10;
const tipY = Math.min(Math.max(aboveY >= padT ? aboveY : p.y + 10, padT), padT + chartH - tipH);
return (
<g>
<rect x={tipX} y={tipY} width={tipW} height={tipH} rx="6" fill="#3D2B1F" opacity="0.92" />
<text x={tipX + tipW / 2} y={tipY + 16} textAnchor="middle" fontSize="10" fill="#F0D9A8">{p.data.label}</text>
<text x={tipX + tipW / 2} y={tipY + 30} textAnchor="middle" fontSize="11" fontWeight="600" fill="#C8973A">{formatCurrency(p.data.revenue)}</text>
<text x={tipX + tipW / 2} y={tipY + 44} textAnchor="middle" fontSize="10" fill="#A08060">{p.data.orders} đơn</text>
</g>
);
})()}
{hovered !== null &&
(() => {
const p = points[hovered];
const tipW = 120,
tipH = 48;
const tipX = Math.min(
Math.max(p.x - tipW / 2, padL),
W - padR - tipW,
);
const aboveY = p.y - tipH - 10;
const tipY = Math.min(
Math.max(aboveY >= padT ? aboveY : p.y + 10, padT),
padT + chartH - tipH,
);
return (
<g>
<rect
x={tipX}
y={tipY}
width={tipW}
height={tipH}
rx="6"
fill="#3D2B1F"
opacity="0.92"
/>
<text
x={tipX + tipW / 2}
y={tipY + 16}
textAnchor="middle"
fontSize="10"
fill="#F0D9A8"
>
{p.data.label}
</text>
<text
x={tipX + tipW / 2}
y={tipY + 30}
textAnchor="middle"
fontSize="11"
fontWeight="600"
fill="#C8973A"
>
{formatCurrency(p.data.revenue)}
</text>
<text
x={tipX + tipW / 2}
y={tipY + 44}
textAnchor="middle"
fontSize="10"
fill="#A08060"
>
{p.data.orders} đơn
</text>
</g>
);
})()}
</svg>
</div>
);
+1 -1
View File
@@ -1,6 +1,6 @@
"use client";
import { useState, useMemo } from "react";
import { useMemo, useState } from "react";
export interface PieSlice {
label: string;
+1 -1
View File
@@ -1,10 +1,10 @@
import Button from "@/components/atoms/buttons/Button";
import ErrorMessageLogin from "@/components/atoms/errors/ErrorMessageLogin";
import LoginInput from "@/components/atoms/inputs/LoginInput";
import { useAuth } from "@/lib/auth-context";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { FormEvent, useState } from "react";
import Button from "@/components/atoms/buttons/Button";
export default function LoginForm() {
const router = useRouter();
+4 -1
View File
@@ -152,7 +152,10 @@ export default function ProductsTab() {
</tr>
) : (
filtered.map((p) => (
<tr key={p.id} className="hover:bg-background transition-colors">
<tr
key={p.id}
className="hover:bg-background transition-colors"
>
<td className="px-4 py-3">
<div>
<p className="text-foreground font-medium">{p.name}</p>