maverick-wave 4.6.0 → 4.8.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/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "4.6.0",
3
+ "version": "4.8.0",
4
4
  "config": {
5
- "version_short": "4.6"
5
+ "version_short": "4.8"
6
6
  },
7
7
  "description": "A lightweight, modern CSS framework for building responsive websites with elegance and speed.",
8
8
  "main": "src/js/main.js",
9
9
  "style": "src/scss/main.scss",
10
10
  "scripts": {
11
11
  "clean": "gulp clean",
12
- "format": "prettier --write \"**/*.{scss,js,json,html,md}\"",
13
- "format:check": "prettier --check \"**/*.{scss,js,json,html,md}\"",
12
+ "format": "prettier --check \"**/*.{scss,js,json,html,md}\"",
13
+ "format:fix": "prettier --write \"**/*.{scss,js,json,html,md}\"",
14
14
  "showcase": "http-server -c-1 -p 8888 dist",
15
15
  "start": "gulp",
16
16
  "build": "gulp clean && gulp build",
@@ -38,9 +38,9 @@
38
38
  ],
39
39
  "devDependencies": {
40
40
  "autoprefixer": "^10.4.21",
41
+ "cssnano": "^8.0.7",
41
42
  "del": "^8.0.1",
42
43
  "gulp": "^5.0.0",
43
- "gulp-clean-css": "^4.3.0",
44
44
  "gulp-file-include": "^2.3.0",
45
45
  "gulp-postcss": "^10.0.0",
46
46
  "gulp-rename": "^2.1.0",
@@ -390,7 +390,8 @@
390
390
 
391
391
  <h3 class="mw-mb-4 mw-mt-6">Additional Cards</h3>
392
392
  <p class="mw-text-muted">
393
- You can also use badges or ribbons on top of a card.
393
+ You can also use badges or ribbons on top of a card, or wrap the one card that
394
+ should stand out in a feature frame.
394
395
  </p>
395
396
 
396
397
  <div class="mw-grid-1">
@@ -553,4 +554,84 @@
553
554
  </div>
554
555
  </div>
555
556
  </div>
557
+ <!-- Feature frame column -->
558
+ <div class="mw-p-2">
559
+ <h3 class="mw-card-title mw-mb-10">Feature Frame</h3>
560
+ <div class="mw-grid-3-lg">
561
+ <div class="mw-card">
562
+ <div class="mw-card-body">
563
+ <h3 class="mw-card-title">Starter</h3>
564
+ <hr class="mw-card-title-divider" />
565
+ <p class="mw-card-text">The basics to get going, billed monthly.</p>
566
+ <div class="mw-card-footer">
567
+ <button type="button" class="mw-btn mw-btn-outline">Choose</button>
568
+ </div>
569
+ </div>
570
+ </div>
571
+ <div class="mw-card-feature">
572
+ <p class="mw-card-feature-label">Most booked</p>
573
+ <div class="mw-card">
574
+ <div class="mw-card-body">
575
+ <h3 class="mw-card-title">Standard</h3>
576
+ <hr class="mw-card-title-divider" />
577
+ <p class="mw-card-text">
578
+ Everything from Starter plus the features most people ask for.
579
+ </p>
580
+ <div class="mw-card-footer">
581
+ <button type="button" class="mw-btn mw-btn-primary">
582
+ Choose
583
+ </button>
584
+ </div>
585
+ </div>
586
+ </div>
587
+ </div>
588
+ <div class="mw-card">
589
+ <div class="mw-card-body">
590
+ <h3 class="mw-card-title">Premium</h3>
591
+ <hr class="mw-card-title-divider" />
592
+ <p class="mw-card-text">
593
+ The full set, with priority support on top.
594
+ </p>
595
+ <div class="mw-card-footer">
596
+ <button type="button" class="mw-btn mw-btn-outline">Choose</button>
597
+ </div>
598
+ </div>
599
+ </div>
600
+ </div>
601
+ <p class="mw-text-muted mw-mt-6">
602
+ The frame is primary by default, secondary and info are one class away.
603
+ </p>
604
+ <div class="mw-grid-3-lg mw-mt-10">
605
+ <div class="mw-card-feature">
606
+ <p class="mw-card-feature-label">Primary</p>
607
+ <div class="mw-card">
608
+ <div class="mw-card-body">
609
+ <h3 class="mw-card-title">Standard</h3>
610
+ <hr class="mw-card-title-divider" />
611
+ <p class="mw-card-text">The one most people end up picking.</p>
612
+ </div>
613
+ </div>
614
+ </div>
615
+ <div class="mw-card-feature mw-card-feature-secondary">
616
+ <p class="mw-card-feature-label">Secondary</p>
617
+ <div class="mw-card">
618
+ <div class="mw-card-body">
619
+ <h3 class="mw-card-title">Team</h3>
620
+ <hr class="mw-card-title-divider" />
621
+ <p class="mw-card-text">Seats for everyone, billed per head.</p>
622
+ </div>
623
+ </div>
624
+ </div>
625
+ <div class="mw-card-feature mw-card-feature-info">
626
+ <p class="mw-card-feature-label">Info</p>
627
+ <div class="mw-card">
628
+ <div class="mw-card-body">
629
+ <h3 class="mw-card-title">Trial</h3>
630
+ <hr class="mw-card-title-divider" />
631
+ <p class="mw-card-text">Free for 30 days, no card needed.</p>
632
+ </div>
633
+ </div>
634
+ </div>
635
+ </div>
636
+ </div>
556
637
  </div>
@@ -5,43 +5,46 @@
5
5
  <h4 class="mw-mb-2">Basic Table</h4>
6
6
  <p class="mw-text-muted">
7
7
  This is the basic table that supports all functions except the complete
8
- responsive feeling with the cards
8
+ responsive feeling with the cards - five columns do not fit a phone, so it
9
+ sits in a <code>mw-table-responsive</code> wrapper
9
10
  </p>
10
11
 
11
- <table class="mw-table">
12
- <thead>
13
- <tr>
14
- <th>#</th>
15
- <th>Name</th>
16
- <th>Position</th>
17
- <th>Location</th>
18
- <th class="mw-text-currency">Budget</th>
19
- </tr>
20
- </thead>
21
- <tbody>
22
- <tr>
23
- <td>1</td>
24
- <td>John Doe</td>
25
- <td>Developer</td>
26
- <td>New York</td>
27
- <td class="mw-text-currency">1,204.50</td>
28
- </tr>
29
- <tr>
30
- <td>2</td>
31
- <td>Jane Smith</td>
32
- <td>Designer</td>
33
- <td>London</td>
34
- <td class="mw-text-currency">87.00</td>
35
- </tr>
36
- <tr>
37
- <td>3</td>
38
- <td>Bob Johnson</td>
39
- <td>Manager</td>
40
- <td>Berlin</td>
41
- <td class="mw-text-currency">15,930.25</td>
42
- </tr>
43
- </tbody>
44
- </table>
12
+ <div class="mw-table-responsive">
13
+ <table class="mw-table">
14
+ <thead>
15
+ <tr>
16
+ <th>#</th>
17
+ <th>Name</th>
18
+ <th>Position</th>
19
+ <th>Location</th>
20
+ <th class="mw-text-currency">Budget</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <tr>
25
+ <td>1</td>
26
+ <td>John Doe</td>
27
+ <td>Developer</td>
28
+ <td>New York</td>
29
+ <td class="mw-text-currency">1,204.50</td>
30
+ </tr>
31
+ <tr>
32
+ <td>2</td>
33
+ <td>Jane Smith</td>
34
+ <td>Designer</td>
35
+ <td>London</td>
36
+ <td class="mw-text-currency">87.00</td>
37
+ </tr>
38
+ <tr>
39
+ <td>3</td>
40
+ <td>Bob Johnson</td>
41
+ <td>Manager</td>
42
+ <td>Berlin</td>
43
+ <td class="mw-text-currency">15,930.25</td>
44
+ </tr>
45
+ </tbody>
46
+ </table>
47
+ </div>
45
48
  <p class="mw-text-muted mw-mt-3">
46
49
  The <strong>Budget</strong> column uses
47
50
  <strong>mw-text-currency</strong> - right-aligned with tabular, lining
@@ -51,11 +51,27 @@ $_active-prefix: 'dark';
51
51
  // Layout knobs. A good default is not enough here: what reads as generous on
52
52
  // a landing page costs visible content in an application with a sticky
53
53
  // header. Same framework, two different right answers.
54
- --mw-container-width: min(1200px, 89%);
55
- // Below 'sm' the percentage turns into wasted margin - 89% of a 375px screen
56
- // leaves 41px of nothing on a card that has to fit amount, status and two
57
- // labels into one row. A fixed gutter uses the width instead.
58
- --mw-container-width-sm: calc(100% - #{spacing('5')} * 2);
54
+ //
55
+ // The page gutter is fluid rather than stepped. A plain percentage keeps too
56
+ // little on a phone and throws away too much on a desktop; a fixed gutter
57
+ // does the reverse - Bootstrap ships 12px at every width, Bulma 32px, and
58
+ // Material asks for 16dp on a phone and more as the screen grows. The ramp
59
+ // below lands on ~24px at 375px, ~32px at 576px, ~40px on a tablet and tops
60
+ // out at 64px, where the 1200px cap takes over. Stepping it at a breakpoint
61
+ // instead would make the container jump *backwards* at the step, because the
62
+ // gutter grows faster there than the viewport does.
63
+ //
64
+ // max() against the safe-area insets, so a notched phone in landscape pushes
65
+ // the content clear of the cutout instead of running underneath it.
66
+ --mw-container-gutter: max(
67
+ clamp(1rem, 4.2vw + 0.5rem, 4rem),
68
+ env(safe-area-inset-left, 0px),
69
+ env(safe-area-inset-right, 0px)
70
+ );
71
+ --mw-container-width: min(
72
+ 1200px,
73
+ calc(100% - 2 * var(--mw-container-gutter))
74
+ );
59
75
  --mw-section-padding-block: #{spacing('7')};
60
76
 
61
77
  // Active theme - aliases onto the dark or light set above
@@ -10,7 +10,7 @@
10
10
 
11
11
  html {
12
12
  scroll-behavior: smooth;
13
- min-width: 375px;
13
+ min-width: 320px;
14
14
  // Keeps anchor targets clear of the fixed header, plus a bit of breathing room
15
15
  scroll-padding-top: calc(var(--mw-header-height) + #{spacing('4')});
16
16
  -webkit-text-size-adjust: 100%;
@@ -27,9 +27,16 @@ h6 {
27
27
  font-weight: font-weight('bold');
28
28
  }
29
29
 
30
+ // Two steps, not one. With the single jump at 576px, everything between there
31
+ // and a tablet kept the full desktop headline - 3rem of h1 across a 690px
32
+ // column is a third of the screen before the first line of copy.
30
33
  h1 {
31
34
  font-size: font-size('5xl');
32
35
 
36
+ @include media-down('md') {
37
+ font-size: font-size('4xl');
38
+ }
39
+
33
40
  @include media-down('sm') {
34
41
  font-size: font-size('3xl');
35
42
  }
@@ -38,6 +45,10 @@ h1 {
38
45
  h2 {
39
46
  font-size: font-size('4xl');
40
47
 
48
+ @include media-down('md') {
49
+ font-size: font-size('3xl');
50
+ }
51
+
41
52
  @include media-down('sm') {
42
53
  font-size: font-size('2xl');
43
54
  }
@@ -1,6 +1,7 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
3
  .mw-blog-post {
4
+ position: relative;
4
5
  margin: spacing('2');
5
6
  padding: spacing('4') spacing('7');
6
7
  animation: pageReveal 1.6s ease-out forwards;
@@ -22,6 +23,11 @@
22
23
  }
23
24
  }
24
25
 
26
+ @include media-down('sm') {
27
+ margin: spacing('1');
28
+ padding: spacing('4') spacing('5');
29
+ }
30
+
25
31
  // Book-like left border
26
32
  &::before {
27
33
  content: '';
@@ -48,7 +54,8 @@
48
54
  position: absolute;
49
55
  bottom: spacing('-2');
50
56
  left: spacing('0');
51
- width: 200px;
57
+ // Never wider than the title it underlines
58
+ width: min(200px, 100%);
52
59
  height: 5px;
53
60
  background: var(--mw-primary-text-color);
54
61
  }
@@ -1,5 +1,8 @@
1
1
  @use '../abstracts' as *;
2
2
 
3
+ // Card width at which the footer stops being a row
4
+ $_mw-card-narrow: 360px;
5
+
3
6
  $_mw-card-addon-colors: (
4
7
  primary: var(--mw-primary-color),
5
8
  secondary: var(--mw-secondary-color),
@@ -43,6 +46,19 @@ $_mw-card-addon-colors: (
43
46
  overflow: hidden;
44
47
  }
45
48
 
49
+ // Query container for the footer below. Named, so the query cannot resolve to
50
+ // a project's own container further up the tree.
51
+ //
52
+ // Only cards that have a footer, and they claim their slot: inline-size
53
+ // containment computes the card's own width as if it were empty, so a card
54
+ // that takes its width from its content - a flex row, `mw-grid-stack`, a
55
+ // timeline wrapper - would collapse to its border. Filling the slot keeps the
56
+ // width external, which is what makes it queryable in the first place.
57
+ &:has(.mw-card-footer) {
58
+ width: 100%;
59
+ container: mw-card / inline-size;
60
+ }
61
+
46
62
  &:hover {
47
63
  transform: translateY(-2px);
48
64
  box-shadow: 0 7px 15px var(--mw-shadow);
@@ -120,13 +136,17 @@ $_mw-card-addon-colors: (
120
136
 
121
137
  &-lg {
122
138
  --mw-card-img-height: 340px;
139
+
140
+ @include media-down('sm') {
141
+ --mw-card-img-height: 260px;
142
+ }
123
143
  }
124
144
 
125
145
  &-xl {
126
146
  --mw-card-img-height: 480px;
127
147
 
128
148
  @include media-down('sm') {
129
- --mw-card-img-height: 440px;
149
+ --mw-card-img-height: 340px;
130
150
  }
131
151
  }
132
152
 
@@ -191,6 +211,9 @@ $_mw-card-addon-colors: (
191
211
  // centered, so plain text next to a button sits on the button's centre
192
212
  // line instead of being stretched to its height and starting at the top
193
213
  align-items: center;
214
+ // Buttons do not shrink, so two that no longer fit have to wrap - without
215
+ // this they leave the card sideways
216
+ flex-wrap: wrap;
194
217
  gap: spacing('3');
195
218
  flex-shrink: 0;
196
219
  text-wrap: balance;
@@ -206,11 +229,27 @@ $_mw-card-addon-colors: (
206
229
  flex-shrink: 0;
207
230
  }
208
231
 
209
- @include media-down('lg') {
232
+ // Stacked once the card is narrow, not once the window is - a card in a
233
+ // three-column grid on a wide desktop is as narrow as the same card on a
234
+ // phone and used to keep its actions in a cramped row anyway.
235
+ @container mw-card (max-width: #{$_mw-card-narrow}) {
210
236
  flex-direction: column;
211
237
  align-items: stretch;
212
238
  gap: spacing('2');
213
239
 
240
+ // `flex: 1 0 100%` on the note is 100% of the *height* in a column: it
241
+ // fills the column and the buttons wrap out of the card sideways
242
+ &:has(.mw-actions-note),
243
+ &:has(.mw-form-actions-hint) {
244
+ flex-wrap: nowrap;
245
+ }
246
+
247
+ .mw-actions-note,
248
+ .mw-form-actions-hint {
249
+ flex: 0 0 auto;
250
+ text-align: left;
251
+ }
252
+
214
253
  > * {
215
254
  width: 100%;
216
255
  }
@@ -288,6 +327,77 @@ $_mw-card-addon-colors: (
288
327
  }
289
328
  }
290
329
 
330
+ // Frame with a bar on top, wrapped around a card - for the one variant in a
331
+ // grid that should stand out.
332
+ //
333
+ // `mw-card-badge` sits inside the card body and overlaps the title on narrow
334
+ // cards. This one wraps around the card instead, and grows outwards: the card
335
+ // keeps the width, height and look of its neighbours, frame and bar reach into
336
+ // the grid gap.
337
+ //
338
+ // <div class="mw-card-feature">
339
+ // <p class="mw-card-feature-label">Most booked</p>
340
+ // <div class="mw-card">…</div>
341
+ // </div>
342
+ //
343
+ // Primary out of the box, `mw-card-feature-secondary` and
344
+ // `mw-card-feature-info` swap the colour.
345
+ //
346
+ // Geometry: 22px bar, 6px gap between frame and card, 1px border. The bar
347
+ // height is fixed and the margins count on it - a two-line label needs the
348
+ // margin and the padding raised with it. It is kept low on purpose: every
349
+ // pixel of bar is a pixel the grid below has to add to its row gap.
350
+ .mw-card-feature {
351
+ position: relative;
352
+ display: flex;
353
+ flex-direction: column;
354
+ margin: -29px -7px -7px;
355
+ padding: 28px 6px 6px;
356
+ border: 1px solid var(--mw-primary-color);
357
+ border-radius: 12px 27px 12px 27px;
358
+
359
+ &-label {
360
+ position: absolute;
361
+ inset: 0 0 auto;
362
+ display: flex;
363
+ align-items: center;
364
+ justify-content: center;
365
+ height: 22px;
366
+ margin: 0;
367
+ padding-inline: spacing('4');
368
+ border-radius: 11px 26px 0 0;
369
+ background: var(--mw-primary-color);
370
+ color: var(--mw-primary-accent-text-color);
371
+ font-size: font-size('2xs');
372
+ font-weight: font-weight('bold');
373
+ letter-spacing: 0.06em;
374
+ text-transform: uppercase;
375
+ white-space: nowrap;
376
+ overflow: hidden;
377
+ text-overflow: ellipsis;
378
+ }
379
+
380
+ > .mw-card {
381
+ flex: 1;
382
+ }
383
+ }
384
+
385
+ [class*='mw-grid-']:has(> .mw-card-feature) {
386
+ row-gap: 48px;
387
+ }
388
+
389
+ // Colour variants - primary is the default above, these two override it
390
+ @each $name in ('secondary', 'info') {
391
+ .mw-card-feature-#{$name} {
392
+ border-color: var(--mw-#{$name}-color);
393
+
394
+ > .mw-card-feature-label {
395
+ background: var(--mw-#{$name}-color);
396
+ color: var(--mw-#{$name}-accent-text-color);
397
+ }
398
+ }
399
+ }
400
+
291
401
  @each $name, $col in $_mw-card-addon-colors {
292
402
  .mw-card-addon-#{$name} {
293
403
  --mw-card-addon-color: #{$col};
@@ -10,6 +10,12 @@
10
10
  align-items: center;
11
11
  justify-content: flex-end;
12
12
  row-gap: spacing('1');
13
+
14
+ @include media-down('sm') {
15
+ justify-content: flex-start;
16
+ column-gap: spacing('6');
17
+ row-gap: spacing('2');
18
+ }
13
19
  }
14
20
 
15
21
  &-item {
@@ -19,6 +25,10 @@
19
25
  gap: spacing('2');
20
26
  &:not(:first-child) {
21
27
  margin-left: spacing('9');
28
+
29
+ @include media-down('sm') {
30
+ margin-left: spacing('0');
31
+ }
22
32
  }
23
33
  font-size: font-size('md');
24
34
 
@@ -13,7 +13,7 @@
13
13
  display: none;
14
14
  align-items: center;
15
15
  justify-content: center;
16
- padding: spacing('3');
16
+ padding: spacing('7');
17
17
  opacity: 0;
18
18
  transition: opacity 0.4s ease;
19
19
 
@@ -58,6 +58,21 @@
58
58
  }
59
59
  }
60
60
 
61
+ @include media-down('sm') {
62
+ .mw-modal-overlay {
63
+ padding: spacing('5');
64
+ }
65
+
66
+ .mw-modal-header,
67
+ .mw-modal-footer {
68
+ padding: spacing('3') spacing('4');
69
+ }
70
+
71
+ .mw-modal-body {
72
+ padding: spacing('4');
73
+ }
74
+ }
75
+
61
76
  // Modal sections
62
77
  .mw-modal-header {
63
78
  padding: spacing('3') spacing('5');
@@ -92,6 +107,9 @@
92
107
  padding: spacing('3') spacing('5');
93
108
  border-top: 1px solid var(--mw-border-accent);
94
109
  display: flex;
110
+ // Three actions do not fit one line inside a phone-width dialog, and a row
111
+ // that cannot wrap pushes the last one out through the border
112
+ flex-wrap: wrap;
95
113
  gap: spacing('2');
96
114
  justify-content: flex-end;
97
115
  }
@@ -35,6 +35,9 @@
35
35
  }
36
36
 
37
37
  @include media-down('sm') {
38
+ width: 100%;
39
+ margin-inline: spacing('0');
40
+
38
41
  th,
39
42
  td {
40
43
  padding: spacing('1') spacing('2');
@@ -15,7 +15,8 @@
15
15
 
16
16
  @include media-down('sm') {
17
17
  grid-template-columns: 1fr;
18
- width: 90%;
18
+ width: 100%;
19
+ padding: spacing('0');
19
20
  gap: spacing('4');
20
21
  }
21
22
 
@@ -34,7 +35,10 @@
34
35
 
35
36
  @include media-down('sm') {
36
37
  grid-template-columns: 1fr;
37
- width: 90%;
38
+ // Full width from here on - the page gutter is the container's job,
39
+ // a second inset only narrows the tile
40
+ width: 100%;
41
+ padding: spacing('0');
38
42
  gap: spacing('4');
39
43
  }
40
44
  }
@@ -46,7 +50,10 @@
46
50
 
47
51
  @include media-down('sm') {
48
52
  grid-template-columns: 1fr;
49
- width: 90%;
53
+ // Full width from here on - the page gutter is the container's job,
54
+ // a second inset only narrows the tile
55
+ width: 100%;
56
+ padding: spacing('0');
50
57
  gap: spacing('4');
51
58
  }
52
59
  }
@@ -193,6 +193,8 @@ $_simple-date-width: 110px;
193
193
  }
194
194
 
195
195
  @include media-down('sm') {
196
+ width: 100%;
197
+
196
198
  // Line moves to the left
197
199
  &::before {
198
200
  left: 0;
@@ -317,6 +319,8 @@ $_simple-date-width: 110px;
317
319
  }
318
320
 
319
321
  @include media-down('sm') {
322
+ width: 100%;
323
+
320
324
  &::before {
321
325
  left: 0;
322
326
  transform: none;
@@ -53,6 +53,18 @@
53
53
  // full-width stacked
54
54
  &-full-width {
55
55
  flex-direction: column;
56
+
57
+ &:has(.mw-actions-note),
58
+ &:has(.mw-form-actions-hint) {
59
+ flex-wrap: nowrap;
60
+ }
61
+
62
+ .mw-actions-note,
63
+ .mw-form-actions-hint {
64
+ flex: 0 0 auto;
65
+ text-align: left;
66
+ }
67
+
56
68
  > * {
57
69
  width: 100%;
58
70
  }
@@ -15,6 +15,10 @@
15
15
  flex-direction: column;
16
16
  align-items: stretch;
17
17
 
18
+ @include media-down('sm') {
19
+ width: min(340px, 100%);
20
+ }
21
+
18
22
  @include media-down('xs') {
19
23
  padding: spacing('7') spacing('4');
20
24
  }