Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
# 02 - CSS Conventions
|
||||
|
||||
Rules for writing CSS in YouTube Studio Flow. These apply to all frontend work. For the token values these rules reference, see [[01 - Visual Design]].
|
||||
|
||||
---
|
||||
|
||||
## Always use CSS Modules
|
||||
|
||||
Every component gets its own `ComponentName.module.css` file, co-located with the component. Class names are consumed as:
|
||||
|
||||
```tsx
|
||||
import styles from './ComponentName.module.css';
|
||||
|
||||
<div className={styles.container}>...</div>
|
||||
```
|
||||
|
||||
Global styles live exclusively in `globals.css`. Do not add component-specific rules to global files.
|
||||
|
||||
---
|
||||
|
||||
## Never use inline hex colors
|
||||
|
||||
All color values must come from CSS variables defined in `globals.css`. This is what makes the dark theme work — swapping variable values at the root switches the entire app.
|
||||
|
||||
```css
|
||||
/* WRONG */
|
||||
color: #01696f;
|
||||
background: #f9f8f5;
|
||||
border: 1px solid #d4d1ca;
|
||||
|
||||
/* CORRECT */
|
||||
color: var(--color-primary);
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
```
|
||||
|
||||
This applies everywhere: component CSS, inline styles, and any dynamically constructed style objects.
|
||||
|
||||
---
|
||||
|
||||
## Never use raw px for spacing
|
||||
|
||||
Use `--space-*` variables for all margins, padding, and gaps. Raw pixel values make the spacing system incoherent and break visual rhythm.
|
||||
|
||||
```css
|
||||
/* WRONG */
|
||||
padding: 16px 24px;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
/* CORRECT */
|
||||
padding: var(--space-4) var(--space-6);
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-3);
|
||||
```
|
||||
|
||||
The spacing scale runs from `--space-1` (0.25rem) to `--space-16` (4rem). See [[01 - Visual Design]] for the full table.
|
||||
|
||||
---
|
||||
|
||||
## The `min-width: 0` rule
|
||||
|
||||
Flex and grid children default to `min-width: auto`, which means they cannot shrink below their content's natural size. In practice this causes horizontal overflow — the child pushes past its container instead of wrapping or truncating.
|
||||
|
||||
Add `min-width: 0` to any flex or grid child that contains text, a table, a wide image, or another flex/grid container:
|
||||
|
||||
```css
|
||||
.wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
min-width: 0; /* required — prevents horizontal scrollbar */
|
||||
}
|
||||
```
|
||||
|
||||
This must be applied at every level of nesting. A `min-width: 0` on an outer element does not propagate to inner flex containers.
|
||||
|
||||
---
|
||||
|
||||
## The `overflow-x: hidden` backstop
|
||||
|
||||
The `.content` wrapper in `DashboardLayout.module.css` carries `overflow-x: hidden` as a definitive backstop against page-level horizontal overflow. Do not remove this rule. It is a last-resort containment boundary, not a substitute for fixing `min-width` at the source.
|
||||
|
||||
---
|
||||
|
||||
## Global utility classes
|
||||
|
||||
Prefer these over writing new styles for common UI elements.
|
||||
|
||||
### Buttons — from `globals.css`
|
||||
|
||||
```html
|
||||
<button class="btn btn-primary">Save</button>
|
||||
<button class="btn btn-secondary">Cancel</button>
|
||||
```
|
||||
|
||||
Do not write custom button styles for standard primary/secondary actions.
|
||||
|
||||
### Pills and badges — from `globals.css`
|
||||
|
||||
```html
|
||||
<span class="pill pill-primary">Active</span>
|
||||
<span class="pill pill-warn">Warning</span>
|
||||
<span class="pill pill-purple">Draft</span>
|
||||
```
|
||||
|
||||
Pills use `--radius-full` and are intended for status chips, labels, and category tags.
|
||||
|
||||
### Form fields — from `FormField.module.css`
|
||||
|
||||
Import this file as `f` by convention:
|
||||
|
||||
```tsx
|
||||
import f from '@/components/shared/FormField.module.css';
|
||||
```
|
||||
|
||||
Available classes:
|
||||
|
||||
```tsx
|
||||
<div className={f.field}>
|
||||
<label className={f.label}>Title</label>
|
||||
<input className={f.input} />
|
||||
</div>
|
||||
|
||||
<div className={f.row}>
|
||||
{/* two fields side by side */}
|
||||
</div>
|
||||
|
||||
<div className={f.actions}>
|
||||
{/* right-aligned action buttons */}
|
||||
</div>
|
||||
```
|
||||
|
||||
| Class | Purpose |
|
||||
|---|---|
|
||||
| `f.field` | Vertical label + input stack |
|
||||
| `f.label` | Styled form label |
|
||||
| `f.input` | Standard text input |
|
||||
| `f.select` | Dropdown/select element |
|
||||
| `f.row` | Horizontal pair of fields |
|
||||
| `f.actions` | Right-aligned button row |
|
||||
|
||||
---
|
||||
|
||||
## Dropdowns and selects
|
||||
|
||||
Use `className={f.select}` from `FormField.module.css`. When a select needs to be inline or auto-sized, override width only:
|
||||
|
||||
```tsx
|
||||
<select className={f.select} style={{ width: 'auto' }}>
|
||||
```
|
||||
|
||||
Do not write custom select styles. The `f.select` class handles appearance, border, padding, color, and focus state consistently across themes.
|
||||
|
||||
---
|
||||
|
||||
## Transitions
|
||||
|
||||
Use these values for interactive elements:
|
||||
|
||||
| Situation | Value |
|
||||
|---|---|
|
||||
| Color, background, border on hover | `transition: color 0.15s, background 0.15s` |
|
||||
| General interactive element | `transition: all 0.15s` |
|
||||
| Layout change (sidebar width) | `transition: width 0.2s` |
|
||||
|
||||
Do not use durations longer than `0.2s` for micro-interactions. Reserve longer durations for full-screen transitions if they are ever introduced.
|
||||
|
||||
---
|
||||
|
||||
## Comments
|
||||
|
||||
Only comment CSS when the reason is not obvious from the code. Acceptable:
|
||||
|
||||
```css
|
||||
.main {
|
||||
flex: 1;
|
||||
min-width: 0; /* prevents horizontal overflow in flex child */
|
||||
}
|
||||
|
||||
.overlay {
|
||||
pointer-events: none; /* must not intercept clicks on siblings */
|
||||
}
|
||||
```
|
||||
|
||||
Not acceptable: describing what the rule does, restating what is visually apparent, notes about which feature uses the class.
|
||||
Reference in New Issue
Block a user