vanilla-framework 4.51.0 → 4.52.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,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-framework",
3
- "version": "4.51.0",
3
+ "version": "4.52.0",
4
4
  "author": {
5
5
  "email": "webteam@canonical.com",
6
6
  "name": "Canonical Webteam"
@@ -19,11 +19,10 @@
19
19
  }
20
20
 
21
21
  .l-full-width__sidebar {
22
- background: $colors--theme--background-alt;
23
-
24
22
  // height of top navigation, as padding applied to .p-navigation__link + line-heigh of the anchor text inside
25
23
  $navigation-top-height: $spv--large * 2 + map-get($settings-text-default, line-height);
26
24
 
25
+ background: $colors--theme--background-alt;
27
26
  height: calc(100% - $navigation-top-height); // height of document reduced by height of top nav
28
27
  min-height: calc(100dvh - $navigation-top-height);
29
28
  position: absolute;
@@ -10,10 +10,12 @@
10
10
  Modifier for a 4-column width horizontal layout. Applied ONLY to the parent .p-content-card.
11
11
  "&.p-content-card--cols-6":
12
12
  Modifier for a 6-column width horizontal layout. Applied ONLY to the parent .p-content-card.
13
+ "&.p-content-card--cols-8":
14
+ Modifier for an 8-column (full-width) layout with 50/50 content and image split on desktop. Applied ONLY to the parent .p-content-card. Image is required.
13
15
  "&.has-image":
14
16
  State class applied to the parent when the card includes an image.
15
17
  "&.has-desc":
16
- State class applied to the parent when the card includes a description that appears on hover.
18
+ State class applied to the parent when the card includes a description. For col-2/4/6 the description slides up on hover; for col-8 it is always visible below the heading.
17
19
  Links:
18
20
  .p-content-card__overlay-link:
19
21
  Invisible absolute link spanning the entire card to make it clickable.
@@ -78,9 +80,10 @@ $card-author-padding-bottom: $sp-small;
78
80
 
79
81
  $card-fallback-spacing-large: $sp-x-large;
80
82
  $card-fallback-image-gap: $sp-small + $sp-xx-small;
83
+ $card-height-8col: 22rem;
81
84
 
82
85
  @mixin mq-min($breakpoint) {
83
- @media screen and (width >= $breakpoint) {
86
+ @media screen and (width >=$breakpoint) {
84
87
  @content;
85
88
  }
86
89
  }
@@ -92,7 +95,7 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
92
95
  }
93
96
 
94
97
  @mixin mq-between($min, $max) {
95
- @media screen and ($min <= width < $max) {
98
+ @media screen and ($min <=width < $max) {
96
99
  @content;
97
100
  }
98
101
  }
@@ -111,18 +114,24 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
111
114
 
112
115
  /* 2-Column Spanning */
113
116
  &--2 {
114
- grid-column: 1 / -1; /* Mobile */
117
+ grid-column: 1 / -1;
118
+
119
+ /* Mobile */
115
120
  @include mq-between($breakpoint-small, $breakpoint-large) {
116
- grid-column: span 2; /* Medium */
121
+ grid-column: span 2;
122
+ /* Medium */
117
123
  }
124
+
118
125
  @include mq-min($breakpoint-large) {
119
- grid-column: span 2; /* Desktop */
126
+ grid-column: span 2;
127
+ /* Desktop */
120
128
  }
121
129
  }
122
130
 
123
131
  /* 4-Column Spanning */
124
132
  &--4 {
125
133
  grid-column: 1 / -1;
134
+
126
135
  @include mq-min($breakpoint-large) {
127
136
  grid-column: span 4;
128
137
  }
@@ -131,10 +140,16 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
131
140
  /* 6-Column Spanning */
132
141
  &--6 {
133
142
  grid-column: 1 / -1;
143
+
134
144
  @include mq-min($breakpoint-large) {
135
145
  grid-column: span 6;
136
146
  }
137
147
  }
148
+
149
+ /* 8-Column Spanning (full width) */
150
+ &--8 {
151
+ grid-column: 1 / -1;
152
+ }
138
153
  }
139
154
 
140
155
  /* =========================================
@@ -168,7 +183,8 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
168
183
  &:not(:has(.p-content-card__footer-outer)) {
169
184
  height: auto;
170
185
  min-height: 0;
171
- padding-bottom: var(--spacing-vertical-large, $sp-medium); /* Keeps spacing balanced */
186
+ padding-bottom: var(--spacing-vertical-large, $sp-medium);
187
+ /* Keeps spacing balanced */
172
188
  }
173
189
  }
