@dogsbay/docs-layout 0.2.0-beta.94 → 0.2.0-beta.95
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 +3 -3
- package/src/BlogIndex.astro +51 -46
- package/src/DocsLayout.astro +41 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/docs-layout",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.95",
|
|
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.
|
|
34
|
-
"@dogsbay/ui": "0.2.0-beta.
|
|
33
|
+
"@dogsbay/primitives": "0.2.0-beta.95",
|
|
34
|
+
"@dogsbay/ui": "0.2.0-beta.95"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"happy-dom": "^20.10.6",
|
package/src/BlogIndex.astro
CHANGED
|
@@ -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
|
-
|
|
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="
|
|
84
|
-
<
|
|
85
|
-
{post.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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="
|
|
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
|
-
|
|
99
|
-
)}
|
|
112
|
+
)}
|
|
100
113
|
|
|
101
|
-
|
|
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
|
-
</
|
|
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">·</span>
|
|
125
|
-
)}
|
|
126
|
-
{post.date && <time datetime={post.date}>{formatDate(post.date)}</time>}
|
|
127
118
|
{/*
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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">·</span>
|
|
132
|
+
)}
|
|
133
|
+
{post.date && <time datetime={post.date}>{formatDate(post.date)}</time>}
|
|
134
|
+
{(post.author?.length || post.date) && <span aria-hidden="true">·</span>}
|
|
135
|
+
<span>{post.readingMinutes} min read</span>
|
|
136
|
+
</div>
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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>
|
package/src/DocsLayout.astro
CHANGED
|
@@ -432,6 +432,18 @@ interface Props {
|
|
|
432
432
|
readingMinutes?: number;
|
|
433
433
|
/** Optional hero image URL, rendered above the prose. */
|
|
434
434
|
heroImage?: string;
|
|
435
|
+
/**
|
|
436
|
+
* Series position, when the post belongs to one. Derived at emit time
|
|
437
|
+
* from publication order, so "Part 3 of 7" cannot disagree with reality
|
|
438
|
+
* the way a hand-typed line does.
|
|
439
|
+
*/
|
|
440
|
+
series?: {
|
|
441
|
+
name: string;
|
|
442
|
+
part: number;
|
|
443
|
+
total: number;
|
|
444
|
+
/** URL of part 1, so a reader landing mid-series can start over. */
|
|
445
|
+
startHref?: string;
|
|
446
|
+
};
|
|
435
447
|
/**
|
|
436
448
|
* Table-of-contents placement. Default `"top"`.
|
|
437
449
|
* - `"top"` — expandable "On this page" disclosure at the top of the
|
|
@@ -521,6 +533,7 @@ const {
|
|
|
521
533
|
updatedDate,
|
|
522
534
|
readingMinutes,
|
|
523
535
|
heroImage,
|
|
536
|
+
series,
|
|
524
537
|
linkIcons,
|
|
525
538
|
class: className,
|
|
526
539
|
} = Astro.props;
|
|
@@ -1155,6 +1168,34 @@ const siteIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
|
|
1155
1168
|
</div>
|
|
1156
1169
|
)}
|
|
1157
1170
|
|
|
1171
|
+
{/*
|
|
1172
|
+
Series banner. Sits above the byline because it is the
|
|
1173
|
+
first thing a reader arriving from search needs: which
|
|
1174
|
+
series is this, where am I in it, and where does it start.
|
|
1175
|
+
A blog index is chronological, so someone can easily meet
|
|
1176
|
+
part 7 first.
|
|
1177
|
+
*/}
|
|
1178
|
+
{chrome === "blog" && series && (
|
|
1179
|
+
<div
|
|
1180
|
+
class="not-prose mb-4 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-md border border-border bg-muted/40 px-3 py-2 text-sm"
|
|
1181
|
+
data-post-series
|
|
1182
|
+
data-pagefind-ignore
|
|
1183
|
+
>
|
|
1184
|
+
<span class="font-medium text-foreground">
|
|
1185
|
+
Part {series.part} of {series.total}
|
|
1186
|
+
</span>
|
|
1187
|
+
<span class="text-muted-foreground">in {series.name}</span>
|
|
1188
|
+
{series.startHref && series.part !== 1 && (
|
|
1189
|
+
<a
|
|
1190
|
+
href={series.startHref}
|
|
1191
|
+
class="ml-auto text-foreground underline underline-offset-2"
|
|
1192
|
+
>
|
|
1193
|
+
Start at part 1
|
|
1194
|
+
</a>
|
|
1195
|
+
)}
|
|
1196
|
+
</div>
|
|
1197
|
+
)}
|
|
1198
|
+
|
|
1158
1199
|
{autoLede && description && (
|
|
1159
1200
|
<p class="text-lg text-muted-foreground mb-6">
|
|
1160
1201
|
{description}
|