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.
Files changed (38) hide show
  1. package/.claude/skills/mw-maverick-wave/SKILL.md +37 -9
  2. package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +22 -14
  3. package/.claude/skills/mw-maverick-wave/references/components.md +4 -0
  4. package/.claude/skills/mw-maverick-wave/references/javascript.md +44 -8
  5. package/.claude/skills/mw-maverick-wave/references/layout.md +48 -6
  6. package/.claude/skills/mw-maverick-wave/references/theming.md +21 -1
  7. package/CHANGELOG.md +20 -0
  8. package/CLAUDE.md +4 -0
  9. package/README.md +4 -2
  10. package/index.html +75 -38
  11. package/maverick-wave.min.css +5 -5
  12. package/maverick-wave.min.js +1 -1
  13. package/package.json +2 -2
  14. package/src/js/main.js +149 -57
  15. package/src/partials/get-started-container.html +5 -10
  16. package/src/partials/highlights-container.html +7 -5
  17. package/src/partials/input-group-container.html +1 -3
  18. package/src/partials/page-header-container.html +2 -2
  19. package/src/partials/section-head-container.html +74 -0
  20. package/src/partials/tags-container.html +0 -6
  21. package/src/scss/base/_base.scss +6 -1
  22. package/src/scss/components/_blog-post.scss +15 -10
  23. package/src/scss/components/_button-bar.scss +10 -6
  24. package/src/scss/components/_code.scss +23 -34
  25. package/src/scss/components/_info.scss +8 -1
  26. package/src/scss/components/_kanban.scss +6 -6
  27. package/src/scss/components/_meta-info.scss +7 -6
  28. package/src/scss/components/_tables.scss +6 -4
  29. package/src/scss/components/_tiles.scss +20 -30
  30. package/src/scss/layout/_grid.scss +28 -0
  31. package/src/scss/layout/_header.scss +16 -9
  32. package/src/scss/layout/_home.scss +21 -2
  33. package/src/scss/layout/_main.scss +10 -7
  34. package/src/scss/layout/_page-header.scss +4 -4
  35. package/src/scss/layout/_section.scss +117 -47
  36. package/src/scss/main-lean.scss +16 -0
  37. package/src/scss/utilities/_index.scss +1 -0
  38. package/src/scss/utilities/_print.scss +107 -0
@@ -98,7 +98,6 @@
98
98
  type="button"
99
99
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
100
100
  aria-label="Remove filter: active"
101
- onclick="this.closest('.mw-tags-item').remove()"
102
101
  >
103
102
  <i class="fas fa-times"></i>
104
103
  </button>
@@ -141,7 +140,6 @@
141
140
  type="button"
142
141
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
143
142
  aria-label="Remove React"
144
- onclick="this.closest('.mw-tags-item').remove()"
145
143
  >
146
144
  <i class="fas fa-times"></i>
147
145
  </button>
@@ -152,7 +150,6 @@
152
150
  type="button"
153
151
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
154
152
  aria-label="Remove Vue.js"
155
- onclick="this.closest('.mw-tags-item').remove()"
156
153
  >
157
154
  <i class="fas fa-times"></i>
158
155
  </button>
@@ -167,7 +164,6 @@
167
164
  type="button"
168
165
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
169
166
  aria-label="Remove Online"
170
- onclick="this.closest('.mw-tags-item').remove()"
171
167
  >
172
168
  <i class="fas fa-times"></i>
173
169
  </button>
@@ -178,7 +174,6 @@
178
174
  type="button"
179
175
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
180
176
  aria-label="Remove Available"
181
- onclick="this.closest('.mw-tags-item').remove()"
182
177
  >
183
178
  <i class="fas fa-times"></i>
184
179
  </button>
@@ -193,7 +188,6 @@
193
188
  type="button"
194
189
  class="mw-btn-mini mw-btn-mini-danger mw-tags-remove"
195
190
  aria-label="Remove Filter: Architecture"
196
- onclick="this.closest('.mw-tags-item').remove()"
197
191
  >
