diff --git a/DESIGN.md b/DESIGN.md index 6698a7f9..25adb52c 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -347,7 +347,7 @@ Motifs carry data. Each answers one pitch line from `COPY.md` and spends one ros **Run chip.** It pairs with "No more skill bloat". Run and install sit side by side, and run is preselected. Run has a dashed border and a hollow rose dot, because nothing stays. Install has a solid border and a filled dot, because files land. A consequence line under the chip says what each choice leaves on disk. -**Braille spark.** It pairs with "Stay hyped". Seven braille bars (`⣀⣤⣶⣿`) show seven days of social mentions, with today in rose. The mention count sits beside it. The spark is made of characters, so the same line works on the site, in the weekly email, in Discord and in a terminal. It replaces the trending flame emoji. +**Braille spark.** It pairs with "Stay hyped". Seven braille bars (`⣀⣤⣶⣿`) show seven days of social mentions, with today in rose. The mention count sits beside it, with its noun from `sparkCount`, so one mention reads "1 mention". On the site, a day with no mentions draws the lowest bar at 40% opacity as a track, so a lone bar still reads as one day of seven. Plain text keeps the blank cell. The spark is made of characters, so the same line works on the site, in the weekly email, in Discord and in a terminal. It replaces the trending flame emoji. **Change grid.** It pairs with "Keep updated". A 13-week grid of days, today at the bottom right. Each change is a stone dot, and the newest change is rose. A ring around a dot shows the size of the version bump, only where a version is known. @@ -459,3 +459,4 @@ These are editorial sets, not necessarily database collections yet. If a set has - **The braille spark replaces the trending flame**: seven braille bars for seven days of mentions, today in rose. The emoji exception for Trending is retired. The spark keeps the sourced mention count beside it, which the flame never carried. Confirmed 2026-10-06. - **Run and install read as different materials**: run is a dashed border with a hollow dot, because nothing stays; install is a solid border with a filled dot, because files land. Run is preselected. Confirmed 2026-10-06. - **Trending shares the /skills shell**: `/skills/trending` uses the full-width layout from `/skills`. Its heading replaces `CompactPageHeader` and lines up with the results column. A sticky 14rem sidebar holds the range links, then the weekly CTA and the skilld install. Nothing sits right of the board, so the board takes every column the sidebar leaves. Rows switch on their own width, and the post carousel shows two cards where it has room. On narrow screens the ranges are a compact row above the board, and the CTA stays after the fifth row. Harlan asked for this on 2026-10-06. It supersedes the 2026-10-01 call that dropped the 9/3 sidebar for taking a quarter of the board's width: that sidebar sat right of a 64rem board, and this one sits left of a board that runs the full page width. +- **Trending rows scan in one pass**: the rank is a plain mono number, and the first three are a step darker. Each metadata line runs source, stars, then the signal that ranked the row, and an empty slot renders nothing. Descriptions stop at two lines, the run chip is as wide as its command, and the post carousel shows whole cards only. The sidebar invitation drops the email preview and the card. Its button is the rail's one solid rose element, so the install chip beside it inks its dot. Harlan asked for this polish on 2026-10-06. 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 `