@levino/shipyard-blog 0.6.3 → 0.7.1
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/astro/BlogIndex.astro +101 -21
- package/astro/BlogIndexPaginated.astro +30 -8
- package/astro/BlogTags.astro +2 -2
- package/package.json +2 -2
package/astro/BlogIndex.astro
CHANGED
|
@@ -135,38 +135,118 @@ const tagBaseUrl = i18n
|
|
|
135
135
|
|
|
136
136
|
<Layout title={blogConfig.blogTitle}>
|
|
137
137
|
<div class="max-w-7xl mx-auto">
|
|
138
|
-
<h1 class="text-4xl font-bold mb-
|
|
139
|
-
<div class="space-y-
|
|
138
|
+
<h1 class="text-4xl font-bold mb-10">{blogConfig.blogTitle}</h1>
|
|
139
|
+
<div class="space-y-6">
|
|
140
140
|
{
|
|
141
|
-
paginatedEntries.map((entry) => {
|
|
141
|
+
paginatedEntries.map((entry, index) => {
|
|
142
142
|
const readingTime = showReadingTime && entry.body
|
|
143
143
|
? getReadingTime(entry.body)
|
|
144
144
|
: undefined
|
|
145
145
|
const tags = entry.data.tags ?? []
|
|
146
|
+
const postLink = `/${getBlogPostLink(entry.id, Astro.currentLocale)}`
|
|
147
|
+
const hasImage = !!entry.data.image
|
|
148
|
+
const isFirst = index === 0
|
|
146
149
|
|
|
147
|
-
return (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
return isFirst && hasImage ? (
|
|
151
|
+
/* Featured first post — full-width card with image */
|
|
152
|
+
<article class="card bg-base-100 shadow-sm" data-testid="blog-post-item">
|
|
153
|
+
<figure>
|
|
154
|
+
<a href={postLink} data-testid="blog-post-link">
|
|
155
|
+
<img
|
|
156
|
+
src={entry.data.image}
|
|
157
|
+
alt={entry.data.title}
|
|
158
|
+
class="w-full object-cover"
|
|
159
|
+
loading="eager"
|
|
160
|
+
/>
|
|
161
|
+
</a>
|
|
162
|
+
</figure>
|
|
163
|
+
<div class="card-body">
|
|
150
164
|
{entry.data.draft && (
|
|
151
|
-
<span class="badge badge-warning
|
|
165
|
+
<span class="badge badge-warning">Draft</span>
|
|
152
166
|
)}
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
167
|
+
<div class="flex flex-wrap items-center gap-2 text-sm text-base-content/60">
|
|
168
|
+
<time datetime={entry.data.date.toISOString()}>{formatDate(entry.data.date)}</time>
|
|
169
|
+
{readingTime && (
|
|
170
|
+
<>
|
|
171
|
+
<span>·</span>
|
|
172
|
+
<BlogReadingTime text={readingTime.text} />
|
|
173
|
+
</>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
<a class="no-underline" href={postLink}>
|
|
177
|
+
<h2 class="card-title text-2xl md:text-3xl">{entry.data.title}</h2>
|
|
178
|
+
</a>
|
|
179
|
+
<p class="text-base-content/70">{entry.data.description}</p>
|
|
180
|
+
{tags.length > 0 && (
|
|
181
|
+
<div class="card-actions">
|
|
182
|
+
<BlogTags tags={tags} baseUrl={tagBaseUrl} />
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
</article>
|
|
187
|
+
) : hasImage ? (
|
|
188
|
+
/* Post with image — side card */
|
|
189
|
+
<article class="card card-side bg-base-100 shadow-sm" data-testid="blog-post-item">
|
|
190
|
+
<figure class="hidden w-48 flex-shrink-0 sm:block">
|
|
191
|
+
<a href={postLink}>
|
|
192
|
+
<img
|
|
193
|
+
src={entry.data.image}
|
|
194
|
+
alt={entry.data.title}
|
|
195
|
+
class="h-full w-full object-cover"
|
|
196
|
+
loading="lazy"
|
|
197
|
+
/>
|
|
198
|
+
</a>
|
|
199
|
+
</figure>
|
|
200
|
+
<div class="card-body">
|
|
201
|
+
{entry.data.draft && (
|
|
202
|
+
<span class="badge badge-warning">Draft</span>
|
|
203
|
+
)}
|
|
204
|
+
<div class="flex flex-wrap items-center gap-2 text-sm text-base-content/60">
|
|
205
|
+
<time datetime={entry.data.date.toISOString()}>{formatDate(entry.data.date)}</time>
|
|
206
|
+
{readingTime && (
|
|
207
|
+
<>
|
|
208
|
+
<span>·</span>
|
|
209
|
+
<BlogReadingTime text={readingTime.text} />
|
|
210
|
+
</>
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
<a class="no-underline" href={postLink} data-testid="blog-post-link">
|
|
214
|
+
<h2 class="card-title">{entry.data.title}</h2>
|
|
215
|
+
</a>
|
|
216
|
+
<p class="line-clamp-2 text-sm text-base-content/70">{entry.data.description}</p>
|
|
217
|
+
{tags.length > 0 && (
|
|
218
|
+
<div class="card-actions">
|
|
219
|
+
<BlogTags tags={tags} baseUrl={tagBaseUrl} />
|
|
220
|
+
</div>
|
|
162
221
|
)}
|
|
163
222
|
</div>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
223
|
+
</article>
|
|
224
|
+
) : (
|
|
225
|
+
/* Post without image — simple card */
|
|
226
|
+
<article class="card bg-base-100 shadow-sm" data-testid="blog-post-item">
|
|
227
|
+
<div class="card-body">
|
|
228
|
+
{entry.data.draft && (
|
|
229
|
+
<span class="badge badge-warning">Draft</span>
|
|
230
|
+
)}
|
|
231
|
+
<div class="flex flex-wrap items-center gap-2 text-sm text-base-content/60">
|
|
232
|
+
<time datetime={entry.data.date.toISOString()}>{formatDate(entry.data.date)}</time>
|
|
233
|
+
{readingTime && (
|
|
234
|
+
<>
|
|
235
|
+
<span>·</span>
|
|
236
|
+
<BlogReadingTime text={readingTime.text} />
|
|
237
|
+
</>
|
|
238
|
+
)}
|
|
168
239
|
</div>
|
|
169
|
-
|
|
240
|
+
<a class="no-underline" href={postLink} data-testid="blog-post-link">
|
|
241
|
+
<h2 class="card-title">{entry.data.title}</h2>
|
|
242
|
+
</a>
|
|
243
|
+
<p class="line-clamp-2 text-sm text-base-content/70">{entry.data.description}</p>
|
|
244
|
+
{tags.length > 0 && (
|
|
245
|
+
<div class="card-actions">
|
|
246
|
+
<BlogTags tags={tags} baseUrl={tagBaseUrl} />
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
170
250
|
</article>
|
|
171
251
|
)
|
|
172
252
|
})
|
|
@@ -115,15 +115,37 @@ const showRightEllipsis =
|
|
|
115
115
|
|
|
116
116
|
<Layout title="Blog">
|
|
117
117
|
<div class="max-w-7xl mx-auto">
|
|
118
|
-
<div class="
|
|
118
|
+
<div class="space-y-6">
|
|
119
119
|
{
|
|
120
|
-
paginatedEntries.map(async (entry) =>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
paginatedEntries.map(async (entry) => {
|
|
121
|
+
const postLink = `/${getBlogPostLink(entry.id, Astro.currentLocale)}`
|
|
122
|
+
const hasImage = !!entry.data.image
|
|
123
|
+
return (
|
|
124
|
+
<article class:list={["card bg-base-100 shadow-sm", { "card-side": hasImage }]} data-testid="blog-post-item">
|
|
125
|
+
{hasImage && (
|
|
126
|
+
<figure class="hidden w-48 flex-shrink-0 sm:block">
|
|
127
|
+
<a href={postLink}>
|
|
128
|
+
<img
|
|
129
|
+
src={entry.data.image}
|
|
130
|
+
alt={entry.data.title}
|
|
131
|
+
class="h-full w-full object-cover"
|
|
132
|
+
loading="lazy"
|
|
133
|
+
/>
|
|
134
|
+
</a>
|
|
135
|
+
</figure>
|
|
136
|
+
)}
|
|
137
|
+
<div class="card-body">
|
|
138
|
+
<div class="text-sm text-base-content/60">
|
|
139
|
+
<time datetime={entry.data.date.toISOString()}>{formatDate(entry.data.date)}</time>
|
|
140
|
+
</div>
|
|
141
|
+
<a class="no-underline" href={postLink} data-testid="blog-post-link">
|
|
142
|
+
<h2 class="card-title">{entry.data.title}</h2>
|
|
143
|
+
</a>
|
|
144
|
+
<p class="line-clamp-2 text-sm text-base-content/70">{entry.data.description}</p>
|
|
145
|
+
</div>
|
|
146
|
+
</article>
|
|
147
|
+
)
|
|
148
|
+
})
|
|
127
149
|
}
|
|
128
150
|
</div>
|
|
129
151
|
|
package/astro/BlogTags.astro
CHANGED
|
@@ -17,11 +17,11 @@ const { tags, baseUrl = '/blog/tags' } = Astro.props
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
{tags.length > 0 && (
|
|
20
|
-
<div class="flex flex-wrap gap-
|
|
20
|
+
<div class="flex flex-wrap gap-1.5">
|
|
21
21
|
{tags.map((tag) => (
|
|
22
22
|
<a
|
|
23
23
|
href={`${baseUrl}/${encodeURIComponent(tag.toLowerCase())}`}
|
|
24
|
-
class="badge badge-
|
|
24
|
+
class="badge badge-soft badge-sm no-underline hover:badge-primary"
|
|
25
25
|
>
|
|
26
26
|
{tag}
|
|
27
27
|
</a>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@levino/shipyard-blog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Blog plugin for shipyard with pagination, sidebar, and git metadata",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"homepage": "https://shipyard.levinkeller.de",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@levino/shipyard-base": "^0.7.
|
|
34
|
+
"@levino/shipyard-base": "^0.7.1",
|
|
35
35
|
"ramda": "^0.31",
|
|
36
36
|
"yaml": "^2.0.0"
|
|
37
37
|
},
|