198
192
  <i class="fas fa-times"></i>
199
193
  </button>
@@ -159,7 +159,12 @@
159
159
  // Point `--mw-section-padding-block` at it to switch a page over - a choice
160
160
  // like the presets are, not the default.
161
161
  --mw-section-padding-fluid: #{fluid(spacing('7'), spacing('12'), $to: 'xl')};
162
- --mw-section-title-gap: #{spacing('7')};
162
+ // The section head: the gap it leaves to the content below, the space
163
+ // between its rule and the title, and the mark sitting on that rule.
164
+ --mw-section-head-gap: #{spacing('10')};
165
+ --mw-section-head-pad: #{spacing('6')};
166
+ --mw-section-head-mark-width: 80px;
167
+ --mw-section-head-mark-color: var(--mw-primary-color);
163
168
  --mw-scroll-hint-offset: #{spacing('9')};
164
169
  --mw-scroll-hint-inline: var(--mw-container-gutter);
165
170
  --mw-scroll-hint-reserve: #{spacing('10')};
@@ -98,17 +98,20 @@
98
98
  &-meta {
99
99
  display: flex;
100
100
  flex-wrap: wrap;
101
- align-items: center;
101
+ flex-direction: column;
102
+ align-items: start;
103
+ gap: spacing('2');
104
+ margin-top: spacing('5');
102
105
  margin-bottom: spacing('6');
103
106
  font-size: font-size('sm');
104
107
  color: var(--mw-text-muted-color);
105
- row-gap: spacing('1');
106
108
 
107
- @include media-down('sm') {
108
- flex-direction: column;
109
- gap: spacing('2');
110
- margin-top: spacing('5');
111
- align-items: start;
109
+ @include media-up('sm') {
110
+ flex-direction: row;
111
+ align-items: center;
112
+ column-gap: normal;
113
+ row-gap: spacing('1');
114
+ margin-top: spacing('0');
112
115
  }
113
116
 
114
117
  &-item {
@@ -262,12 +265,14 @@
262
265
  padding-top: spacing('4');
263
266
  border-top: 1px solid var(--mw-secondary-text-color);
264
267
  display: flex;
268
+ flex-direction: column;
269
+ gap: spacing('2');
265
270
  justify-content: space-between;
266
271
  align-items: center;
267
272
 
268
- @include media-down('sm') {
269
- flex-direction: column;
270
- gap: spacing('2');
273
+ @include media-up('sm') {
274
+ flex-direction: row;
275
+ gap: normal;
271
276
  }
272
277
 
273
278
  &-button {
@@ -3,7 +3,8 @@
3
3
  @layer mw.components {
4
4
  .mw-button-bar {
5
5
  display: flex;
6
- gap: spacing('3');
6
+ flex-direction: column;
7
+ gap: spacing('2');
7
8
  align-items: center;
8
9
  justify-content: center;
9
10
  flex-wrap: wrap;
@@ -11,17 +12,20 @@
11
12
  border-radius: radius('md');
12
13
  padding: spacing('2');
13
14
 
15
+ .mw-btn {
16
+ width: 100%;
17
+ }
18
+
14
19
  &:hover {
15
20
  border-color: var(--mw-border-accent);
16
21
  }
17
22
 
18
- @include media-down('sm') {
19
- flex-direction: column;
20
- gap: spacing('2');
23
+ @include media-up('sm') {
24
+ flex-direction: row;
25
+ gap: spacing('3');
21
26
 
22
27
  .mw-btn {
23
- width: 100%;
24
- min-width: 0;
28
+ width: auto;
25
29
  }
26
30
  }
27
31
  }
@@ -42,15 +42,15 @@
42
42
  white-space: pre-wrap;
43
43
  display: block;
44
44
  line-height: 1.5;
45
+ font-size: font-size('3xs');
45
46
 
46
- @include media-down('sm') {
47
+ @include media-up('xs') {
47
48
  font-size: font-size('2xs');
48
- white-space: pre-wrap;
49
- word-break: break-word;
50
49
  }
51
50
 
52
- @include media-down('xs') {
53
- font-size: font-size('3xs');
51
+ // Back to the shared `code, pre` size
52
+ @include media-up('sm') {
53
+ font-size: font-size('xs');
54
54
  }
55
55
  }
56
56
  }
@@ -80,10 +80,13 @@
80
80
  &-filename {
81
81
  font-weight: font-weight('medium');
82
82
  margin-right: spacing('2');
83
+ font-size: font-size('2xs');
84
+ // The header wraps at this width, so the language chip needs its own line
85
+ margin-bottom: spacing('1');
83
86
 
84
- @include media-down('sm') {
85
- font-size: font-size('2xs');
86
- margin-bottom: spacing('1');
87
+ @include media-up('sm') {
88
+ font-size: font-size('xs');
89
+ margin-bottom: spacing('0');
87
90
  }
88
91
  }
89
92
 
@@ -102,19 +105,16 @@
102
105
  border: none;
103
106
  max-width: 100%;
104
107
  overflow-x: auto;
108
+ font-size: font-size('3xs');
109
+ padding: spacing('1');
105
110
 
106
- @include media-down('sm') {
111
+ @include media-up('xs') {
107
112
  font-size: font-size('2xs');
108
- padding: spacing('1');
109
-
110
- code {
111
- white-space: pre-wrap;
112
- word-break: break-word;
113
- }
114
113
  }
115
114
 
116
- @include media-down('xs') {
117
- font-size: font-size('3xs');
115
+ @include media-up('sm') {
116
+ font-size: font-size('xs');
117
+ padding: spacing('4');
118
118
  }
119
119
  }
120
120
  }
@@ -213,18 +213,6 @@
213
213
  overflow-x: auto;
214
214
  position: relative;
215
215
 
216
- // Add horizontal scrolling indicator for small screens
217
- @include media-down('sm') {
218
- background-position:
219
- left center,
220
- right center;
221
- background-repeat: no-repeat;
222
- background-size:
223
- 20px 100%,
224
- 20px 100%;
225
- background-attachment: local, local;
226
- }
227
-
228
216
  & > * {
229
217
  max-width: 100%;
230
218
  }
@@ -234,14 +222,15 @@
234
222
  width: 100%;
235
223
 
236
224
  pre {
237
- white-space: pre;
225
+ white-space: pre-wrap;
226
+ word-break: break-word;
238
227
  width: 100%;
239
228
  overflow-x: auto;
240
229
 
241
- // For very small screens, allow wrapping
242
- @include media-down('xs') {
243
- white-space: pre-wrap;
244
- word-break: break-word;
230
+ // From here the box can scroll a long line instead of splitting it
231
+ @include media-up('xs') {
232
+ white-space: pre;
233
+ word-break: normal;
245
234
  }
246
235
  }
247
236
 
@@ -63,7 +63,9 @@
63
63
  align-items: flex-start;
64
64
  width: 100%;
65
65
  max-width: 68ch;
66
- margin-inline: auto;
66
+ // Left, like everything else that carries running text. It used to centre
67
+ // itself, which only ever matched a page whose headings were centred too.
68
+ margin-inline: 0;
67
69
  padding: spacing('6') spacing('7');
68
70
  font-weight: font-weight('normal');
69
71
  line-height: 1.7;
@@ -78,6 +80,11 @@
78
80
  transform: none;
79
81
  }
80
82
 
83
+ // For the page that does centre its blocks
84
+ &-center {
85
+ margin-inline: auto;
86
+ }
87
+
81
88
  strong {
82
89
  margin-bottom: spacing('2');
83
90
  }
@@ -67,15 +67,15 @@
67
67
  auto-fit,
68
68
  minmax(min(#{$_mw-kanban-lane-min}, 100%), 1fr)
69
69
  );
70
- gap: spacing('4');
71
- padding: spacing('4');
70
+ // Frame only - how tight the board sits on a phone is a viewport call
71
+ gap: spacing('3');
72
+ padding: spacing('3');
72
73
  background: var(--mw-kanban-background);
73
74
  border-radius: radius('md');
74
75
 
75
- // Frame only - how tight the board sits on a phone is a viewport call
76
- @include media-down('sm') {
77
- gap: spacing('3');
78
- padding: spacing('3');
76
+ @include media-up('sm') {
77
+ gap: spacing('4');
78
+ padding: spacing('4');
79
79
  }
80
80
  }
81
81
 
@@ -9,13 +9,14 @@
9
9
  display: flex;
10
10
  flex-wrap: wrap;
11
11
  align-items: center;
12
- justify-content: flex-end;
13
- row-gap: spacing('1');
12
+ justify-content: flex-start;
13
+ column-gap: spacing('6');
14
+ row-gap: spacing('2');
14
15
 
15
- @include media-down('sm') {
16
- justify-content: flex-start;
17
- column-gap: spacing('6');
18
- row-gap: spacing('2');
16
+ @include media-up('sm') {
17
+ justify-content: flex-end;
18
+ column-gap: normal;
19
+ row-gap: spacing('1');
19
20
  }
20
21
  }
21
22
 
@@ -10,7 +10,8 @@
10
10
 
11
11
  th,
12
12
  td {
13
- padding: spacing('3') spacing('4');
13
+ padding: spacing('2') spacing('3');
14
+ font-size: font-size('xs');
14
15
  text-align: left;
15
16
  border: 1px solid var(--mw-border);
16
17
  color: var(--mw-text-muted-color);
@@ -40,11 +41,12 @@
40
41
  }
41
42
  }
42
43
 
43
- @include media-down('sm') {
44
+ @include media-up('sm') {
44
45
  th,
45
46
  td {
46
- padding: spacing('2') spacing('3');
47
- font-size: font-size('xs');
47
+ padding: spacing('3') spacing('4');
48
+ // Back to whatever the table is set in - the base size is the phone step
49
+ font-size: inherit;
48
50
  }
49
51
  }
50
52
  }
@@ -20,9 +20,12 @@
20
20
  grid-template-columns: repeat(3, 1fr);
21
21
  }
22
22
 
23
+ // The page gutter is the container's job, a second inset only narrows the tile
23
24
  &-4col {
24
- width: 85%;
25
- grid-template-columns: repeat(2, 1fr);
25
+ @include media-up('sm') {
26
+ width: 85%;
27
+ grid-template-columns: repeat(2, 1fr);
28
+ }
26
29
 
27
30
  @include media-up('md') {
28
31
  grid-template-columns: repeat(3, 1fr);
@@ -31,28 +34,12 @@
31
34
  @include media-up('lg') {
32
35
  grid-template-columns: repeat(4, 1fr);
33
36
  }
34
-
35
- @include media-down('sm') {
36
- grid-template-columns: 1fr;
37
- // Full width from here on - the page gutter is the container's job,
38
- // a second inset only narrows the tile
39
- width: 100%;
40
- padding: spacing('0');
41
- gap: spacing('4');
42
- }
43
37
  }
44
38
 
45
39
  &-2col {
46
- width: 75%;
47
- grid-template-columns: repeat(2, 1fr);
48
-
49
- @include media-down('sm') {
50
- grid-template-columns: 1fr;
51
- // Full width from here on - the page gutter is the container's job,
52
- // a second inset only narrows the tile
53
- width: 100%;
54
- padding: spacing('0');
55
- gap: spacing('4');
40
+ @include media-up('sm') {
41
+ width: 75%;
42
+ grid-template-columns: repeat(2, 1fr);
56
43
  }
57
44
  }
58
45
  }
@@ -75,7 +62,7 @@
75
62
  container: mw-tile / inline-size;
76
63
  background: var(--mw-card-background);
77
64
  @include surface;
78
- padding: spacing('5');
65
+ padding: spacing('4');
79
66
  box-shadow: var(--mw-elevation-2);
80
67
  transition: var(--mw-transition);
81
68
  border: 1px solid var(--mw-border);
@@ -84,6 +71,11 @@
84
71
  flex-direction: column;
85
72
  cursor: pointer;
86
73
 
74
+ // Ahead of the size modifiers below, which take over from 'sm'
75
+ @include media-up('sm') {
76
+ padding: spacing('5');
77
+ }
78
+
87
79
  // Same hover as a card, arc included - a tile is the larger clickable
88
80
  // relative of one, and a pair that looks alike has to react alike.
89
81
  &::after {
@@ -169,7 +161,9 @@
169
161
  }
170
162
 
171
163
  &-sm {
172
- padding: spacing('4');
164
+ @include media-up('sm') {
165
+ padding: spacing('4');
166
+ }
173
167
 
174
168
  .mw-tile-img {
175
169
  width: 80px;
@@ -197,7 +191,9 @@
197
191
  }
198
192
 
199
193
  &-lg {
200
- padding: spacing('6');
194
+ @include media-up('sm') {
195
+ padding: spacing('6');
196
+ }
201
197
 
202
198
  .mw-tile-img {
203
199
  width: 120px;
@@ -249,10 +245,4 @@
249
245
  margin: spacing('0') auto spacing('2');
250
246
  }
251
247
  }
252
-
253
- @include media-down('sm') {
254
- .mw-tile {
255
- padding: spacing('4');
256
- }
257
- }
258
248
  }
@@ -51,6 +51,10 @@ $_column-steps-lg: (
51
51
  ),
52
52
  );
53
53
 
54
+ // The breakpoints a grid can be pushed to. Outside the layer blocks for the
55
+ // same reason as the steps above: both read it.
56
+ $_grid-from: ('sm', 'md', 'lg', 'xl');
57
+
54
58
  @layer mw.layout {
55
59
  %grid-base {
56
60
  display: grid;
@@ -290,6 +294,19 @@ $_column-steps-lg: (
290
294
  }
291
295
  }
292
296
 
297
+ // Every ramp above turns two-column at `sm`, and 576px is generous for a
298
+ // column of running text next to a picture. This pushes the whole ramp up:
299
+ // single column until the breakpoint named, the grid's own steps from there.
300
+ // A modifier, so it works on all of them - and it has to come after them,
301
+ // because it carries the same specificity and wins on order alone.
302
+ @each $breakpoint in $_grid-from {
303
+ .mw-grid-from-#{$breakpoint} {
304
+ @include media-down($breakpoint) {
305
+ @include _single-column;
306
+ }
307
+ }
308
+ }
309
+
293
310
  // A feature card grows outwards - its frame and its label bar reach into the
294
311
  // gap, and two rows of them would touch. The card asks for the room, but the
295
312
  // grid has to hand it over: written next to the card it would sit in
@@ -350,4 +367,15 @@ $_column-steps-lg: (
350
367
  @include _reveal-ramp($steps);
351
368
  }
352
369
  }
370
+
371
+ // Below its breakpoint the grid is one column, so the stagger has to count in
372
+ // one too - otherwise two cards standing above each other rise on different
373
+ // beats. Last, so it beats the ramp it corrects at equal specificity.
374
+ @each $breakpoint in $_grid-from {
375
+ .mw-grid-from-#{$breakpoint} {
376
+ @include media-down($breakpoint) {
377
+ @include _reveal-stagger(1);
378
+ }
379
+ }
380
+ }
353
381
  }
@@ -529,16 +529,19 @@
529
529
  }
530
530
  }
531
531
 
532
- // Profile button - avatar plus the signed-in name
532
+ // Profile button - a round avatar until there is room for the signed-in name
533
+ // beside it
533
534
  .mw-profile-btn {
534
535
  display: inline-flex;
535
536
  align-items: center;
537
+ justify-content: center;
536
538
  gap: spacing('3');
537
539
  height: 40px;
538
- padding: spacing('0') spacing('4') spacing('0') spacing('1');
540
+ width: 40px;
541
+ padding: spacing('0');
539
542
  background: transparent;
540
543
  border: 1px solid var(--mw-header-border);
541
- border-radius: radius('2xl');
544
+ border-radius: radius('full');
542
545
  color: var(--mw-header-text-color);
543
546
  cursor: pointer;
544
547
  transition: var(--mw-transition);
@@ -583,14 +586,18 @@
583
586
  font-size: font-size('xl');
584
587
  }
585
588
 
586
- @include media-down('md') {
587
- padding: spacing('0');
588
- width: 40px;
589
- justify-content: center;
590
- border-radius: radius('full');
589
+ .mw-profile-btn-name {
590
+ display: none;
591
+ }
592
+
593
+ @include media-up('md') {
594
+ width: auto;
595
+ justify-content: normal;
596
+ padding: spacing('0') spacing('4') spacing('0') spacing('1');
597
+ border-radius: radius('2xl');
591
598
 
592
599
  .mw-profile-btn-name {
593
- display: none;
600
+ display: inline;
594
601
  }
595
602
  }
596
603
  }
@@ -5,11 +5,17 @@
5
5
  justify-items: center;
6
6
  align-items: center;
7
7
  text-align: center;
8
+ // The hero container runs the full width of the screen (see _main.scss), so
9
+ // the content has to produce the container width itself - otherwise it
10
+ // starts at a different edge than the header and every section below it.
11
+ // The gutter is already inside the token, hence no inline padding here.
12
+ width: var(--mw-container-width);
13
+ margin-inline: auto;
8
14
 
9
15
  &-content {
10
- padding: spacing('9') spacing('4');
16
+ padding: spacing('9') spacing('0');
11
17
  @include media-up('sm') {
12
- padding: spacing('6');
18
+ padding-block: spacing('6');
13
19
  }
14
20
 
15
21
  &-fade {
@@ -28,6 +34,19 @@
28
34
  }
29
35
  }
30
36
 
37
+ // A hero that points somewhere instead of sitting in the middle: the signet,
38
+ // the headline and the buttons all start at the edge the rest of the page
39
+ // starts at. Centred is still the default - a hero is short enough for it,
40
+ // which is exactly what a section head is not.
41
+ .mw-home-start {
42
+ justify-items: start;
43
+ text-align: left;
44
+
45
+ .mw-home-text {
46
+ margin-inline: 0;
47
+ }
48
+ }
49
+
31
50
  @keyframes fadeIn {
32
51
  from {
33
52
  opacity: 0;
@@ -8,21 +8,24 @@
8
8
  min-height: 100dvh;
9
9
  display: flex;
10
10
  flex-direction: column;
11
+ // Numbered section heads count per page body, so a second main on the same
12
+ // document starts at 01 again instead of continuing the first one.
13
+ counter-reset: mw-section-head;
11
14
  }
12
15
 
13
- // Set in from the container it sits in, and giving that back a step at a time
14
- // as the screen shrinks. For a column of full-width cards, which at 1200px
15
- // leaves more empty card than content.
16
+ // Takes the full container on a phone and steps inwards as the screen grows.
17
+ // For a column of full-width cards, which at 1200px leaves more empty card
18
+ // than content.
16
19
  .mw-container-narrow {
17
- width: 80%;
20
+ width: 100%;
18
21
  margin-inline: auto;
19
22
 
20
- @include media-down('lg') {
23
+ @include media-up('md') {
21
24
  width: 90%;
22
25
  }
23
26
 
24
- @include media-down('md') {
25
- width: 100%;
27
+ @include media-up('lg') {
28
+ width: 80%;
26
29
  }
27
30
  }
28
31
 
@@ -34,11 +34,11 @@
34
34
  flex-wrap: wrap;
35
35
  align-items: center;
36
36
  gap: spacing('3');
37
- margin-left: auto;
37
+ width: 100%;
38
38
 
39
- @include media-down('sm') {
40
- width: 100%;
41
- margin-left: spacing('0');
39
+ @include media-up('sm') {
40
+ width: auto;
41
+ margin-left: auto;
42
42
  }
43
43
  }
44
44