chore: release [ci skip]
This commit is contained in:
@@ -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"
|
||||
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,14 +311,15 @@ 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 (
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -376,17 +374,11 @@ Use this template when building atomic components:
|
||||
* - 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>
|
||||
@@ -453,7 +449,7 @@ export const ComponentName = ({ prop1, prop2, className = '' }) => {
|
||||
|
||||
```jsx
|
||||
<button
|
||||
className="px-4 py-3 min-h-[44px] focus:outline-none focus:ring-2 focus:ring-offset-2"
|
||||
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)
|
||||
|
||||
|
||||
@@ -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 ✓
|
||||
|
||||
@@ -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,21 +210,24 @@ 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] |
|
||||
|
||||
## 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,6 +1,14 @@
|
||||
---
|
||||
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:
|
||||
- claude-sonnet-4-20250514 (design and testing)
|
||||
@@ -13,30 +21,38 @@ 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"
|
||||
↓
|
||||
@@ -51,6 +67,7 @@ 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)
|
||||
|
||||
@@ -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
|
||||
@@ -197,7 +199,7 @@ 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 |
|
||||
@@ -226,7 +228,7 @@ 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 |
|
||||
@@ -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/`
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+3
-6
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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">Mô 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">
|
||||
Mô 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}`}
|
||||
>
|
||||
+
|
||||
|
||||
+36
-19
@@ -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,30 +41,36 @@ 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 |
|
||||
@@ -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.
|
||||
|
||||
@@ -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,7 +13,6 @@ export default function PaymentSummaryCard({
|
||||
isCustomer = false,
|
||||
backHref,
|
||||
}: PaymentSummaryCardProps) {
|
||||
|
||||
const [isReviewOpen, setIsReviewOpen] = useState(false);
|
||||
const handlePayment = () => {
|
||||
// UI-only: open review modal after "payment"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,44 +69,119 @@ 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 && (() => {
|
||||
{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 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);
|
||||
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>
|
||||
<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>
|
||||
);
|
||||
})()}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
export interface PieSlice {
|
||||
label: string;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -16,7 +16,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend-container
|
||||
image: git.demonkernel.io.vn/foodsurf/frontend:1.1.2
|
||||
image: git.demonkernel.io.vn/foodsurf/frontend:1.2.0
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
resources:
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "temp",
|
||||
"version": "1.1.2",
|
||||
"version": "1.2.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "temp",
|
||||
"version": "1.1.2",
|
||||
"version": "1.2.0",
|
||||
"dependencies": {
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
"@types/node": "^20.19.37",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "temp",
|
||||
"version": "1.1.2",
|
||||
"version": "1.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-config-next": "16.1.7",
|
||||
"prettier": "^3.8.2",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-embed": "^0.5.1",
|
||||
"prettier-plugin-groovy": "^0.2.1",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
|
||||
Generated
+64
-55
@@ -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)
|
||||
nextjs:
|
||||
specifier: ^0.0.3
|
||||
version: 0.0.3
|
||||
react:
|
||||
specifier: 19.2.3
|
||||
version: 19.2.3
|
||||
@@ -47,7 +50,7 @@ importers:
|
||||
version: 13.1.5(semantic-release@25.0.3(typescript@5.9.3))
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
specifier: ^6.0.2
|
||||
version: 6.0.2(prettier@3.8.2)
|
||||
version: 6.0.2(prettier@3.8.3)
|
||||
'@types/react-dom':
|
||||
specifier: ^19.2.3
|
||||
version: 19.2.3(@types/react@19.2.14)
|
||||
@@ -58,17 +61,17 @@ importers:
|
||||
specifier: 16.1.7
|
||||
version: 16.1.7(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
|
||||
prettier:
|
||||
specifier: ^3.8.2
|
||||
version: 3.8.2
|
||||
specifier: ^3.8.3
|
||||
version: 3.8.3
|
||||
prettier-plugin-embed:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
prettier-plugin-groovy:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1(prettier@3.8.2)
|
||||
version: 0.2.1(prettier@3.8.3)
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.7.2
|
||||
version: 0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.2))(prettier@3.8.2)
|
||||
version: 0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3))(prettier@3.8.3)
|
||||
semantic-release:
|
||||
specifier: ^25.0.3
|
||||
version: 25.0.3(typescript@5.9.3)
|
||||
@@ -171,11 +174,11 @@ packages:
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
||||
'@emnapi/core@1.9.2':
|
||||
resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==}
|
||||
'@emnapi/core@1.10.0':
|
||||
resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
|
||||
|
||||
'@emnapi/runtime@1.9.2':
|
||||
resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==}
|
||||
'@emnapi/runtime@1.10.0':
|
||||
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
||||
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||
@@ -1092,8 +1095,8 @@ packages:
|
||||
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
baseline-browser-mapping@2.10.18:
|
||||
resolution: {integrity: sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==}
|
||||
baseline-browser-mapping@2.10.19:
|
||||
resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1171,8 +1174,8 @@ packages:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-lite@1.0.30001787:
|
||||
resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==}
|
||||
caniuse-lite@1.0.30001788:
|
||||
resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==}
|
||||
|
||||
chalk@2.4.1:
|
||||
resolution: {integrity: sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==}
|
||||
@@ -1463,8 +1466,8 @@ packages:
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
electron-to-chromium@1.5.336:
|
||||
resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==}
|
||||
electron-to-chromium@1.5.340:
|
||||
resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==}
|
||||
|
||||
emoji-regex@10.6.0:
|
||||
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
||||
@@ -1620,11 +1623,11 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
|
||||
|
||||
eslint-plugin-react-hooks@7.0.1:
|
||||
resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==}
|
||||
eslint-plugin-react-hooks@7.1.0:
|
||||
resolution: {integrity: sha512-LDicyhrRFrIaheDYryeM2W8gWyZXnAs4zIr2WVPiOSeTmIu2RjR4x/9N0xLaRWZ+9hssBDGo3AadcohuzAvSvg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
|
||||
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0
|
||||
|
||||
eslint-plugin-react@7.37.5:
|
||||
resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
|
||||
@@ -1889,8 +1892,8 @@ packages:
|
||||
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-tsconfig@4.13.7:
|
||||
resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==}
|
||||
get-tsconfig@4.14.0:
|
||||
resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==}
|
||||
|
||||
git-log-parser@1.2.1:
|
||||
resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==}
|
||||
@@ -2649,6 +2652,10 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
|
||||
nextjs@0.0.3:
|
||||
resolution: {integrity: sha512-mYbDUo4/sRAZ8TqK63PCpYnFiLg7BICG/ot9+guOrUKd4/Fo71ZmEQ41IZbH6nqbQvG7SXTBuofJXAIWfNho0w==}
|
||||
engines: {node: '>=0.8.21'}
|
||||
|
||||
nocache@2.0.0:
|
||||
resolution: {integrity: sha512-YdKcy2x0dDwOh+8BEuHvA+mnOKAhmMQDgKBOCUGaLpewdmsRYguYZSom3yA+/OrE61O/q+NMQANnun65xpI1Hw==}
|
||||
|
||||
@@ -2992,8 +2999,8 @@ packages:
|
||||
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postcss@8.5.9:
|
||||
resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==}
|
||||
postcss@8.5.10:
|
||||
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
prelude-ls@1.2.1:
|
||||
@@ -3064,8 +3071,8 @@ packages:
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.8.2:
|
||||
resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==}
|
||||
prettier@3.8.3:
|
||||
resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3634,8 +3641,8 @@ packages:
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici@6.24.1:
|
||||
resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==}
|
||||
undici@6.25.0:
|
||||
resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==}
|
||||
engines: {node: '>=18.17'}
|
||||
|
||||
undici@7.25.0:
|
||||
@@ -3845,7 +3852,7 @@ snapshots:
|
||||
'@actions/http-client@4.0.0':
|
||||
dependencies:
|
||||
tunnel: 0.0.6
|
||||
undici: 6.24.1
|
||||
undici: 6.25.0
|
||||
|
||||
'@actions/io@3.0.2': {}
|
||||
|
||||
@@ -3966,13 +3973,13 @@ snapshots:
|
||||
'@colors/colors@1.5.0':
|
||||
optional: true
|
||||
|
||||
'@emnapi/core@1.9.2':
|
||||
'@emnapi/core@1.10.0':
|
||||
dependencies:
|
||||
'@emnapi/wasi-threads': 1.2.1
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/runtime@1.9.2':
|
||||
'@emnapi/runtime@1.10.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
@@ -4124,7 +4131,7 @@ snapshots:
|
||||
|
||||
'@img/sharp-wasm32@0.34.5':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.9.2
|
||||
'@emnapi/runtime': 1.10.0
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-arm64@0.34.5':
|
||||
@@ -4157,8 +4164,8 @@ snapshots:
|
||||
|
||||
'@napi-rs/wasm-runtime@0.2.12':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.9.2
|
||||
'@emnapi/runtime': 1.9.2
|
||||
'@emnapi/core': 1.10.0
|
||||
'@emnapi/runtime': 1.10.0
|
||||
'@tybys/wasm-util': 0.10.1
|
||||
optional: true
|
||||
|
||||
@@ -4468,10 +4475,10 @@ snapshots:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.2.2
|
||||
'@tailwindcss/oxide': 4.2.2
|
||||
postcss: 8.5.9
|
||||
postcss: 8.5.10
|
||||
tailwindcss: 4.2.2
|
||||
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.2)':
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.29.1
|
||||
'@babel/parser': 7.29.2
|
||||
@@ -4481,7 +4488,7 @@ snapshots:
|
||||
lodash-es: 4.18.1
|
||||
minimatch: 9.0.9
|
||||
parse-imports-exports: 0.2.4
|
||||
prettier: 3.8.2
|
||||
prettier: 3.8.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -4874,7 +4881,7 @@ snapshots:
|
||||
|
||||
balanced-match@4.0.4: {}
|
||||
|
||||
baseline-browser-mapping@2.10.18: {}
|
||||
baseline-browser-mapping@2.10.19: {}
|
||||
|
||||
basic-auth@2.0.1:
|
||||
dependencies:
|
||||
@@ -4924,9 +4931,9 @@ snapshots:
|
||||
|
||||
browserslist@4.28.2:
|
||||
dependencies:
|
||||
baseline-browser-mapping: 2.10.18
|
||||
caniuse-lite: 1.0.30001787
|
||||
electron-to-chromium: 1.5.336
|
||||
baseline-browser-mapping: 2.10.19
|
||||
caniuse-lite: 1.0.30001788
|
||||
electron-to-chromium: 1.5.340
|
||||
node-releases: 2.0.37
|
||||
update-browserslist-db: 1.2.3(browserslist@4.28.2)
|
||||
|
||||
@@ -4970,7 +4977,7 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
caniuse-lite@1.0.30001787: {}
|
||||
caniuse-lite@1.0.30001788: {}
|
||||
|
||||
chalk@2.4.1:
|
||||
dependencies:
|
||||
@@ -5255,7 +5262,7 @@ snapshots:
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
electron-to-chromium@1.5.336: {}
|
||||
electron-to-chromium@1.5.340: {}
|
||||
|
||||
emoji-regex@10.6.0: {}
|
||||
|
||||
@@ -5411,7 +5418,7 @@ snapshots:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1))
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1))
|
||||
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1))
|
||||
eslint-plugin-react-hooks: 7.1.0(eslint@9.39.4(jiti@2.6.1))
|
||||
globals: 16.4.0
|
||||
typescript-eslint: 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
@@ -5435,7 +5442,7 @@ snapshots:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
eslint: 9.39.4(jiti@2.6.1)
|
||||
get-tsconfig: 4.13.7
|
||||
get-tsconfig: 4.14.0
|
||||
is-bun-module: 2.0.0
|
||||
stable-hash: 0.0.5
|
||||
tinyglobby: 0.2.16
|
||||
@@ -5504,7 +5511,7 @@ snapshots:
|
||||
safe-regex-test: 1.1.0
|
||||
string.prototype.includes: 2.0.1
|
||||
|
||||
eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@2.6.1)):
|
||||
eslint-plugin-react-hooks@7.1.0(eslint@9.39.4(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/parser': 7.29.2
|
||||
@@ -5882,7 +5889,7 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
get-tsconfig@4.13.7:
|
||||
get-tsconfig@4.14.0:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
@@ -6579,8 +6586,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@next/env': 16.1.7
|
||||
'@swc/helpers': 0.5.15
|
||||
baseline-browser-mapping: 2.10.18
|
||||
caniuse-lite: 1.0.30001787
|
||||
baseline-browser-mapping: 2.10.19
|
||||
caniuse-lite: 1.0.30001788
|
||||
postcss: 8.4.31
|
||||
react: 19.2.3
|
||||
react-dom: 19.2.3(react@19.2.3)
|
||||
@@ -6599,6 +6606,8 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
nextjs@0.0.3: {}
|
||||
|
||||
nocache@2.0.0: {}
|
||||
|
||||
node-emoji@2.2.0:
|
||||
@@ -6862,7 +6871,7 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
postcss@8.5.9:
|
||||
postcss@8.5.10:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
@@ -6881,17 +6890,17 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
|
||||
prettier-plugin-groovy@0.2.1(prettier@3.8.2):
|
||||
prettier-plugin-groovy@0.2.1(prettier@3.8.3):
|
||||
dependencies:
|
||||
prettier: 3.8.2
|
||||
prettier: 3.8.3
|
||||
|
||||
prettier-plugin-tailwindcss@0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.2))(prettier@3.8.2):
|
||||
prettier-plugin-tailwindcss@0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3))(prettier@3.8.3):
|
||||
dependencies:
|
||||
prettier: 3.8.2
|
||||
prettier: 3.8.3
|
||||
optionalDependencies:
|
||||
'@trivago/prettier-plugin-sort-imports': 6.0.2(prettier@3.8.2)
|
||||
'@trivago/prettier-plugin-sort-imports': 6.0.2(prettier@3.8.3)
|
||||
|
||||
prettier@3.8.2: {}
|
||||
prettier@3.8.3: {}
|
||||
|
||||
pretty-ms@9.3.0:
|
||||
dependencies:
|
||||
@@ -7617,7 +7626,7 @@ snapshots:
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici@6.24.1: {}
|
||||
undici@6.25.0: {}
|
||||
|
||||
undici@7.25.0: {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user