201 lines
6.9 KiB
Markdown
201 lines
6.9 KiB
Markdown
# Vanilla CSS & CSS Modules Style Guide
|
|
|
|
**Variable Remuneration, Compensation, and Commissions System - Hoteles Estelar**
|
|
|
|
---
|
|
|
|
This document outlines the strict guidelines for styling the application using **Vanilla CSS** and **CSS Modules**. By sticking to these guidelines, we ensure absolute isolation of component styles, prevent class name collisions, maintain a centralized token system, and support robust theme modifications (light/dark mode).
|
|
|
|
---
|
|
|
|
## 1. Centralized Design Tokens (`globals.css`)
|
|
|
|
All colors, spacing, typography, transitions, and layout presets must be defined as CSS custom properties (variables) inside `src/app/globals.css`. Global variables are declared in HSL (Hue, Saturation, Lightness) format to allow dynamic opacity control using `alpha-value` mixing.
|
|
|
|
```css
|
|
:root {
|
|
/* Color Palette - HSL values for premium dark/light mode */
|
|
--primary-h: 220;
|
|
--primary-s: 85%;
|
|
--primary-l: 57%;
|
|
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
|
|
|
--secondary-h: 260;
|
|
--secondary-s: 70%;
|
|
--secondary-l: 50%;
|
|
--secondary: hsl(var(--secondary-h), var(--secondary-s), var(--secondary-l));
|
|
|
|
--background-h: 0;
|
|
--background-s: 0%;
|
|
--background-l: 100%;
|
|
--background: hsl(var(--background-h), var(--background-s), var(--background-l));
|
|
|
|
--foreground-h: 220;
|
|
--foreground-s: 40%;
|
|
--foreground-l: 10%;
|
|
--foreground: hsl(var(--foreground-h), var(--foreground-s), var(--foreground-l));
|
|
|
|
--card: hsl(0, 0%, 97%);
|
|
--border: hsl(220, 20%, 90%);
|
|
|
|
/* Spacing Grid (8pt Grid System) */
|
|
--space-1: 0.25rem; /* 4px */
|
|
--space-2: 0.5rem; /* 8px */
|
|
--space-3: 0.75rem; /* 12px */
|
|
--space-4: 1rem; /* 16px */
|
|
--space-6: 1.5rem; /* 24px */
|
|
--space-8: 2rem; /* 32px */
|
|
--space-12: 3rem; /* 48px */
|
|
|
|
/* Typography Scale */
|
|
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
|
|
--text-xs: 0.75rem;
|
|
--text-sm: 0.875rem;
|
|
--text-base: 1rem;
|
|
--text-lg: 1.125rem;
|
|
--text-xl: 1.25rem;
|
|
--text-2xl: 1.5rem;
|
|
--text-3xl: 1.875rem;
|
|
--text-4xl: 2.25rem;
|
|
|
|
--weight-normal: 400;
|
|
--weight-medium: 500;
|
|
--weight-semibold: 600;
|
|
--weight-bold: 700;
|
|
|
|
/* Border Radius & Shadow Tokens */
|
|
--radius-sm: 0.375rem;
|
|
--radius-md: 0.5rem;
|
|
--radius-lg: 0.75rem;
|
|
--radius-xl: 1rem;
|
|
--radius-full: 9999px;
|
|
|
|
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
|
|
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
|
--shadow-glow: 0 0 15px 2px hsla(var(--primary-h), var(--primary-s), var(--primary-l), 0.15);
|
|
|
|
/* Transitions */
|
|
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
--transition-normal: 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
--transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
/* Dark mode overrides (Activated via html[data-theme='dark'] or media queries) */
|
|
[data-theme='dark'] {
|
|
--background-h: 220;
|
|
--background-s: 40%;
|
|
--background-l: 6%;
|
|
--background: hsl(var(--background-h), var(--background-s), var(--background-l));
|
|
|
|
--foreground-h: 220;
|
|
--foreground-s: 15%;
|
|
--foreground-l: 90%;
|
|
--foreground: hsl(var(--foreground-h), var(--foreground-s), var(--foreground-l));
|
|
|
|
--card: hsl(220, 30%, 11%);
|
|
--border: hsl(220, 20%, 18%);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Theme Consistency & Background Rules
|
|
|
|
To prevent background mismatching or flashing layout inconsistencies when moving between pages:
|
|
1. **Container Backgrounds**: Pages must use the radial gradient background that transitions smoothly across theme states:
|
|
```css
|
|
.container {
|
|
background: radial-gradient(circle at top right, hsla(var(--primary-h), var(--primary-s), var(--primary-l), 0.08), transparent 45%),
|
|
var(--background);
|
|
color: var(--foreground);
|
|
font-family: var(--font-sans);
|
|
transition: background var(--transition-slow);
|
|
padding-bottom: var(--space-12);
|
|
}
|
|
```
|
|
2. **Context-Backed Authentication & Theme**: Fetching user profiles or auth tokens on page mount is handled by the central `UserProvider` context to avoid page rendering flashes.
|
|
3. **Typography**: System default fonts are forbidden. Font tokens (`var(--font-sans)`) must be used on the body and all wrapper components.
|
|
|
|
---
|
|
|
|
## 3. Component Scoping with CSS Modules
|
|
|
|
All component-specific styles must live inside a `.module.css` file adjacent to the React component (e.g. `Button.tsx` pairs with `Button.module.css`).
|
|
|
|
### 3.1. Naming Conventions (Flat Local Names)
|
|
Since CSS Modules automatically generate unique identifiers at compile time (e.g., `.container` becomes `.Button_container__u1a2x`), complex BEM class names are not required. Use clear, semantic local names:
|
|
* Good: `.container`, `.card`, `.button`, `.badge`
|
|
* Avoid: `.button-container-outer`, `.btn-v2`
|
|
|
|
### 3.2. Scoped Styling in React
|
|
```tsx
|
|
import styles from './Button.module.css';
|
|
|
|
interface ButtonProps {
|
|
variant?: 'primary' | 'secondary';
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export function Button({ variant = 'primary', isActive, children }: ButtonProps) {
|
|
return (
|
|
<button
|
|
className={`
|
|
${styles.button}
|
|
${styles[variant]}
|
|
${isActive ? styles.isActive : ''}
|
|
`}
|
|
>
|
|
{children}
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Styling & Layout Guidelines
|
|
|
|
* **Layout Structure**: Use **CSS Grid** for page structures and multi-column layouts. Use **Flexbox** for alignment inside rows, headers, and buttons. Never use tables or absolute positioning for structural layouts.
|
|
* **Sizing & Spacing**: Use `rem` for typography, margin, padding, widths, and heights to ensure relative scaling. Always use variables from the spacing grid (`var(--space-4)`).
|
|
* **Responsive Design**: Follow a mobile-first media query approach. Breakpoints are coded as:
|
|
```css
|
|
.container {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: var(--space-4);
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.container {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.container {
|
|
grid-template-columns: repeat(4, 1fr);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. UI Polish & Animations
|
|
|
|
To deliver a premium visual experience:
|
|
* **Micro-interactions**: Every interactive element (buttons, cards, inputs) must have a subtle hover effect using hardware-accelerated properties (`transform`, `opacity`, `background-color`).
|
|
```css
|
|
.card {
|
|
background-color: var(--card);
|
|
border: 1px solid var(--border);
|
|
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: var(--shadow-lg), var(--shadow-glow);
|
|
}
|
|
```
|
|
* **No Inline Styles**: Inline styles (`style={{ ... }}`) are forbidden unless evaluating dynamically updated values that cannot be declared beforehand (e.g., progress bar percentage `--progress: 73%`).
|
|
* **Internationalization Integration**: Never hardcode text strings inside CSS files or class names. Labels must be fetched from the client translation dictionary (`t('key')`) to support bilingual layout rendering seamlessly.
|