@dogsbay/docs-layout 0.2.0-beta.94 → 0.2.0-beta.96

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": "@dogsbay/docs-layout",
3
- "version": "0.2.0-beta.94",
3
+ "version": "0.2.0-beta.96",
4
4
  "description": "Standard documentation layout components for Dogsbay",
5
5
  "type": "module",
6
6
  "exports": {
@@ -30,8 +30,8 @@
30
30
  "./json-ld": "./src/json-ld.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@dogsbay/primitives": "0.2.0-beta.94",
34
- "@dogsbay/ui": "0.2.0-beta.94"
33
+ "@dogsbay/primitives": "0.2.0-beta.96",
34
+ "@dogsbay/ui": "0.2.0-beta.96"
35
35
  },
36
36
  "devDependencies": {
37
37
  "happy-dom": "^20.10.6",
@@ -14,6 +14,8 @@
14
14
  * docs, so there is no blog palette, no blog typography scale, and no
15
15
  * second set of card styles to keep in sync.
16
16
  */
17
+ import Card from "@dogsbay/ui/card/Card.astro";
18
+
17
19
  interface BlogPostRef {
18
20
  slug: string;
19
21
  title: string;
@@ -78,65 +80,68 @@ const hrefForPage = (n: number): string => (n === 1 ? `${base}/` : `${base}/page
78
80
  <p class="text-muted-foreground">No posts yet.</p>
79
81
  )}
80
82
 
81
- <ul class="not-prose flex flex-col gap-8" data-blog-index>
83
+ {/*
84
+ Three across at lg, two at sm, one on mobile. The card is one link, not
85
+ a card containing links: nesting interactive elements inside a clickable
86
+ card is the classic keyboard-and-screen-reader trap, so tags and other
87
+ links stay off the card and live on the post page instead.
88
+
89
+ `items-stretch` + `h-full` keeps a short post's card the same height as
90
+ a long one's — ragged card bottoms are the thing that makes a grid look
91
+ broken rather than sparse.
92
+ */}
93
+ <ul
94
+ class="not-prose grid list-none grid-cols-1 items-stretch gap-6 p-0 sm:grid-cols-2 lg:grid-cols-3"
95
+ data-blog-index
96
+ >
82
97
  {posts.map((post) => (
83
- <li class="group">
84
- <article class="flex flex-col gap-2">
85
- {post.heroImage && (
86
- <a href={post.url} tabindex="-1" aria-hidden="true">
87
- {/*
88
- aspect-boxed for the same reason as the post hero: an
89
- unsized image in a list shifts every card below it.
90
- */}
98
+ <li class="m-0 p-0">
99
+ <a
100
+ href={post.url}
101
+ class="group block h-full rounded-lg no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
102
+ >
103
+ <Card class="flex h-full flex-col gap-3 p-5 transition-colors group-hover:border-ring">
104
+ {post.heroImage && (
91
105
  <img
92
106
  src={post.heroImage}
93
107
  alt=""
94
- class="mb-2 w-full rounded-lg border border-border object-cover aspect-[2/1]"
108
+ class="aspect-[16/9] w-full rounded-md border border-border object-cover"
95
109
  loading="lazy"
96
110
  decoding="async"
97
111
  />
98
- </a>
99
- )}
112
+ )}
100
113
 
101
- <h2 class="text-xl font-semibold tracking-tight">
102
- <a
103
- href={post.url}
104
- class="text-foreground no-underline hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm"
105
- >
114
+ <h2 class="text-lg font-semibold leading-snug tracking-tight text-foreground group-hover:underline">
106
115
  {post.title}
107
- </a>
108
- </h2>
116
+ </h2>
109
117
 
110
- {/*
111
- Byline mirrors the post page's, minus the reading estimate's
112
- separator noise. data-pagefind-ignore because the same values
113
- are indexed as structured filters on the post itself; without
114
- it, every card's date leads its search excerpt.
115
- */}
116
- <div
117
- class="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-muted-foreground"
118
- data-pagefind-ignore
119
- >
120
- {post.author && post.author.length > 0 && (
121
- <span class="font-medium text-foreground">{post.author.join(", ")}</span>
122
- )}
123
- {post.author && post.author.length > 0 && post.date && (
124
- <span aria-hidden="true">&middot;</span>
125
- )}
126
- {post.date && <time datetime={post.date}>{formatDate(post.date)}</time>}
127
118
  {/*
128
- Guarded like the post page's byline. Unconditional, a post with
129
- neither author nor date opened with a stray 5 min read", and
130
- the card disagreed with the page it linked to.
119
+ data-pagefind-ignore: the same values are indexed as structured
120
+ filters on the post itself. Without it every card's date leads
121
+ its search excerpt.
131
122
  */}
132
- {(post.author?.length || post.date) && <span aria-hidden="true">&middot;</span>}
133
- <span>{post.readingMinutes} min read</span>
134
- </div>
123
+ <div
124
+ class="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground"
125
+ data-pagefind-ignore
126
+ >
127
+ {post.author && post.author.length > 0 && (
128
+ <span class="font-medium text-foreground">{post.author.join(", ")}</span>
129
+ )}
130
+ {post.author && post.author.length > 0 && post.date && (
131
+ <span aria-hidden="true">&middot;</span>
132
+ )}
133
+ {post.date && <time datetime={post.date}>{formatDate(post.date)}</time>}
134
+ {(post.author?.length || post.date) && <span aria-hidden="true">&middot;</span>}
135
+ <span>{post.readingMinutes} min read</span>
136
+ </div>
135
137
 
136
- {post.description && (
137
- <p class="text-muted-foreground">{post.description}</p>
138
- )}
139
- </article>
138
+ {post.description && (
139
+ <p class="m-0 text-sm leading-relaxed text-muted-foreground">
140
+ {post.description}
141
+ </p>
142
+ )}
143
+ </Card>
144
+ </a>
140
145
  </li>
141
146
  ))}
142
147
  </ul>
@@ -1224,10 +1224,12 @@ const siteIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
1224
1224
  next={next}
1225
1225
  {/*
1226
1226
  Blog adjacency is chronological, so "Previous/Next"
1227
- would describe the wrong axis prev is the NEWER post.
1227
+ describes the wrong axis. Left is older, right is newer
1228
+ a timeline runs that way, and so does a series: the
1229
+ right-hand link is the next part.
1228
1230
  */}
1229
- prevLabel={chrome === "blog" ? "Newer" : undefined}
1230
- nextLabel={chrome === "blog" ? "Older" : undefined}
1231
+ prevLabel={chrome === "blog" ? "Older" : undefined}
1232
+ nextLabel={chrome === "blog" ? "Newer" : undefined}
1231
1233
  copyright={copyright}
1232
1234
  llmsLink={llmFooterLink}
1233
1235
  llmsLinkHref={llmsLinkHrefResolved}