174
190
 
@@ -221,6 +237,16 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
221
237
  }
222
238
  }
223
239
 
240
+ /* 8-Column: Desktop horizontal grid layout */
241
+ @include mq-min($breakpoint-large) {
242
+ &.p-content-card--cols-8.has-image {
243
+ display: grid;
244
+ grid-template-columns: 1fr 1fr;
245
+ min-height: $card-height-8col;
246
+ padding: 0;
247
+ }
248
+ }
249
+
224
250
  &__overlay-link {
225
251
  inset: 0;
226
252
  position: absolute;
@@ -242,6 +268,18 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
242
268
  line-clamp: 2;
243
269
  }
244
270
 
271
+ .p-content-card--cols-8 & {
272
+ -webkit-line-clamp: 3;
273
+ line-clamp: 3;
274
+ }
275
+
276
+ @include mq-between($breakpoint-small, $breakpoint-large) {
277
+ .p-content-card--cols-8 & {
278
+ -webkit-line-clamp: 2;
279
+ line-clamp: 2;
280
+ }
281
+ }
282
+
245
283
  &:hover,
246
284
  &:focus,
247
285
  &:active,
@@ -268,7 +306,6 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
268
306
  display: -webkit-box;
269
307
  -webkit-line-clamp: 3;
270
308
  line-clamp: 3;
271
- line-height: 1.5;
272
309
  margin-top: 0 !important;
273
310
  max-height: 4.5em;
274
311
  max-width: none;
@@ -283,11 +320,25 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
283
320
  max-height: 3em;
284
321
  }
285
322
 
323
+ .p-content-card--cols-8 & {
324
+ -webkit-line-clamp: 3;
325
+ line-clamp: 3;
326
+ max-height: 4.5em;
327
+ }
328
+
286
329
  @include mq-min($breakpoint-large) {
287
330
  .p-content-card--cols-6 & {
288
331
  margin-top: $card-nudge-negative !important;
289
332
  }
290
333
  }
334
+
335
+ @include mq-between($breakpoint-small, $breakpoint-large) {
336
+ .p-content-card--cols-8 & {
337
+ -webkit-line-clamp: 2;
338
+ line-clamp: 2;
339
+ max-height: 3em;
340
+ }
341
+ }
291
342
  }
292
343
 
293
344
  &__content {
@@ -298,6 +349,12 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
298
349
  justify-content: space-between;
299
350
  min-width: 0;
300
351
  width: 100%;
352
+
353
+ @include mq-min($breakpoint-large) {
354
+ .p-content-card--cols-8 & {
355
+ grid-column: 1;
356
+ }
357
+ }
301
358
  }
302
359
 
303
360
  &__body {
@@ -315,6 +372,20 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
315
372
  padding: 0;
316
373
  }
317
374
  }
375
+
376
+ .p-content-card--cols-8 & {
377
+ display: flex;
378
+ flex-direction: column;
379
+ min-height: 0;
380
+ padding: 0 $sp-medium;
381
+ }
382
+
383
+ @include mq-min($breakpoint-large) {
384
+ .p-content-card--cols-8 & {
385
+ align-self: stretch;
386
+ padding: $sp-medium $sp-medium 0 $sp-medium;
387
+ }
388
+ }
318
389
  }
319
390
 
320
391
  &__primary-content,
@@ -335,6 +406,13 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
335
406
  &__hover-content {
336
407
  opacity: 0;
337
408
  transform: translateY(150px);
409
+
410
+ .p-content-card--cols-8 & {
411
+ flex: 1;
412
+ min-height: 0;
413
+ opacity: 1;
414
+ transform: translateY(0);
415
+ }
338
416
  }
