maverick-wave 5.24.0 → 5.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/mw-maverick-wave/SKILL.md +32 -5
- package/.claude/skills/mw-maverick-wave/references/components.md +4 -0
- package/.claude/skills/mw-maverick-wave/references/javascript.md +44 -8
- package/.claude/skills/mw-maverick-wave/references/layout.md +39 -11
- package/.claude/skills/mw-maverick-wave/references/theming.md +34 -10
- package/CHANGELOG.md +20 -0
- package/CLAUDE.md +4 -0
- package/README.md +4 -2
- package/index.html +13 -0
- package/maverick-wave.min.css +7 -5
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/src/js/main.js +149 -57
- package/src/partials/accordions-container.html +1 -1
- package/src/partials/alerts-container.html +1 -1
- package/src/partials/announcement-container.html +1 -1
- package/src/partials/avatars-container.html +1 -1
- package/src/partials/badges-container.html +1 -1
- package/src/partials/blog-posts-container.html +2 -2
- package/src/partials/breadcrumbs-container.html +1 -1
- package/src/partials/button-bar-container.html +1 -1
- package/src/partials/buttons-container.html +1 -1
- package/src/partials/calendar-container.html +1 -1
- package/src/partials/cards-container.html +1 -1
- package/src/partials/code-container.html +1 -1
- package/src/partials/colors-container.html +3 -3
- package/src/partials/coming-soon-container.html +1 -1
- package/src/partials/contact-container.html +1 -1
- package/src/partials/divider-container.html +1 -1
- package/src/partials/dropdown-container.html +1 -1
- package/src/partials/empty-state-container.html +1 -1
- package/src/partials/form-container.html +1 -1
- package/src/partials/form-elements-container.html +1 -1
- package/src/partials/form-field-container.html +1 -1
- package/src/partials/gallery-container.html +1 -1
- package/src/partials/get-started-container.html +5 -10
- package/src/partials/grid-container.html +1 -1
- package/src/partials/header-utilities-container.html +2 -2
- package/src/partials/html-lists-container.html +1 -1
- package/src/partials/info-container.html +1 -1
- package/src/partials/input-group-container.html +2 -4
- package/src/partials/item-lists-container.html +1 -1
- package/src/partials/kanban-container.html +2 -2
- package/src/partials/kbd-container.html +1 -1
- package/src/partials/leader-row-container.html +2 -2
- package/src/partials/login-container.html +2 -2
- package/src/partials/lunch-menu-container.html +2 -2
- package/src/partials/media-container.html +1 -1
- package/src/partials/meta-info-container.html +1 -1
- package/src/partials/modals-container.html +1 -1
- package/src/partials/page-header-container.html +1 -1
- package/src/partials/pagination-container.html +2 -2
- package/src/partials/palette-container.html +2 -2
- package/src/partials/panels-container.html +2 -2
- package/src/partials/parallax-container.html +1 -1
- package/src/partials/pricing-container.html +2 -2
- package/src/partials/progress-container.html +1 -1
- package/src/partials/prose-container.html +1 -1
- package/src/partials/ratings-container.html +1 -1
- package/src/partials/section-head-container.html +6 -3
- package/src/partials/segmented-container.html +1 -1
- package/src/partials/skeleton-container.html +1 -1
- package/src/partials/spinners-container.html +1 -1
- package/src/partials/stepper-container.html +1 -1
- package/src/partials/tables-container.html +1 -1
- package/src/partials/tabs-container.html +1 -1
- package/src/partials/tags-container.html +1 -7
- package/src/partials/testimonials-container.html +1 -1
- package/src/partials/tiles-container.html +1 -1
- package/src/partials/typography-container.html +1 -1
- package/src/partials/utilities-container.html +1 -1
- package/src/scss/base/_base.scss +21 -5
- package/src/scss/components/_blog-post.scss +15 -10
- package/src/scss/components/_button-bar.scss +10 -6
- package/src/scss/components/_code.scss +23 -34
- package/src/scss/components/_info.scss +8 -1
- package/src/scss/components/_kanban.scss +6 -6
- package/src/scss/components/_meta-info.scss +7 -6
- package/src/scss/components/_tables.scss +6 -4
- package/src/scss/components/_tiles.scss +20 -30
- package/src/scss/layout/_grid.scss +28 -0
- package/src/scss/layout/_header.scss +16 -9
- package/src/scss/layout/_home.scss +21 -2
- package/src/scss/layout/_main.scss +7 -7
- package/src/scss/layout/_page-header.scss +4 -4
- package/src/scss/layout/_section.scss +33 -10
- package/src/scss/main-lean.scss +16 -0
- package/src/scss/utilities/_index.scss +1 -0
- package/src/scss/utilities/_print.scss +107 -0
- package/src/scss/utilities/_touch-targets.scss +4 -0
|
@@ -75,6 +75,22 @@ Or from the npm package via SCSS: `@use 'maverick-wave/src/scss/main';`
|
|
|
75
75
|
(details and configuration in `references/theming.md`). The viewport meta above
|
|
76
76
|
belongs in `src/index.html` there, with `viewport-fit=cover` just the same.
|
|
77
77
|
|
|
78
|
+
**`main-lean` for a page that uses a handful of components.** The full build is
|
|
79
|
+
~41 kB gzipped and carries all 48 of them. `main-lean` is the same framework
|
|
80
|
+
without any component - tokens, reset, typography, layout, utilities - and the
|
|
81
|
+
components come in one by one next to it:
|
|
82
|
+
|
|
83
|
+
```scss
|
|
84
|
+
@use 'maverick-wave/src/scss/main-lean' with (
|
|
85
|
+
$primary-color: #1b1b1d
|
|
86
|
+
);
|
|
87
|
+
@use 'maverick-wave/src/scss/components/buttons';
|
|
88
|
+
@use 'maverick-wave/src/scss/components/cards';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
That lands at ~16 kB gzipped plus what the components add (three of them ≈ 19 kB
|
|
92
|
+
in total). The configuration goes on `main-lean`, not on the component imports.
|
|
93
|
+
|
|
78
94
|
> **Never load `maverick-wave.min.js` in a SPA.** Everything in it is wired up
|
|
79
95
|
> once on `DOMContentLoaded` and writes straight into the DOM. In an Angular
|
|
80
96
|
> app that fires once during bootstrap: components rendered later are never
|
|
@@ -166,6 +182,11 @@ between them moved.
|
|
|
166
182
|
Column grids and most components are mobile-first. The mixins emit range syntax
|
|
167
183
|
(`media-up` is `width >= bp`, `media-down` is `width < bp`), so the two never
|
|
168
184
|
overlap at the breakpoint itself and neither has to stop a fraction short of it.
|
|
185
|
+
Write `media-up`: the base block is the phone and each breakpoint adds to it.
|
|
186
|
+
`media-down` is right in three cases - a rule that sets what the base never sets
|
|
187
|
+
(turned around it would hard-wire an inherited value), a narrow layout that costs
|
|
188
|
+
more properties than the wide one (the navbar sheet, the modal bottom sheet), and
|
|
189
|
+
a class that only ever means "below here", like `mw-hide-mobile`.
|
|
169
190
|
|
|
170
191
|
**Overriding.** Everything the framework emits sits in
|
|
171
192
|
`@layer mw.reset, mw.base, mw.forms, mw.components, mw.layout, mw.utilities`.
|
|
@@ -234,7 +255,8 @@ none of them survive into the compiled CSS. Full list in `references/theming.md`
|
|
|
234
255
|
zoom. A headline passes `$to: 'xl'`.
|
|
235
256
|
- `fluid-container($min, $max, $from, $to)` - the same ramp in `cqi` against the
|
|
236
257
|
container. Use it instead of `fluid()` inside a `@container` block.
|
|
237
|
-
- `media-up($bp)` / `media-down($bp)` - the breakpoint map as a query.
|
|
258
|
+
- `media-up($bp)` / `media-down($bp)` - the breakpoint map as a query. `media-up`
|
|
259
|
+
is the default direction, see **Breakpoints** above.
|
|
238
260
|
- `touch-context($bp: 'md')` - coarse pointer _or_ narrow viewport, the condition
|
|
239
261
|
every target-size rule in the framework hangs under.
|
|
240
262
|
- `touch-floor($size: 2.75rem)` - that condition plus a `min-height`.
|
|
@@ -299,7 +321,7 @@ feature frame) ·
|
|
|
299
321
|
`mw-content` ·
|
|
300
322
|
`mw-section` · `mw-section-head` (+ `-title`, `-intro`, `-numbered`, colours) ·
|
|
301
323
|
`mw-page-header` · `mw-grid-*`
|
|
302
|
-
(+ `mw-grid-even`) ·
|
|
324
|
+
(+ `mw-grid-even`, `mw-grid-from-{sm,md,lg,xl}`) ·
|
|
303
325
|
`mw-columns-2/3` · `mw-row-split` · `mw-hero` (+ `mw-scroll-hint`, `-end`) ·
|
|
304
326
|
`mw-parallax` (+ `-media`, `-content`, `-dimmed`, `-sticky`, `-rise`,
|
|
305
327
|
`-slow`, `-pattern`) · `mw-footer`
|
|
@@ -312,7 +334,7 @@ feature frame) ·
|
|
|
312
334
|
`mw-glow-{primary,secondary,info,success,warning,danger}` ·
|
|
313
335
|
`mw-corner-plain` ·
|
|
314
336
|
`mw-aspect-square|video|wide|portrait|photo` · `mw-d-{sm,md,lg,xl}-*` /
|
|
315
|
-
`mw-hide-mobile` / `mw-hide-desktop` · `mw-overflow-*` / `mw-snap-x` ·
|
|
337
|
+
`mw-hide-mobile` / `mw-hide-desktop` / `mw-hide-print` / `mw-print-only` · `mw-overflow-*` / `mw-snap-x` ·
|
|
316
338
|
`mw-reveal` / `mw-reveal-stagger` · spacing, flex, display, text
|
|
317
339
|
|
|
318
340
|
## Pitfalls
|
|
@@ -477,13 +499,18 @@ feature frame) ·
|
|
|
477
499
|
directly after the block, so the overlap reads as a surface and not a cut.
|
|
478
500
|
It sits at `:where()` weight, so a plain `box-shadow` of your own on that
|
|
479
501
|
section replaces it.
|
|
480
|
-
30.
|
|
502
|
+
30. **A stored theme needs a script in the `<head>`.** `main.js` runs at the
|
|
503
|
+
end of the body, so a reader whose choice differs from the OS sees the
|
|
504
|
+
other theme for one frame. Five inline lines in the head apply it before
|
|
505
|
+
the first paint - the snippet is in `references/javascript.md`. The theme
|
|
506
|
+
classes live on `<html>` for exactly this reason.
|
|
507
|
+
31. **`viewport-fit=cover` belongs in the viewport meta.** The container
|
|
481
508
|
gutter, the mobile nav panel and the modal padding all budget for the
|
|
482
509
|
cutout with `env(safe-area-inset-*)`, and iOS resolves every one of those
|
|
483
510
|
to `0` without it - on a notched phone the content then sits under the
|
|
484
511
|
rounded corner. Nothing errors, which is why the shipped JS writes a
|
|
485
512
|
console warning on localhost when the meta is missing.
|
|
486
|
-
|
|
513
|
+
32. **Half the layout reads its own width, not the viewport.** `mw-card`,
|
|
487
514
|
`mw-tile`, `mw-stepper`, both timelines and - since 5.13.0 -
|
|
488
515
|
`mw-gallery-container` and `mw-image-slider` are `@container` queries, so
|
|
489
516
|
any of them in a half-width column takes its narrow layout there while the
|
|
@@ -1319,6 +1319,10 @@ edge drops and the key sits 1px lower.
|
|
|
1319
1319
|
- The cursor is `default` because a figure is usually not clickable. On `<a>`
|
|
1320
1320
|
and `<button>` it turns into a pointer automatically; on anything else use
|
|
1321
1321
|
`mw-info-clickable`.
|
|
1322
|
+
- `mw-info-block` is the same surface carrying a paragraph: 68 characters
|
|
1323
|
+
wide, left-aligned, and it does not lift on hover. It sits at the left edge
|
|
1324
|
+
like everything else with running text in it - `mw-info-block-center` puts it
|
|
1325
|
+
back in the middle of its container.
|
|
1322
1326
|
- `mw-info-mini` is the 20px status dot: sizes `-sm`, `-lg`, `-xl`, colours
|
|
1323
1327
|
`-primary`, `-secondary`, `-success`, `-warning`, `-danger`, `-info`.
|
|
1324
1328
|
|
|
@@ -2,15 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## What `maverick-wave.min.js` is
|
|
4
4
|
|
|
5
|
-
One vanilla IIFE, no dependencies, ~24 kB. It queries the DOM
|
|
6
|
-
`DOMContentLoaded` and attaches listeners.
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
One vanilla IIFE, no dependencies, ~24 kB. It queries the DOM on
|
|
6
|
+
`DOMContentLoaded` and attaches listeners. No `MutationObserver`, no exported
|
|
7
|
+
module - it is built for a server-rendered or static page.
|
|
8
|
+
|
|
9
|
+
Markup that arrives later gets wired through the one public entry point:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
window.MaverickWave.init(subtree); // or init() for the whole document
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Call it after an htmx swap, after filling a modal from a fetch, or after a view
|
|
16
|
+
transition replaced the body. Every element that already carries listeners is
|
|
17
|
+
skipped, so calling it twice over the same markup does nothing - the components
|
|
18
|
+
are safe to re-run, the document- and window-level behaviour is wired once and
|
|
19
|
+
never again.
|
|
20
|
+
|
|
21
|
+
What that does **not** make it is a SPA library - see below.
|
|
9
22
|
|
|
10
23
|
## Why a SPA must not load it
|
|
11
24
|
|
|
12
|
-
-
|
|
13
|
-
in a routed application
|
|
25
|
+
- Anything rendered after bootstrap needs `MaverickWave.init()` by hand, for
|
|
26
|
+
every subtree, on every render - in a routed application that is all of it.
|
|
14
27
|
- It writes straight into the DOM (class toggles, generated elements, inline
|
|
15
28
|
styles). In Angular that happens outside change detection; in a zoneless app
|
|
16
29
|
the framework never learns about it, and on the next re-render your bindings
|
|
@@ -23,6 +36,29 @@ in a Vite entry point. Load the **CSS only** and rebuild the handful of
|
|
|
23
36
|
behaviours in components. Each one is a few lines - the framework's state
|
|
24
37
|
classes are the entire contract.
|
|
25
38
|
|
|
39
|
+
## The theme has to be applied before the first paint
|
|
40
|
+
|
|
41
|
+
`main.js` sits at the end of the body, so a stored choice that differs from the
|
|
42
|
+
operating system reaches the page one frame too late - the reader sees the other
|
|
43
|
+
theme flash. The fix is five lines in the `<head>`, inline and synchronous,
|
|
44
|
+
before the stylesheet has painted anything:
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<script>
|
|
48
|
+
(function () {
|
|
49
|
+
var stored = localStorage.getItem('mw-theme');
|
|
50
|
+
if (stored === 'light' || stored === 'dark') {
|
|
51
|
+
document.documentElement.classList.add('mw-theme-' + stored);
|
|
52
|
+
}
|
|
53
|
+
})();
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That is also why the toggle writes the class on `<html>` and not on `<body>`:
|
|
58
|
+
in the head there is no body yet. An external file would not help - it paints
|
|
59
|
+
first. With nothing stored, nothing happens here and the page follows the OS on
|
|
60
|
+
its own through `light-dark()`.
|
|
61
|
+
|
|
26
62
|
## Behaviour inventory
|
|
27
63
|
|
|
28
64
|
| Behaviour | What the shipped JS does | What to do instead |
|
|
@@ -33,11 +69,11 @@ classes are the entire contract.
|
|
|
33
69
|
| Mobile nav | Toggles `open` on `mw-menu-btn` and `mw-navbar` plus `mw-nav-open` on `<body>`, writes `aria-expanded` when the button is a `<button>`, closes on anchor click and on Escape (focus returns to the button) | One signal, bound to all three - the body class carries the scrim, the scroll lock and the pinning of the bar; reset it on navigation end |
|
|
34
70
|
| Scroll spy | Sets `mw-active` on `mw-navbar-link` from the scroll position | Router-based: `routerLinkActive="mw-active"` |
|
|
35
71
|
| Anchor scrolling | Intercepts `a[href^="#"]` and runs its own eased scroll - duration scales with distance, capped at 1.4s, cancelled by wheel or touch. Lands on `scroll-padding-top`, moves focus to the target, writes the hash with `replaceState`, and measures a sticky target unpinned | The router; for in-page anchors `scrollIntoView({ behavior: 'smooth' })` or your own animation |
|
|
36
|
-
| Theme toggle | `localStorage['mw-theme']`, toggles `mw-theme-light` / `mw-theme-dark` on `<
|
|
72
|
+
| Theme toggle | `localStorage['mw-theme']`, toggles `mw-theme-light` / `mw-theme-dark` on `<html>` and `mw-active` on the toggle, wrapped in `mw-theme-switching` on `<html>` so the flip starts no transitions. With nothing stored it takes `prefers-color-scheme` and keeps following it | A theme service - see `examples/angular-services.md` |
|
|
37
73
|
| Progress bar | `IntersectionObserver` sets `width` from `data-value` | Bind `[style.width.%]="value()"` on `mw-progress-fill` |
|
|
38
74
|
| Slider | On `input`, sets `--value` (track fill) and `data-value` (badge text) | Bind `[style.--value.%]` and `[attr.data-value]` |
|
|
39
75
|
| Alerts | Close button adds `mw-alert-closing` (fade out), then `mw-alert-closed` (`display: none`) after `--mw-duration-base` | Remove the alert from the list/signal |
|
|
40
|
-
| Checkbox lists | Adds `mw-selected` to the `li`, emits a `checkboxToggle` event, exposes `window.
|
|
76
|
+
| Checkbox lists | Adds `mw-selected` to the `li`, emits a `checkboxToggle` event, exposes `window.mwToggleCheckbox` | `[class.mw-selected]="item.checked"` |
|
|
41
77
|
| Gallery | Generates the dots, moves the track, swipe handling (single finger, dominant axis, passive listeners), writes `mw-gallery-desc` | Render dots in the template, bind the track transform and `mw-active` on the current dot |
|
|
42
78
|
| Image slider | Toggles `mw-active` on the overlay image and the control button with the matching `data-index` | Bind `mw-active` from the selected index |
|
|
43
79
|
| Kanban board | Counts the tickets per lane, moves a card between lanes (`data-kanban-move`) and marks the arrival with `mw-kanban-card-moved-forward` / `-back`, clones `mw-kanban-card-template` on save, derives the next key from `data-kanban-prefix`, toggles `mw-active` on the composer | Keep the tickets in a signal/store and render the lanes from it; `mw-active` on the composer, `mw-kanban-editing` on the ticket it replaces. Neither the `<template>` nor the `mw-kanban-composer-*` hook classes are needed |
|
|
@@ -237,16 +237,16 @@ pointing at the trigger in every combination.
|
|
|
237
237
|
|
|
238
238
|
## Sections
|
|
239
239
|
|
|
240
|
-
| Class | Use
|
|
241
|
-
| ----------------------------------- |
|
|
242
|
-
| `mw-section` | Vertical rhythm for a page band - `--mw-section-padding-block`, 3.3rem (2.5rem below `md`, 1.75rem below `sm`)
|
|
243
|
-
| `mw-section-alternate` | Diagonal pattern background; combine with `mw-section`
|
|
244
|
-
| `mw-section-head` | The opening of a section: hairline rule, a mark on its left end, title and lead - all on one left edge. Variants `-secondary`, `-success`, `-warning`, `-danger`, `-info` recolour the mark
|
|
245
|
-
| `mw-section-head-title` | The heading inside it, `2xl` growing to `4xl` up to 992px, tight tracking
|
|
246
|
-
| `mw-section-head-intro` | The lead under it - muted, 65 characters, and from `md` up at most four fifths of the container
|
|
247
|
-
| `mw-section-head-numbered` | Adds the running number at the right end of the rule; the browser counts, restarting per `mw-main`
|
|
248
|
-
| `mw-section-subtitle` | Left-aligned heading with a thin secondary underline, `xl` growing to `2xl` up to 576px - the level inside a section
|
|
249
|
-
| `mw-section-nav` + `mw-section-btn` | Sticky single-row strip of outline-style jump links; parks under the header and scrolls sideways when it overflows
|
|
240
|
+
| Class | Use |
|
|
241
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
242
|
+
| `mw-section` | Vertical rhythm for a page band - `--mw-section-padding-block`, 3.3rem (2.5rem below `md`, 1.75rem below `sm`). Point it at `--mw-section-padding-compact` or `--mw-section-padding-airy`, which step down the same way, or at `--mw-section-padding-fluid`, which ramps with the screen instead |
|
|
243
|
+
| `mw-section-alternate` | Diagonal pattern background; combine with `mw-section` |
|
|
244
|
+
| `mw-section-head` | The opening of a section: hairline rule, a mark on its left end, title and lead - all on one left edge. Variants `-secondary`, `-success`, `-warning`, `-danger`, `-info` recolour the mark |
|
|
245
|
+
| `mw-section-head-title` | The heading inside it, `2xl` growing to `4xl` up to 992px, tight tracking |
|
|
246
|
+
| `mw-section-head-intro` | The lead under it - muted, 65 characters, and from `md` up at most four fifths of the container |
|
|
247
|
+
| `mw-section-head-numbered` | Adds the running number at the right end of the rule; the browser counts, restarting per `mw-main` |
|
|
248
|
+
| `mw-section-subtitle` | Left-aligned heading with a thin secondary underline, `xl` growing to `2xl` up to 576px - the level inside a section. A paragraph right under it is treated as its lead and gets the gap to the content from the framework - no margin utility needed |
|
|
249
|
+
| `mw-section-nav` + `mw-section-btn` | Sticky single-row strip of outline-style jump links; parks under the header and scrolls sideways when it overflows |
|
|
250
250
|
|
|
251
251
|
```html
|
|
252
252
|
<section class="mw-section mw-section-alternate">
|
|
@@ -282,6 +282,12 @@ Its tokens: `--mw-section-head-gap` (space to the content below),
|
|
|
282
282
|
`--mw-section-head-pad` (rule to title), `--mw-section-head-mark-width` (80px)
|
|
283
283
|
and `--mw-section-head-mark-color`.
|
|
284
284
|
|
|
285
|
+
The first two are multiples of `--mw-section-head-step`, which is derived from
|
|
286
|
+
`--mw-section-padding-block` - so a section spacing preset moves the heads with
|
|
287
|
+
it, and the fluid preset carries them along without a ramp of its own. A head
|
|
288
|
+
with no `mw-section-head-intro` takes a smaller gap: the gap sized to follow a
|
|
289
|
+
paragraph reads as a hole under a rule and one line of type.
|
|
290
|
+
|
|
285
291
|
The strip sticks at `--mw-header-height` and is `--mw-section-nav-height` tall
|
|
286
292
|
(3.7rem). Anything it can cover on a jump needs the sum as `scroll-margin-top`;
|
|
287
293
|
a block wrapping a `mw-section-subtitle` gets that from the framework already.
|
|
@@ -335,7 +341,12 @@ width.
|
|
|
335
341
|
|
|
336
342
|
A `mw-container` that contains a `mw-hero` switches to full-bleed, full-height
|
|
337
343
|
mode with the background image from `--mw-hero-background`.
|
|
338
|
-
`mw-home-content-fade` fades the content in.
|
|
344
|
+
`mw-home-content-fade` fades the content in. `mw-home-start` puts the whole
|
|
345
|
+
block against the left container edge instead of centring it - for a hero that
|
|
346
|
+
points somewhere rather than sitting in the middle. `mw-home` carries the
|
|
347
|
+
container width itself, because the hero container runs the full width of the
|
|
348
|
+
screen; without that the hero content would start at a different edge than
|
|
349
|
+
every section below it.
|
|
339
350
|
|
|
340
351
|
The image is treated per theme through `--mw-hero-image-filter` - a filter, not
|
|
341
352
|
a tinted overlay: `$hero-filter-dark` (`brightness(0.7)`) against
|
|
@@ -489,6 +500,13 @@ row becomes as tall as the tallest instead of as tall as its own contents. For a
|
|
|
489
500
|
column of cards that should end on one line even when one of them carries an
|
|
490
501
|
extra sentence.
|
|
491
502
|
|
|
503
|
+
`mw-grid-from-sm|md|lg|xl` is the second modifier: it holds the grid at one
|
|
504
|
+
column until that breakpoint, and the grid's own ramp takes over from there.
|
|
505
|
+
Every ramp turns two-column at `sm`, and 576px is generous for running text
|
|
506
|
+
next to a picture - `mw-grid-2 mw-grid-from-md` is the pair that fixes that.
|
|
507
|
+
It also resets the `mw-reveal-stagger` cycle below the breakpoint, so two cards
|
|
508
|
+
standing above each other do not rise on different beats.
|
|
509
|
+
|
|
492
510
|
Every one of them has a `-lg` twin with a wider gap (2.5rem instead of 1.35rem):
|
|
493
511
|
`mw-grid-2-lg`, `mw-grid-3-lg`, `mw-grid-4-lg`, `mw-grid-5-lg`, `mw-grid-1-lg`,
|
|
494
512
|
`mw-grid-auto-lg`, `mw-grid-flex-lg`, `mw-grid-lg`.
|
|
@@ -543,6 +561,16 @@ applies below that. The pair `mw-d-none mw-d-md-flex` is hidden on a phone and a
|
|
|
543
561
|
row from a tablet on. `mw-hide-mobile` (gone below md) and `mw-hide-desktop`
|
|
544
562
|
(gone from md up) spell out the two everyone actually reaches for.
|
|
545
563
|
|
|
564
|
+
**Print** - the framework ships a print stylesheet, so a page that is dark on
|
|
565
|
+
screen comes out of the printer as black on white: the surface, ink, border and
|
|
566
|
+
elevation tokens are redeclared for paper, the fixed chrome (header, ribbon,
|
|
567
|
+
section nav, scroll cue, burger, theme toggle, toasts) is dropped, cards keep a
|
|
568
|
+
hairline instead of a tone, headings do not end a page and cards, rows and
|
|
569
|
+
figures are not torn across one. A link in `mw-prose` or `mw-disclaimer` that
|
|
570
|
+
points at an http(s) address prints its target after the text. `mw-hide-print`
|
|
571
|
+
takes an element off the paper, `mw-print-only` is the note that exists only
|
|
572
|
+
there. Nothing to switch on.
|
|
573
|
+
|
|
546
574
|
**Text overflow** - `mw-text-truncate` is one line ending in an ellipsis and
|
|
547
575
|
carries `min-width: 0` with it, which is the reason truncation "does not work"
|
|
548
576
|
nine times out of ten inside a flex row. `mw-text-clamp-2` through `-5` is that
|
|
@@ -83,6 +83,8 @@ Safari 16.4+, Firefox 128+. The same range is declared as `browserslist` in
|
|
|
83
83
|
| `--mw-container-gutter`, `--mw-container-width` | Page gutter of `mw-container` (fluid `clamp(1rem, 4.2vw + 0.5rem, 4rem)`, never below the safe-area inset) and the width derived from it (`min(1200px, 100% - 2 * gutter)`) |
|
|
84
84
|
| `--mw-section-padding-block` | Top/bottom rhythm of `mw-section` (3.3rem, stepping down to 2.5rem below `md` and 1.75rem below `sm`) |
|
|
85
85
|
| `--mw-section-padding-fluid` | The fluid alternative to the value above - 1.75rem on a phone up to 5.5rem at `xl`. Not applied by itself: set `--mw-section-padding-block: var(--mw-section-padding-fluid)` |
|
|
86
|
+
| `--mw-section-padding-compact`, `--mw-section-padding-airy` | The two presets, as tokens so the phone steps reach them - point `--mw-section-padding-block` at one |
|
|
87
|
+
| `--mw-section-head-step` | One step of the head rhythm, derived from `--mw-section-padding-block`. Every measure in a head and around a subtitle is a multiple of it, so a spacing preset moves them all |
|
|
86
88
|
| `--mw-section-nav-height` | Height the sticky `mw-section-nav` reserves (3.7rem). Add it to `--mw-header-height` for the `scroll-margin-top` of anything the strip can cover |
|
|
87
89
|
| `--mw-root-font-size` | Percentage the whole rem scale is built on (`100%`). Type, spacing and control heights move with it; px breakpoints do not |
|
|
88
90
|
| `--mw-calendar-dot` | Colour of a single calendar dot - set it per dot or per cell; the `mw-calendar-dot-*` classes are presets for it |
|
|
@@ -233,15 +235,17 @@ URL carries the choice - a link is how a look gets agreed on before it is built.
|
|
|
233
235
|
| `mw-density-compact` | Card and panel padding and the three control heights drop one step down the spacing scale. Type is untouched - `--mw-root-font-size` is the switch that scales everything together |
|
|
234
236
|
| `mw-density-roomy` | The same one step up |
|
|
235
237
|
|
|
236
|
-
| Property
|
|
237
|
-
|
|
|
238
|
-
| `--mw-radius-scale`
|
|
239
|
-
| `--mw-root-font-size`
|
|
240
|
-
| `--mw-font-family-heading`
|
|
241
|
-
| `--mw-container-width`
|
|
242
|
-
| `--mw-section-padding-block`
|
|
243
|
-
| `--mw-section-padding-fluid`
|
|
244
|
-
| `--mw-
|
|
238
|
+
| Property | Effect |
|
|
239
|
+
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
240
|
+
| `--mw-radius-scale` | Multiplies the whole radius scale - `0` squares everything off |
|
|
241
|
+
| `--mw-root-font-size` | Percentage on `html`. The scale is rem, so type, padding and control heights move together; breakpoints are px and stay put |
|
|
242
|
+
| `--mw-font-family-heading` | Headline typeface; body copy is untouched |
|
|
243
|
+
| `--mw-container-width` | Where the content stops growing |
|
|
244
|
+
| `--mw-section-padding-block` | Air above and below each section |
|
|
245
|
+
| `--mw-section-padding-fluid` | The same, but growing with the screen - point the line above at it |
|
|
246
|
+
| `--mw-section-padding-compact`, `--mw-section-padding-airy` | A tighter and an airier fixed rhythm - point the line above at one |
|
|
247
|
+
| `--mw-section-head-step` | Scales every gap in a section head and around a subtitle at once |
|
|
248
|
+
| `--mw-motion-scale` | Multiplies all six duration tokens - `0.6` brisk, `1.6` relaxed. `prefers-reduced-motion` still overrides it |
|
|
245
249
|
|
|
246
250
|
**Writing your own.** A variant that retunes a _theme-bound_ token - anything in
|
|
247
251
|
the dark/light maps - cannot be written on `:root` alone: `mw-theme-light`
|
|
@@ -396,6 +400,10 @@ Functions read the maps: `spacing('4')`, `font-size('lg')`,
|
|
|
396
400
|
container widths, not breakpoint names, because a container has none.
|
|
397
401
|
- `media-up($bp)` / `media-down($bp)` - the `$breakpoints` map as range syntax,
|
|
398
402
|
`width >= bp` and `width < bp`, so the two never overlap at the breakpoint.
|
|
403
|
+
`media-up` is the direction the framework is written in: the base block is the
|
|
404
|
+
phone and each breakpoint adds to it. `media-down` is for a rule that sets what
|
|
405
|
+
the base never sets - turned around it would hard-wire an inherited value - and
|
|
406
|
+
for a narrow layout that costs more properties than the wide one.
|
|
399
407
|
- `touch-context($bp: 'md')` - coarse pointer _or_ narrow viewport. Every
|
|
400
408
|
target-size rule in the framework hangs under it; put your own control under
|
|
401
409
|
the same condition instead of guessing it.
|
|
@@ -440,7 +448,7 @@ Give it a layer of its own:
|
|
|
440
448
|
|
|
441
449
|
## Importing only what you need
|
|
442
450
|
|
|
443
|
-
The full stylesheet is ~
|
|
451
|
+
The full stylesheet is ~290 kB raw / ~41 kB gzipped. Marketing components
|
|
444
452
|
(`blog-post`, `gallery`, `content-slider`, `techstack-bucket`, `tiles`,
|
|
445
453
|
`coming-soon`, `ratings`, `home`, `hero`) are dead weight in an application, and
|
|
446
454
|
Angular bundle budgets notice.
|
|
@@ -452,6 +460,22 @@ colourless. The cascade layer order comes along on its own: every module loads
|
|
|
452
460
|
`abstracts`, which declares it, so a hand-picked subset orders itself the same
|
|
453
461
|
way the full build does.
|
|
454
462
|
|
|
463
|
+
**The short way is `main-lean`**: the whole framework minus every component -
|
|
464
|
+
tokens, reset, typography, the complete layout and all utilities, ~98 kB raw /
|
|
465
|
+
~16 kB gzipped. Configure it like `main` and add the components next to it:
|
|
466
|
+
|
|
467
|
+
```scss
|
|
468
|
+
@use 'maverick-wave/src/scss/main-lean' with (
|
|
469
|
+
$primary-color: #0f766e
|
|
470
|
+
);
|
|
471
|
+
@use 'maverick-wave/src/scss/components/buttons';
|
|
472
|
+
@use 'maverick-wave/src/scss/components/cards';
|
|
473
|
+
@use 'maverick-wave/src/scss/components/alerts';
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Those three land at ~19 kB gzipped against ~41 kB for the full build. Pick the
|
|
477
|
+
files by hand, as below, when you also want to leave parts of the layout out.
|
|
478
|
+
|
|
455
479
|
```scss
|
|
456
480
|
// styles.scss - configure first, then pick
|
|
457
481
|
@use 'maverick-wave/src/scss/abstracts/variables' with (
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ Patch releases are only for test purposes - here I only document major and minor
|
|
|
6
6
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
7
7
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
8
|
|
|
9
|
+
## [5.26.0] - 2026-09-20
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Spacing
|
|
14
|
+
|
|
15
|
+
## [5.25.0] - 2026-09-20
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- print stylesheet
|
|
20
|
+
- `main-lean` entry point
|
|
21
|
+
- `mw-home-start` for a hero at the left container edge
|
|
22
|
+
- `mw-grid-from-*` keeps a grid single column up to that breakpoint
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- more "mobile first" design
|
|
27
|
+
- `mw-home` carries the container width
|
|
28
|
+
|
|
9
29
|
## [5.24.0] - 2026-09-20
|
|
10
30
|
|
|
11
31
|
### Changed
|
package/CLAUDE.md
CHANGED
|
@@ -36,6 +36,10 @@ There are no test or lint scripts.
|
|
|
36
36
|
- `utilities/` - Spacing, flex, display utility classes
|
|
37
37
|
- `main.scss` - Entry point using `@use`/`@forward` (not `@import`)
|
|
38
38
|
|
|
39
|
+
**Mobile-first** - The unprefixed block is the phone layout; `media-up($bp)` adds
|
|
40
|
+
to it. `media-down($bp)` only for rules that set what the base never sets, or
|
|
41
|
+
where the narrow layout costs more properties than the wide one.
|
|
42
|
+
|
|
39
43
|
**JavaScript** (`src/js/main.js`) - Single file. All components auto-initialize on `DOMContentLoaded`. Includes: gallery and image sliders, theme toggle (persisted to localStorage, transitions suppressed during the flip), accordion, mobile nav, progress bar (IntersectionObserver), scroll spy, tabs (which also get their ARIA and arrow-key handling here), alerts/toasts, modals, range inputs, dropdowns, language switcher, checkbox lists, kanban board, calendar.
|
|
40
44
|
|
|
41
45
|
**HTML showcase** (`index.html` + `src/partials/`) - The top-level `index.html` uses `@@include()` syntax to pull in 63 partials from `src/partials/`. These compile into `dist/index.html`.
|
package/README.md
CHANGED
|
@@ -45,12 +45,12 @@ The result is a framework that balances utility with simplicity, offering develo
|
|
|
45
45
|
<title>My MaverickWave Project</title>
|
|
46
46
|
<link
|
|
47
47
|
rel="stylesheet"
|
|
48
|
-
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
48
|
+
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.26.0/maverick-wave.min.css"
|
|
49
49
|
/>
|
|
50
50
|
</head>
|
|
51
51
|
<body>
|
|
52
52
|
<!-- Your content here -->
|
|
53
|
-
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
53
|
+
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.26.0/maverick-wave.min.js"></script>
|
|
54
54
|
</body>
|
|
55
55
|
</html>
|
|
56
56
|
```
|
|
@@ -437,6 +437,8 @@ They exist on the SCSS path only - the compiled CSS carries none of them.
|
|
|
437
437
|
ignores the reader's font size. The default range stops at `md`, a headline
|
|
438
438
|
passes `$to: 'xl'`.
|
|
439
439
|
- `media-up($bp)` / `media-down($bp)` - the `$breakpoints` map as a query.
|
|
440
|
+
`media-up` is the direction the framework is written in: the base block is the
|
|
441
|
+
phone, each breakpoint adds to it.
|
|
440
442
|
- `touch-context($bp: 'md')` - coarse pointer _or_ narrow viewport, the condition
|
|
441
443
|
every target-size rule in the framework hangs under.
|
|
442
444
|
- `touch-floor($size: 2.75rem)` - that condition plus a `min-height`. Not for a
|
package/index.html
CHANGED
|
@@ -25,6 +25,19 @@
|
|
|
25
25
|
cached: the filename never changes, and without it a stale stylesheet
|
|
26
26
|
survives a normal reload -->
|
|
27
27
|
<link rel="stylesheet" href="maverick-wave.min.css?v={{VERSION}}" />
|
|
28
|
+
|
|
29
|
+
<!-- Applies a stored theme choice before the first paint. Without it a
|
|
30
|
+
reader whose choice differs from the OS sees the other theme for a
|
|
31
|
+
frame, because main.js only runs at the end of the body. Inline and
|
|
32
|
+
synchronous on purpose - an external file would paint first. -->
|
|
33
|
+
<script>
|
|
34
|
+
(function () {
|
|
35
|
+
var stored = localStorage.getItem('mw-theme');
|
|
36
|
+
if (stored === 'light' || stored === 'dark') {
|
|
37
|
+
document.documentElement.classList.add('mw-theme-' + stored);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
</script>
|
|
28
41
|
<!-- Favicons -->
|
|
29
42
|
<link rel="icon" type="image/svg+xml" href="favicon/favicon.svg" />
|
|
30
43
|
<link
|