mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 17:05:48 +00:00
Mark sync-based onboarding dismissal as fully complete so the hint tour does not restart on the next boot. Guard the sync setup CTA while the dialog is loading or open, cover the async races in tests, and move the onboarding z-index to a design token.
208 lines
10 KiB
Markdown
208 lines
10 KiB
Markdown
# Styling Guide
|
||
|
||
## Rules
|
||
|
||
- **All visual styling must use CSS variables** from `src/styles/_css-variables.scss` — never hardcode colors, spacing, shadows, transitions, or z-index.
|
||
- **Positioning/layout is fine as plain CSS** — flexbox, grid, display, position, dimensions.
|
||
- **Check `src/app/ui/` first** before creating new styled elements — 40+ reusable components exist.
|
||
- **Component SCSS should be minimal** — shared styles belong in `src/styles/components/` or as a mixin.
|
||
- **Material overlay components** (menus, dialogs, tooltips) render outside component scope — style them in `src/styles/components/` and add a comment in the component pointing there.
|
||
|
||
## Anti-Patterns
|
||
|
||
| Avoid | Do Instead |
|
||
| ------------------------------------ | ------------------------------------------------------------------------- |
|
||
| Hardcoded colors (`#fff`, `red`) | CSS variables (`--text-color`, `--card-bg`, `--color-danger`) |
|
||
| Hardcoded spacing (`16px`, `1rem`) | Spacing variables (`--s2`, `--s`, `--s-half`) |
|
||
| Hardcoded shadows | Elevation variables (`--whiteframe-shadow-*dp`, `--md-sys-level*`) |
|
||
| Hardcoded transitions/durations | Transition variables (`--transition-standard`, `--transition-duration-*`) |
|
||
| Custom z-index values | Z-index variables (`--z-main-header`, `--z-backdrop`, etc.) |
|
||
| New styled elements without checking | Check `src/app/ui/` for existing reusable components first |
|
||
|
||
## Key Files
|
||
|
||
| File | Purpose |
|
||
| -------------------------------- | ------------------------------------------------------------- |
|
||
| `src/styles/_css-variables.scss` | All CSS custom properties (design tokens) |
|
||
| `src/styles/themes.scss` | Material theme setup + utility classes |
|
||
| `src/styles/page.scss` | Global page/body styles |
|
||
| `src/styles/util.scss` | Utility classes |
|
||
| `src/styles/components/` | Global component styles (Material overrides, shared patterns) |
|
||
| `src/styles/mixins/` | Reusable SCSS mixins |
|
||
| `src/app/ui/` | 40+ reusable Angular UI components |
|
||
|
||
## Spacing Variables (8px Grid)
|
||
|
||
| Variable | Value | Variable | Value |
|
||
| ------------- | ----- | -------- | ----- |
|
||
| `--s-quarter` | 2px | `--s4` | 32px |
|
||
| `--s-half` | 4px | `--s5` | 40px |
|
||
| `--s` | 8px | `--s6` | 48px |
|
||
| `--s2` | 16px | `--s7` | 56px |
|
||
| `--s3` | 24px | `--s8` | 64px |
|
||
|
||
```scss
|
||
// ✅ Good
|
||
padding: var(--s2) var(--s3);
|
||
gap: var(--s-half);
|
||
|
||
// ❌ Bad
|
||
padding: 16px 24px;
|
||
gap: 4px;
|
||
```
|
||
|
||
## Color Variables
|
||
|
||
| Use case | Variables |
|
||
| ------------------ | -------------------------------------------------------------------------------------------------- |
|
||
| Text | `--text-color`, `--text-color-muted`, `--text-color-most-intense` |
|
||
| Backgrounds | `--bg`, `--card-bg`, `--task-c-bg`, `--sub-task-c-bg` |
|
||
| Semantic | `--color-success` (#4caf50), `--color-warning` (#ff9800), `--color-danger` (#f44336) |
|
||
| Material palette | `--palette-primary-500`, `--palette-accent-500`, `--palette-warn-500` (100–900) |
|
||
| Overlays | `--c-dark-10` through `--c-dark-90`, `--c-light-05` through `--c-light-90` |
|
||
| Alpha coefficients | `--border-alpha` (0.12), `--overlay-alpha` (0.1), `--muted-alpha` (0.6), `--separator-alpha` (0.3) |
|
||
|
||
### Theme-Specific Values
|
||
|
||
Light theme sets: `--bg: #f8f8f7`, `--card-bg: #ffffff`, `--text-color: rgb(44, 44, 44)`
|
||
Dark theme sets: `--bg: #131314`, `--card-bg: var(--dark3)`, `--text-color: rgb(230, 230, 230)`
|
||
|
||
Dark elevation colors: `--dark0` (rgb(0,0,0)) through `--dark24` (rgb(56,56,56))
|
||
|
||
### Theme-Specific Overrides in Components
|
||
|
||
```scss
|
||
@include darkTheme() {
|
||
/* dark-only styles */
|
||
}
|
||
@include lightTheme() {
|
||
/* light-only styles */
|
||
}
|
||
```
|
||
|
||
Mixins are in `src/styles/mixins/_theming.scss`.
|
||
|
||
## Shadows & Elevation
|
||
|
||
- `--whiteframe-shadow-1dp` through `--whiteframe-shadow-24dp` — classic Material shadows
|
||
- `--md-sys-level1` through `--md-sys-level5` — Material Design 3 style
|
||
|
||
## Transitions & Animations
|
||
|
||
| Type | Variables |
|
||
| ---------- | ------------------------------------------------------------------------------------------------------------------ |
|
||
| Shorthands | `--transition-fast`, `--transition-standard`, `--transition-enter`, `--transition-leave` |
|
||
| Durations | `--transition-duration-xs` (90ms), `-s` (150ms), `-m` (225ms), `-l` (375ms) |
|
||
| Additional | `--transition-duration-enter` (225ms), `--transition-duration-leave` (195ms), `--page-transition-duration` (225ms) |
|
||
| Timing | `--ani-standard-timing`, `--ani-enter-timing`, `--ani-leave-timing`, `--ani-sharp-timing` |
|
||
|
||
When migrating hardcoded durations, pick the nearest bucket — up to ~15% drift is acceptable for UI transitions.
|
||
|
||
## Focus Ring
|
||
|
||
Keyboard-accessibility tokens for custom interactive elements. Material components keep their own focus treatment; use these for non-Material buttons, cards, and custom controls.
|
||
|
||
| Variable | Value |
|
||
| --------------------- | ---------------------------- |
|
||
| `--focus-ring-width` | 2px |
|
||
| `--focus-ring-offset` | 2px |
|
||
| `--focus-ring-color` | `var(--palette-primary-500)` |
|
||
|
||
Quickest adoption — add the `.focus-ring` utility class from `util.scss`, which applies an `outline` on `:focus-visible` only (so it doesn't fire on mouse clicks).
|
||
|
||
```scss
|
||
// opt-in per-element
|
||
.my-button:focus-visible {
|
||
outline: var(--focus-ring-width) solid var(--focus-ring-color);
|
||
outline-offset: var(--focus-ring-offset);
|
||
}
|
||
```
|
||
|
||
## Z-Index Layers
|
||
|
||
| Variable | Value | Purpose |
|
||
| ------------------------ | ----- | ------------------------ |
|
||
| `--z-check-done` | 11 | Task done checkbox |
|
||
| `--z-main-header` | 12 | Main header |
|
||
| `--z-task-title-focus` | 32 | Focused task title |
|
||
| `--z-mobile-bottom-nav` | 50 | Mobile bottom navigation |
|
||
| `--z-side-nav` | 60 | Side navigation |
|
||
| `--z-backdrop` | 222 | Backdrop overlay |
|
||
| `--z-add-task-bar` | 999 | Add task bar |
|
||
| `--z-search-bar` | 999 | Search bar |
|
||
| `--z-onboarding-presets` | 999 | Onboarding preset screen |
|
||
| `--z-tour` | 1001 | Tour overlay |
|
||
|
||
## Layout Variables
|
||
|
||
| Variable | Value | Notes |
|
||
| ----------------------- | ----- | ------------------ |
|
||
| `--component-max-width` | 800px | 900–1000px on iPad |
|
||
| `--side-nav-width` | 200px | |
|
||
| `--side-nav-width-l` | 400px | |
|
||
| `--bar-height-large` | 56px | |
|
||
| `--bar-height` | 48px | |
|
||
| `--bar-height-small` | 40px | |
|
||
|
||
## Responsive Breakpoints
|
||
|
||
Available as CSS vars (`--layout-xxxs` through `--layout-xl`) and as SCSS mixins in `src/styles/mixins/_media-queries.scss`:
|
||
|
||
| Breakpoint | Value |
|
||
| ---------- | ------ |
|
||
| `xxxs` | 398px |
|
||
| `xxs` | 450px |
|
||
| `xs` | 600px |
|
||
| `s` | 800px |
|
||
| `m` | 1000px |
|
||
| `l` | 1200px |
|
||
| `xl` | 2000px |
|
||
|
||
## Utility Classes
|
||
|
||
Defined in `src/styles/util.scss` and `src/styles/themes.scss`:
|
||
|
||
- Layout: `.center-wrapper`, `.mw` (max-width container)
|
||
- Responsive: `.hide-xs`, `.hide-xxs`, `.hide-gt-sm`
|
||
- Input: `.show-only-on-touch-primary`, `.show-only-on-mouse-primary`
|
||
- Theme: `.show-dark-only`, `.show-light-only`
|
||
- Color: `.bg-primary`, `.bgc-accent`, `.color-primary`, `.bg-success`, `.bg-warning`, `.bg-danger`
|
||
- Effects: `.milk-glass` (backdrop blur)
|
||
|
||
## Authoring Themes
|
||
|
||
Theme files live in `src/assets/themes/*.css` and are loaded at runtime.
|
||
|
||
### Side nav: never apply CB-creating properties to the `magic-side-nav` host
|
||
|
||
The mobile drawer (`.nav-sidenav`) and its overlay (`.nav-backdrop-mobile`) are `position: fixed` children of the `magic-side-nav` host. On mobile the host shrinks to `width: 0` (`hostWidthSignal` in `magic-side-nav.component.ts`).
|
||
|
||
Any property that establishes a [new containing block for fixed-position descendants](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block) — `backdrop-filter`, `filter`, `transform`, `perspective`, `contain: paint|layout|strict`, or a matching `will-change` — re-anchors the drawer and backdrop to the 0-wide host. The drawer never appears when the user taps the menu.
|
||
|
||
Apply glass/blur/tint to the inner `.nav-sidenav` instead:
|
||
|
||
```css
|
||
/* ❌ Bad — collapses the mobile drawer */
|
||
body.isDarkTheme magic-side-nav {
|
||
background: var(--my-pane);
|
||
backdrop-filter: blur(32px);
|
||
}
|
||
|
||
/* ✅ Good — host stays visually inert */
|
||
body.isDarkTheme magic-side-nav .nav-sidenav {
|
||
background: var(--my-pane);
|
||
backdrop-filter: blur(32px);
|
||
}
|
||
```
|
||
|
||
Properties that do NOT create a containing block — `background`, `border`, `box-shadow`, `margin` — are safe on the host. See `velvet.css` and `liquid-glass.css` for full reference patterns.
|
||
|
||
## Global Component Styles
|
||
|
||
Located in `src/styles/components/`, these are needed for elements that render outside component scope:
|
||
|
||
- `_overwrite-material.scss` — Material component customizations
|
||
- `_customizer-menu.scss`, `backdrop.scss`, `bottom-panel.scss`
|
||
- `markdown.scss`, `mentions.scss`, `table.scss`
|
||
- `fab-wrapper.scss`, `wrap-buttons.scss`, `multi-btn-wrapper.scss`
|
||
- `planner-shared.scss`, `formly-rows.scss`, `scrollbars.scss`
|