339
417
 
340
418
  &__description {
@@ -350,6 +428,19 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
350
428
  line-clamp: 2;
351
429
  }
352
430
 
431
+ .p-content-card--cols-8 & {
432
+ -webkit-line-clamp: 3;
433
+ line-clamp: 3;
434
+ }
435
+
436
+ @include mq-max($breakpoint-large) {
437
+ .p-content-card--cols-8 & {
438
+ -webkit-line-clamp: 2;
439
+ line-clamp: 2;
440
+ margin-bottom: 1rem;
441
+ }
442
+ }
443
+
353
444
  @include mq-min($breakpoint-large) {
354
445
  .p-content-card--cols-6 & {
355
446
  margin-top: $card-nudge-negative !important;
@@ -359,9 +450,13 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
359
450
 
360
451
  &__footer-container {
361
452
  /* Structural grouping element.
362
- Because the parent (.p-content-card__content) uses flexbox space-between,
453
+ Because the parent (.p-content-card__content) uses flexbox space-between,
363
454
  this wrapper prevents the <hr> from floating awkwardly in the middle of the card.
364
455
  */
456
+
457
+ .p-content-card--cols-8 & {
458
+ width: 100%;
459
+ }
365
460
  }
366
461
 
367
462
  &__footer-outer {
@@ -444,6 +539,11 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
444
539
  .p-content-card--cols-6 & {
445
540
  height: $card-image-height-horizontal-large;
446
541
  }
542
+
543
+ .p-content-card--cols-8 & {
544
+ aspect-ratio: auto;
545
+ height: 100%;
546
+ }
447
547
  }
448
548
  }
449
549
 
@@ -457,6 +557,17 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
457
557
 
458
558
  width: 100%;
459
559
 
560
+ @include mq-min($breakpoint-large) {
561
+ .p-content-card--cols-8 & {
562
+ grid-column: 2;
563
+ grid-row: 1 / -1;
564
+ height: 100%;
565
+ padding: 0.5rem;
566
+ padding-bottom: 0;
567
+ width: 100%;
568
+ }
569
+ }
570
+
460
571
  @include mq-min($breakpoint-small) {
461
572
  .p-content-card--cols-4 &,
462
573
  .p-content-card--cols-6 & {
@@ -465,6 +576,12 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
465
576
  width: $card-image-width;
466
577
  }
467
578
  }
579
+
580
+ @include mq-max($breakpoint-large) {
581
+ .p-content-card--cols-8 & {
582
+ padding: 0rem 0.5rem 1rem 0.5rem;
583
+ }
584
+ }
468
585
  }
469
586
 
470
587
  &__author-and-date {
@@ -508,14 +625,14 @@ $card-fallback-image-gap: $sp-small + $sp-xx-small;
508
625
  }
509
626
 
