maverick-wave 5.23.0 → 5.25.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 +37 -9
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +22 -14
- 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 +48 -6
- package/.claude/skills/mw-maverick-wave/references/theming.md +21 -1
- package/CHANGELOG.md +20 -0
- package/CLAUDE.md +4 -0
- package/README.md +4 -2
- package/index.html +75 -38
- package/maverick-wave.min.css +5 -5
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/src/js/main.js +149 -57
- package/src/partials/get-started-container.html +5 -10
- package/src/partials/highlights-container.html +7 -5
- package/src/partials/input-group-container.html +1 -3
- package/src/partials/page-header-container.html +2 -2
- package/src/partials/section-head-container.html +74 -0
- package/src/partials/tags-container.html +0 -6
- package/src/scss/base/_base.scss +6 -1
- 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 +10 -7
- package/src/scss/layout/_page-header.scss +4 -4
- package/src/scss/layout/_section.scss +117 -47
- package/src/scss/main-lean.scss +16 -0
- package/src/scss/utilities/_index.scss +1 -0
- package/src/scss/utilities/_print.scss +107 -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
|
|
@@ -156,9 +172,9 @@ keys at all (negative gap is invalid CSS and is not generated).
|
|
|
156
172
|
**Font sizes** (`mw-text-3xs` … `mw-text-6xl`): `3xs` 0.6, `2xs` 0.7, `xs` 0.8,
|
|
157
173
|
`sm` 0.9, `base` 1, `md` 1.1, `lg` 1.3, `xl` 1.5, `2xl` 1.8, `3xl` 2.2, `4xl` 2.5,
|
|
158
174
|
`5xl` 3, `6xl` 4.3 rem. The utility classes are single steps; `h1`, `h2`,
|
|
159
|
-
`mw-section-title` and `mw-section-subtitle` interpolate instead - `h1`
|
|
160
|
-
`3xl` to `5xl` between 375px and 768px, `h2` `2xl` to `4xl`, the
|
|
161
|
-
|
|
175
|
+
`mw-section-head-title` and `mw-section-subtitle` interpolate instead - `h1`
|
|
176
|
+
runs `3xl` to `5xl` between 375px and 768px, `h2` `2xl` to `4xl`, the head title
|
|
177
|
+
`2xl` to `4xl` up to 992px and the subtitle one step up to 576px. The endpoints are the values the old
|
|
162
178
|
breakpoint steps had, so a phone and a desktop look the same and only the widths
|
|
163
179
|
between them moved.
|
|
164
180
|
|
|
@@ -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`.
|
|
@@ -297,8 +319,9 @@ feature frame) ·
|
|
|
297
319
|
|
|
298
320
|
**Layout** (`references/layout.md`) `mw-main` · `mw-container` (+ `-narrow`) ·
|
|
299
321
|
`mw-content` ·
|
|
300
|
-
`mw-section`
|
|
301
|
-
|
|
322
|
+
`mw-section` · `mw-section-head` (+ `-title`, `-intro`, `-numbered`, colours) ·
|
|
323
|
+
`mw-page-header` · `mw-grid-*`
|
|
324
|
+
(+ `mw-grid-even`, `mw-grid-from-{sm,md,lg,xl}`) ·
|
|
302
325
|
`mw-columns-2/3` · `mw-row-split` · `mw-hero` (+ `mw-scroll-hint`, `-end`) ·
|
|
303
326
|
`mw-parallax` (+ `-media`, `-content`, `-dimmed`, `-sticky`, `-rise`,
|
|
304
327
|
`-slow`, `-pattern`) · `mw-footer`
|
|
@@ -311,7 +334,7 @@ feature frame) ·
|
|
|
311
334
|
`mw-glow-{primary,secondary,info,success,warning,danger}` ·
|
|
312
335
|
`mw-corner-plain` ·
|
|
313
336
|
`mw-aspect-square|video|wide|portrait|photo` · `mw-d-{sm,md,lg,xl}-*` /
|
|
314
|
-
`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` ·
|
|
315
338
|
`mw-reveal` / `mw-reveal-stagger` · spacing, flex, display, text
|
|
316
339
|
|
|
317
340
|
## Pitfalls
|
|
@@ -476,13 +499,18 @@ feature frame) ·
|
|
|
476
499
|
directly after the block, so the overlap reads as a surface and not a cut.
|
|
477
500
|
It sits at `:where()` weight, so a plain `box-shadow` of your own on that
|
|
478
501
|
section replaces it.
|
|
479
|
-
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
|
|
480
508
|
gutter, the mobile nav panel and the modal padding all budget for the
|
|
481
509
|
cutout with `env(safe-area-inset-*)`, and iOS resolves every one of those
|
|
482
510
|
to `0` without it - on a notched phone the content then sits under the
|
|
483
511
|
rounded corner. Nothing errors, which is why the shipped JS writes a
|
|
484
512
|
console warning on localhost when the meta is missing.
|
|
485
|
-
|
|
513
|
+
32. **Half the layout reads its own width, not the viewport.** `mw-card`,
|
|
486
514
|
`mw-tile`, `mw-stepper`, both timelines and - since 5.13.0 -
|
|
487
515
|
`mw-gallery-container` and `mw-image-slider` are `@container` queries, so
|
|
488
516
|
any of them in a half-width column takes its narrow layout there while the
|
|
@@ -143,11 +143,13 @@ accordion FAQ.
|
|
|
143
143
|
<!-- Features -->
|
|
144
144
|
<section id="features" class="mw-section mw-section-alternate">
|
|
145
145
|
<div class="mw-container">
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
146
|
+
<div class="mw-section-head">
|
|
147
|
+
<h2 class="mw-section-head-title">Features</h2>
|
|
148
|
+
<p class="mw-section-head-intro">
|
|
149
|
+
Three things every team asks about on the first call - and the
|
|
150
|
+
numbers behind them.
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
151
153
|
|
|
152
154
|
<!-- mw-reveal-stagger on the grid: every card rises as it scrolls
|
|
153
155
|
in, the second and third of each row a beat later -->
|
|
@@ -217,10 +219,12 @@ accordion FAQ.
|
|
|
217
219
|
<!-- Pricing -->
|
|
218
220
|
<section id="pricing" class="mw-section">
|
|
219
221
|
<div class="mw-container">
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
<div class="mw-section-head">
|
|
223
|
+
<h2 class="mw-section-head-title">Pricing</h2>
|
|
224
|
+
<p class="mw-section-head-intro">
|
|
225
|
+
Per workspace, per month. Every plan starts with a 14 day trial.
|
|
226
|
+
</p>
|
|
227
|
+
</div>
|
|
224
228
|
|
|
225
229
|
<!-- mw-offer pushes the price row to the bottom of the body, so the
|
|
226
230
|
three prices line up although the lists differ in length. The
|
|
@@ -316,10 +320,12 @@ accordion FAQ.
|
|
|
316
320
|
<!-- Voices -->
|
|
317
321
|
<section id="voices" class="mw-section mw-section-alternate">
|
|
318
322
|
<div class="mw-container">
|
|
319
|
-
<
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
+
<div class="mw-section-head">
|
|
324
|
+
<h2 class="mw-section-head-title">Voices</h2>
|
|
325
|
+
<p class="mw-section-head-intro">
|
|
326
|
+
What teams say after the first quarter.
|
|
327
|
+
</p>
|
|
328
|
+
</div>
|
|
323
329
|
|
|
324
330
|
<!-- Quotes of unequal length: columns, not a grid. The stagger
|
|
325
331
|
works on the column children just the same -->
|
|
@@ -367,7 +373,9 @@ accordion FAQ.
|
|
|
367
373
|
<!-- FAQ -->
|
|
368
374
|
<section id="faq" class="mw-section">
|
|
369
375
|
<div class="mw-container">
|
|
370
|
-
<
|
|
376
|
+
<div class="mw-section-head">
|
|
377
|
+
<h2 class="mw-section-head-title">FAQ</h2>
|
|
378
|
+
</div>
|
|
371
379
|
|
|
372
380
|
<div class="mw-accordion">
|
|
373
381
|
<div class="mw-accordion-item">
|
|
@@ -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 |
|
|
@@ -241,15 +241,22 @@ pointing at the trigger in every combination.
|
|
|
241
241
|
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
242
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-fluid` for spacing that grows with the screen |
|
|
243
243
|
| `mw-section-alternate` | Diagonal pattern background; combine with `mw-section` |
|
|
244
|
-
| `mw-section-
|
|
245
|
-
| `mw-section-
|
|
246
|
-
| `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 |
|
|
247
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 |
|
|
248
250
|
|
|
249
251
|
```html
|
|
250
252
|
<section class="mw-section mw-section-alternate">
|
|
251
253
|
<div class="mw-container">
|
|
252
|
-
<
|
|
254
|
+
<div class="mw-section-head mw-section-head-numbered">
|
|
255
|
+
<h2 class="mw-section-head-title">Components</h2>
|
|
256
|
+
<p class="mw-section-head-intro">
|
|
257
|
+
The everyday parts - buttons, tags, alerts and their many friends.
|
|
258
|
+
</p>
|
|
259
|
+
</div>
|
|
253
260
|
<nav class="mw-section-nav">
|
|
254
261
|
<a href="#buttons" class="mw-section-btn"
|
|
255
262
|
><i class="fas fa-hand-pointer"></i> Buttons</a
|
|
@@ -262,13 +269,26 @@ pointing at the trigger in every combination.
|
|
|
262
269
|
</section>
|
|
263
270
|
```
|
|
264
271
|
|
|
272
|
+
**Why the head is left-aligned and has no centred variant.** Centred running
|
|
273
|
+
text moves its own left edge with every line break, so the eye has to find the
|
|
274
|
+
start of each line instead of returning to a fixed position - unnoticeable over
|
|
275
|
+
two lines, tiring from the third or fourth on. Aligned, the title, the lead and
|
|
276
|
+
the content below share one edge, and that shared edge is what makes a band of
|
|
277
|
+
elements read as one section. A hero, a single call to action or a caption is
|
|
278
|
+
short enough to centre; a section head is not, so the framework does not offer
|
|
279
|
+
the choice.
|
|
280
|
+
|
|
281
|
+
Its tokens: `--mw-section-head-gap` (space to the content below),
|
|
282
|
+
`--mw-section-head-pad` (rule to title), `--mw-section-head-mark-width` (80px)
|
|
283
|
+
and `--mw-section-head-mark-color`.
|
|
284
|
+
|
|
265
285
|
The strip sticks at `--mw-header-height` and is `--mw-section-nav-height` tall
|
|
266
286
|
(3.7rem). Anything it can cover on a jump needs the sum as `scroll-margin-top`;
|
|
267
287
|
a block wrapping a `mw-section-subtitle` gets that from the framework already.
|
|
268
288
|
|
|
269
289
|
## Page header
|
|
270
290
|
|
|
271
|
-
The application counterpart to `mw-section-
|
|
291
|
+
The application counterpart to `mw-section-head`: title and subtitle left,
|
|
272
292
|
actions right, wrapping when it gets tight. Below `sm` the actions take the full
|
|
273
293
|
width.
|
|
274
294
|
|
|
@@ -315,7 +335,12 @@ width.
|
|
|
315
335
|
|
|
316
336
|
A `mw-container` that contains a `mw-hero` switches to full-bleed, full-height
|
|
317
337
|
mode with the background image from `--mw-hero-background`.
|
|
318
|
-
`mw-home-content-fade` fades the content in.
|
|
338
|
+
`mw-home-content-fade` fades the content in. `mw-home-start` puts the whole
|
|
339
|
+
block against the left container edge instead of centring it - for a hero that
|
|
340
|
+
points somewhere rather than sitting in the middle. `mw-home` carries the
|
|
341
|
+
container width itself, because the hero container runs the full width of the
|
|
342
|
+
screen; without that the hero content would start at a different edge than
|
|
343
|
+
every section below it.
|
|
319
344
|
|
|
320
345
|
The image is treated per theme through `--mw-hero-image-filter` - a filter, not
|
|
321
346
|
a tinted overlay: `$hero-filter-dark` (`brightness(0.7)`) against
|
|
@@ -469,6 +494,13 @@ row becomes as tall as the tallest instead of as tall as its own contents. For a
|
|
|
469
494
|
column of cards that should end on one line even when one of them carries an
|
|
470
495
|
extra sentence.
|
|
471
496
|
|
|
497
|
+
`mw-grid-from-sm|md|lg|xl` is the second modifier: it holds the grid at one
|
|
498
|
+
column until that breakpoint, and the grid's own ramp takes over from there.
|
|
499
|
+
Every ramp turns two-column at `sm`, and 576px is generous for running text
|
|
500
|
+
next to a picture - `mw-grid-2 mw-grid-from-md` is the pair that fixes that.
|
|
501
|
+
It also resets the `mw-reveal-stagger` cycle below the breakpoint, so two cards
|
|
502
|
+
standing above each other do not rise on different beats.
|
|
503
|
+
|
|
472
504
|
Every one of them has a `-lg` twin with a wider gap (2.5rem instead of 1.35rem):
|
|
473
505
|
`mw-grid-2-lg`, `mw-grid-3-lg`, `mw-grid-4-lg`, `mw-grid-5-lg`, `mw-grid-1-lg`,
|
|
474
506
|
`mw-grid-auto-lg`, `mw-grid-flex-lg`, `mw-grid-lg`.
|
|
@@ -523,6 +555,16 @@ applies below that. The pair `mw-d-none mw-d-md-flex` is hidden on a phone and a
|
|
|
523
555
|
row from a tablet on. `mw-hide-mobile` (gone below md) and `mw-hide-desktop`
|
|
524
556
|
(gone from md up) spell out the two everyone actually reaches for.
|
|
525
557
|
|
|
558
|
+
**Print** - the framework ships a print stylesheet, so a page that is dark on
|
|
559
|
+
screen comes out of the printer as black on white: the surface, ink, border and
|
|
560
|
+
elevation tokens are redeclared for paper, the fixed chrome (header, ribbon,
|
|
561
|
+
section nav, scroll cue, burger, theme toggle, toasts) is dropped, cards keep a
|
|
562
|
+
hairline instead of a tone, headings do not end a page and cards, rows and
|
|
563
|
+
figures are not torn across one. A link in `mw-prose` or `mw-disclaimer` that
|
|
564
|
+
points at an http(s) address prints its target after the text. `mw-hide-print`
|
|
565
|
+
takes an element off the paper, `mw-print-only` is the note that exists only
|
|
566
|
+
there. Nothing to switch on.
|
|
567
|
+
|
|
526
568
|
**Text overflow** - `mw-text-truncate` is one line ending in an ellipsis and
|
|
527
569
|
carries `min-width: 0` with it, which is the reason truncation "does not work"
|
|
528
570
|
nine times out of ten inside a flex row. `mw-text-clamp-2` through `-5` is that
|
|
@@ -396,6 +396,10 @@ Functions read the maps: `spacing('4')`, `font-size('lg')`,
|
|
|
396
396
|
container widths, not breakpoint names, because a container has none.
|
|
397
397
|
- `media-up($bp)` / `media-down($bp)` - the `$breakpoints` map as range syntax,
|
|
398
398
|
`width >= bp` and `width < bp`, so the two never overlap at the breakpoint.
|
|
399
|
+
`media-up` is the direction the framework is written in: the base block is the
|
|
400
|
+
phone and each breakpoint adds to it. `media-down` is for a rule that sets what
|
|
401
|
+
the base never sets - turned around it would hard-wire an inherited value - and
|
|
402
|
+
for a narrow layout that costs more properties than the wide one.
|
|
399
403
|
- `touch-context($bp: 'md')` - coarse pointer _or_ narrow viewport. Every
|
|
400
404
|
target-size rule in the framework hangs under it; put your own control under
|
|
401
405
|
the same condition instead of guessing it.
|
|
@@ -440,7 +444,7 @@ Give it a layer of its own:
|
|
|
440
444
|
|
|
441
445
|
## Importing only what you need
|
|
442
446
|
|
|
443
|
-
The full stylesheet is ~
|
|
447
|
+
The full stylesheet is ~290 kB raw / ~41 kB gzipped. Marketing components
|
|
444
448
|
(`blog-post`, `gallery`, `content-slider`, `techstack-bucket`, `tiles`,
|
|
445
449
|
`coming-soon`, `ratings`, `home`, `hero`) are dead weight in an application, and
|
|
446
450
|
Angular bundle budgets notice.
|
|
@@ -452,6 +456,22 @@ colourless. The cascade layer order comes along on its own: every module loads
|
|
|
452
456
|
`abstracts`, which declares it, so a hand-picked subset orders itself the same
|
|
453
457
|
way the full build does.
|
|
454
458
|
|
|
459
|
+
**The short way is `main-lean`**: the whole framework minus every component -
|
|
460
|
+
tokens, reset, typography, the complete layout and all utilities, ~98 kB raw /
|
|
461
|
+
~16 kB gzipped. Configure it like `main` and add the components next to it:
|
|
462
|
+
|
|
463
|
+
```scss
|
|
464
|
+
@use 'maverick-wave/src/scss/main-lean' with (
|
|
465
|
+
$primary-color: #0f766e
|
|
466
|
+
);
|
|
467
|
+
@use 'maverick-wave/src/scss/components/buttons';
|
|
468
|
+
@use 'maverick-wave/src/scss/components/cards';
|
|
469
|
+
@use 'maverick-wave/src/scss/components/alerts';
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Those three land at ~19 kB gzipped against ~41 kB for the full build. Pick the
|
|
473
|
+
files by hand, as below, when you also want to leave parts of the layout out.
|
|
474
|
+
|
|
455
475
|
```scss
|
|
456
476
|
// styles.scss - configure first, then pick
|
|
457
477
|
@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.25.0] - 2026-09-20
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- print stylesheet
|
|
14
|
+
- `main-lean` entry point
|
|
15
|
+
- `mw-home-start` for a hero at the left container edge
|
|
16
|
+
- `mw-grid-from-*` keeps a grid single column up to that breakpoint
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- more "mobile first" design
|
|
21
|
+
- `mw-home` carries the container width
|
|
22
|
+
|
|
23
|
+
## [5.24.0] - 2026-09-20
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- section header overhaul
|
|
28
|
+
|
|
9
29
|
## [5.23.0] - 2026-09-20
|
|
10
30
|
|
|
11
31
|
### Added
|
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.25.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.25.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
|