From df954b300e3775b4952ab920186c33921e742eeb Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Tue, 6 Oct 2026 03:29:42 +1100 Subject: [PATCH 1/2] fix(trending): agree the spark's mention count with its noun The board passed one fixed plural, "mentions in 7 days", so a Skill with one post read "1 mentions". sparkCount in shared/braille-spark.ts now picks the noun from the count, and BrailleSpark takes the window as a separate period. Both the visible count and the screen reader label use it. A day with no mentions now draws the lowest bar at 40% opacity as a track. Plain text keeps the blank cell. With blank cells, a week with one post was one bar floating in a gap before its label. --- app/components/BrailleSpark.vue | 42 ++++++++++++++----- .../app/components/TrendingBoardItem.vue | 2 +- shared/braille-spark.ts | 20 +++++++++ test/a11y.spec.ts | 11 +++++ test/unit/braille-spark.test.ts | 18 +++++++- 5 files changed, 80 insertions(+), 13 deletions(-) diff --git a/app/components/BrailleSpark.vue b/app/components/BrailleSpark.vue index 31baf383..46f3e896 100644 --- a/app/components/BrailleSpark.vue +++ b/app/components/BrailleSpark.vue @@ -1,37 +1,49 @@ @@ -39,8 +51,8 @@ const label = computed(() => `${shown.value.toLocaleString('en-US')} ${unit}. Pe diff --git a/layers/marketing/app/components/TrendingPostCarousel.vue b/layers/marketing/app/components/TrendingPostCarousel.vue index d3e3dc3f..e53071e2 100644 --- a/layers/marketing/app/components/TrendingPostCarousel.vue +++ b/layers/marketing/app/components/TrendingPostCarousel.vue @@ -12,8 +12,9 @@ import TrendingPostCard from './TrendingPostCard.vue' * does the work, so every post is in the server HTML, a touch screen swipes * it, and focus on a card scrolls that card into view. * - * The next card peeks in from the edge, which is what says there is more. - * Where the carousel is wide enough, two cards show at once. + * Only whole cards show: one, or two where the carousel is wide enough. A + * second card cut off at the board's edge read as a broken layout, not as + * more to come, so the count under the cards says how many there are. */ const { posts, names, label } = defineProps<{ posts: readonly TrendingPost[] @@ -112,25 +113,23 @@ function move(by: number) { .post-carousel__slide { display: flex; - flex: 0 0 88%; + flex: 0 0 100%; min-inline-size: 0; scroll-snap-align: start; } -.post-carousel__slide--only { - flex-basis: 100%; -} - .post-carousel__slide > * { flex: 1; } +/* Under the cards, ending on their right edge. The negative margin takes back the chevron's padding. */ .post-carousel__nav { display: flex; align-items: center; justify-content: flex-end; gap: 0.125rem; margin-top: 0.375rem; + margin-inline-end: -0.25rem; } .post-carousel__count { @@ -143,13 +142,17 @@ function move(by: number) { /* * Two cards at a time once a card would otherwise stretch past a readable - * line. They grow to fill the track when only one or two exist, and a third - * still peeks in from the edge. Two posts side by side leave nothing to step - * through, so they show no controls. + * line, each exactly half the track less the gap, so the second ends on the + * track's edge. A lone post takes the whole track. Two posts side by side + * leave nothing to step through, so they show no controls. */ @container (min-width: 36rem) { .post-carousel__slide { - flex: 1 0 46%; + flex-basis: calc((100% - 0.5rem) / 2); + } + + .post-carousel__slide--only { + flex-basis: 100%; } .post-carousel:has(.post-carousel__slide:nth-child(2):last-child) .post-carousel__nav { diff --git a/layers/marketing/app/components/TrendingWeeklyCta.vue b/layers/marketing/app/components/TrendingWeeklyCta.vue index 7570fa4a..392e70ca 100644 --- a/layers/marketing/app/components/TrendingWeeklyCta.vue +++ b/layers/marketing/app/components/TrendingWeeklyCta.vue @@ -11,7 +11,14 @@ import { useElementVisibility } from '@vueuse/core' * A plain block, not an `