510
627
  @include mq-min($breakpoint-large) {
511
- &.has-desc:hover .p-content-card__primary-content,
512
- &.has-desc:focus-within .p-content-card__primary-content {
628
+ &.has-desc:not(.p-content-card--cols-8):hover .p-content-card__primary-content,
629
+ &.has-desc:not(.p-content-card--cols-8):focus-within .p-content-card__primary-content {
513
630
  opacity: 0;
514
631
  transform: translateY(-150px);
515
632
  }
516
633
 
517
- &.has-desc:hover .p-content-card__hover-content,
518
- &.has-desc:focus-within .p-content-card__hover-content {
634
+ &.has-desc:not(.p-content-card--cols-8):hover .p-content-card__hover-content,
635
+ &.has-desc:not(.p-content-card--cols-8):focus-within .p-content-card__hover-content {
519
636
  opacity: 1;
520
637
  transform: translateY(0);
521
638
  }
@@ -262,6 +262,9 @@ $list-step-bullet-margin: $sph--x-large;
262
262
 
263
263
  display: grid;
264
264
 
265
+ // --columns is set in the container queries above
266
+ grid-template-columns: repeat(var(--columns), 1fr);
267
+
265
268
  @container (width >= #{$horizontal-list-section-medium-content-width}) {
266
269
  grid-gap: 0 map-get($grid-gutter-widths, default);
267
270
  }
@@ -282,9 +285,6 @@ $list-step-bullet-margin: $sph--x-large;
282
285
  }
283
286
  }
284
287
 
285
- // --columns is set in the container queries above
286
- grid-template-columns: repeat(var(--columns), 1fr);
287
-
288
288
  .p-list__item {
289
289
  @extend %vf-list-item;
290
290
  @include vf-list-item-icon-divisor-offset;
@@ -82,13 +82,13 @@
82
82
  // same as %section-padding--default
83
83
  padding-bottom: $spv--strip-regular * 0.5;
84
84
 
85
+ // padding top based on p-section--hero
86
+ padding-top: $spv--large;
87
+
85
88
  @media (min-width: $breakpoint-large) {
86
89
  padding-bottom: $spv--strip-regular;
87
90
  }
88
91
 
89
- // padding top based on p-section--hero
90
- padding-top: $spv--large;
91
-
92
92
  // on large screens, same as %section-padding--shallow
93
93
  @media (min-width: $breakpoint-large) {
94
94
  padding-top: $spv--x-large;
@@ -1,23 +1,27 @@
1
1
  {#
2
2
  All Params
3
- columns: Grid column span for the card. Options are 2, 4, 6. Default is 2.
3
+ columns: Grid column span for the card. Options are 2, 4, 6, 8. Default is 2.
4
4
  heading: H4 title text. Truncated at 3 lines. Required.
5
5
  link: Link to referenced item. Makes the entire card clickable. Required.
6
- image: Dictionary containing 'src' and 'alt' for the 16:9 image. Required for col-6.
6
+ image: Dictionary containing 'src' and 'alt' for the 16:9 image. Required for col-6 and col-8.
7
7
  author: Optional string for the author's name. Hidden if no image is provided.
8
8
  date: Optional string for the publication date. Hidden if no image is provided.
9
9
  footer: Dictionary containing 'resource_type' (icon and text) and 'content_type' (read-only chip).
10
- description: Optional text that slides up on hover, truncating at 4 lines.
10
+ description: Optional text. For col-2/4/6 slides up on hover (4 lines; 2 for col-6). For col-8 always visible below the heading (3 lines desktop/tablet, 2 lines mobile).
11
11
 
12
12
  Variants:
13
13
  col-2: 2-column width card layout (Vertical)
14
14
  Params: columns (2), heading (req), link (req), image (opt), author (opt, hidden if no image), date (opt, hidden if no image), footer (opt), description (opt)
15
-
15
+
16
16
  col-4: 4-column width card layout (Horizontal)
17
17
  Params: columns (4), heading (req), link (req), image (opt), footer (opt), description (opt)
18
-
18
+
19
19
  col-6: 6-column width card layout (Horizontal)
20
20
  Params: columns (6), heading (req), link (req), image (req), author (opt), date (opt), footer (opt), description (opt)
21
+
22
+ col-8: 8-column (full-width) card layout (50/50 horizontal on desktop, vertical stack on mobile/tablet)
23
+ Heading uses h4 with p-heading--1 styling. Image appears on the right on desktop, above heading on mobile/tablet.
24
+ Params: columns (8), heading (req), link (req), image (req), author (opt), date (opt), footer (opt), description (opt)
21
25
  #}
22
26
 
23
27
  {%- macro vf_card(columns="2", link=None, heading=None, image=None, author=None, date=None, footer=None, description=None) -%}
@@ -26,11 +30,12 @@
26
30
  {%- set layout = 'p-content-card--cols-' ~ col_str -%}
27
31
  {%- set img_class = 'has-image' if image else '' -%}
28
32
  {%- set has_desc = 'has-desc' if description else '' -%}
33
+ {%- set heading_extra_class = 'p-heading--1 ' if col_str == '8' else '' -%}
29
34
 
30
35
  <div class="p-content-card-wrapper p-content-card-wrapper--{{ col_str }}">
31
-
36
+
32
37
  <div class="p-content-card {{ layout }} {{ img_class }} {{ has_desc }}">
33
-
38
+
34
39
  {%- if link -%}
35
40
  <a href="{{ link }}" class="p-content-card__overlay-link" tabindex="-1" aria-hidden="true"></a>
36
41
  {%- endif -%}
@@ -43,16 +48,16 @@
43
48
 
44
49
  <div class="p-content-card__content">
45
50
  <div class="p-content-card__body">
46
-
51
+
47
52
  <div class="p-content-card__primary-content">
48
- <h4 class="p-content-card__heading">
53
+ <h4 class="{{ heading_extra_class }}p-content-card__heading">
49
54
  {%- if link -%}
50
55
  <a href="{{ link }}" class="p-content-card__main-link">{{ heading }}</a>
51
56
  {%- else -%}
52
57
  {{ heading }}
53
58
  {%- endif -%}
54
59
  </h4>
55
-
60
+
56
61
  {%- if image and (author or date) -%}
57
62
  <div class="p-content-card__author-and-date u-sv-3">
58
63
  <small>
@@ -72,7 +77,7 @@
72
77
  {%- endif -%}
73
78
 
74
79
  </div>
75
-
80
+
76
81
  {%- if footer -%}
77
82
  <div class="p-content-card__footer-container">
78
83
  <hr class="p-rule--muted">
@@ -95,4 +100,5 @@
95
100
  </div>
96
101
  </div>
97
102
  </div>
103
+
98
104
  {%- endmacro -%}
@@ -4,16 +4,20 @@
4
4
  # is_list_full_width_on_tablet: whether list title/description each have their
5
5
  # own row on tablet vs. 50/50 split between title/description
6
6
  # padding: Type of padding to apply. Options are "deep", "shallow", "default". Default is "default".
7
+ # top_rule_variant: Variant of the horizontal rule rendered at the top of the pattern.
8
+ # Options are "default", "muted", "highlighted", "none". Default is "default".
7
9
  # Slots
8
10
  # title: top-level title element
9
11
  # description: top-level description element
10
12
  # list_item_title_[1-25]: title element of each child list item
11
13
  # list_item_description_[1-25]: description element of each child list item
12
14
  # cta: CTA block element
15
+ {% from "_macros/shared/vf_section_top_rule.jinja" import vf_section_top_rule %}
13
16
  {% macro vf_tiered_list(
14
17
  padding="default",
15
18
  is_description_full_width_on_desktop=true,
16
- is_list_full_width_on_tablet=true) -%}
19
+ is_list_full_width_on_tablet=true,
20
+ top_rule_variant="default") -%}
17
21
  {%- set title_content = caller('title') -%}
18
22
  {%- set description_content = caller('description') -%}
19
23
  {%- set has_description = description_content|trim|length > 0 -%}
@@ -30,7 +34,7 @@
30
34
  {%- endif -%}
31
35
 
32
36
  <div class="{{ padding_classes }} u-fixed-width">
33
- <hr class="p-rule">
37
+ {{ vf_section_top_rule(top_rule_variant) }}
34
38
  <div class="p-section--shallow">
35
39
  {% if has_description == true -%}
36
40
  {%- if is_description_full_width_on_desktop == true -%}
@@ -67,7 +67,7 @@
67
67
  // if it's a demo, use local build.css for better QA, otherwise use latest published Vanilla
68
68
  /demos\.haus$/.test(window.location.host)
69
69
  ? `${window.location.origin}/static/build/css/build.css`
70
- : 'https://assets.ubuntu.com/v1/vanilla_framework_version_' + VANILLA_VERSION.replaceAll('.', '_') + '_min.css',
70
+ : 'https://assets.ubuntu.com/v1/vanilla_framework_version_' + VANILLA_VERSION + '.min.css',
71
71
  // link to example stylesheet (to set margin on body)
72
72
  'https://assets.ubuntu.com/v1/4653d9ba-example.css',
73
73
  ],