@xexr/blog-platform 1.0.9 → 1.0.10
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/dist/app/blog/[slug]/page.tsx +117 -13
- package/dist/index.d.mts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +51 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -11
- package/dist/index.mjs.map +1 -1
- package/dist/lib/storage/drizzle.ts +15 -0
- package/dist/types/contracts.ts +9 -0
- package/dist/types/index.d.mts +6 -0
- package/dist/types/index.d.ts +6 -0
- package/package.json +1 -1
|
@@ -86,6 +86,46 @@ function formatReadingTime(seconds: number): string {
|
|
|
86
86
|
return `${minutes} min read`;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
function formatCreditUrl(url: string): string {
|
|
90
|
+
try {
|
|
91
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
92
|
+
} catch {
|
|
93
|
+
return url;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function FeaturedImageCredit({
|
|
98
|
+
creditText,
|
|
99
|
+
creditUrl,
|
|
100
|
+
}: {
|
|
101
|
+
creditText?: string;
|
|
102
|
+
creditUrl?: string;
|
|
103
|
+
}) {
|
|
104
|
+
if (!creditText && !creditUrl) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const label = creditText ?? formatCreditUrl(creditUrl ?? "");
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<span>
|
|
112
|
+
Credit:{" "}
|
|
113
|
+
{creditUrl ? (
|
|
114
|
+
<a
|
|
115
|
+
href={creditUrl}
|
|
116
|
+
target="_blank"
|
|
117
|
+
rel="noreferrer"
|
|
118
|
+
className="underline underline-offset-2 transition-colors hover:text-[var(--blog-text-accent)]"
|
|
119
|
+
>
|
|
120
|
+
{label}
|
|
121
|
+
</a>
|
|
122
|
+
) : (
|
|
123
|
+
label
|
|
124
|
+
)}
|
|
125
|
+
</span>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
89
129
|
export default function ArticlePage({
|
|
90
130
|
article,
|
|
91
131
|
className,
|
|
@@ -109,6 +149,11 @@ export default function ArticlePage({
|
|
|
109
149
|
|
|
110
150
|
// Use the featured image URL provided by Bloggy (hosted on Bloggy's domain)
|
|
111
151
|
const imageUrl = article.featuredImage;
|
|
152
|
+
const hasFeaturedImageMeta = Boolean(
|
|
153
|
+
article.featuredImageCaption ??
|
|
154
|
+
article.featuredImageCreditText ??
|
|
155
|
+
article.featuredImageCreditUrl,
|
|
156
|
+
);
|
|
112
157
|
|
|
113
158
|
return (
|
|
114
159
|
<article
|
|
@@ -140,6 +185,45 @@ export default function ArticlePage({
|
|
|
140
185
|
</header>
|
|
141
186
|
)}
|
|
142
187
|
|
|
188
|
+
<style>{`
|
|
189
|
+
.article-content figure > p {
|
|
190
|
+
margin-top: 0 !important;
|
|
191
|
+
margin-bottom: 0 !important;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.article-content figure figcaption {
|
|
195
|
+
margin-top: 0.5rem !important;
|
|
196
|
+
text-align: center;
|
|
197
|
+
font-size: 0.875rem !important;
|
|
198
|
+
line-height: 1.35 !important;
|
|
199
|
+
color: hsl(var(--muted-foreground));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.article-content figure figcaption .blog-image-credit {
|
|
203
|
+
display: block;
|
|
204
|
+
margin-top: 0.25rem;
|
|
205
|
+
font-size: 0.75rem;
|
|
206
|
+
line-height: 1.25;
|
|
207
|
+
letter-spacing: 0.025em;
|
|
208
|
+
opacity: 0.8;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.article-content figure figcaption > span:not(.blog-image-credit) {
|
|
212
|
+
margin-left: 0.5rem;
|
|
213
|
+
padding-left: 0.5rem;
|
|
214
|
+
border-left: 1px solid var(--blog-accent-border);
|
|
215
|
+
font-size: 0.75rem;
|
|
216
|
+
letter-spacing: 0.025em;
|
|
217
|
+
opacity: 0.8;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.article-content figure figcaption a {
|
|
221
|
+
color: inherit;
|
|
222
|
+
text-decoration-line: underline;
|
|
223
|
+
text-underline-offset: 0.18em;
|
|
224
|
+
}
|
|
225
|
+
`}</style>
|
|
226
|
+
|
|
143
227
|
{/* Article Header */}
|
|
144
228
|
<header className="article-header mx-auto mb-6 max-w-4xl space-y-4 text-center sm:mb-8 sm:space-y-6 lg:mb-12 lg:space-y-8">
|
|
145
229
|
{/* Title */}
|
|
@@ -237,18 +321,38 @@ export default function ArticlePage({
|
|
|
237
321
|
|
|
238
322
|
{/* Featured Image */}
|
|
239
323
|
{imageUrl && (
|
|
240
|
-
<
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
324
|
+
<figure className="article-featured-image mx-auto my-8 w-full max-w-4xl sm:my-12 lg:my-16">
|
|
325
|
+
<div className="aspect-[16/9] overflow-hidden rounded-3xl border border-[var(--blog-accent-border)] shadow-[0_24px_80px_rgb(168_85_247_/_0.14)]">
|
|
326
|
+
<Image
|
|
327
|
+
src={imageUrl}
|
|
328
|
+
alt={
|
|
329
|
+
article.featuredImageAlt ??
|
|
330
|
+
`Featured image for ${article.title}`
|
|
331
|
+
}
|
|
332
|
+
className="h-full w-full object-cover"
|
|
333
|
+
width={800}
|
|
334
|
+
height={450}
|
|
335
|
+
priority
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
{hasFeaturedImageMeta && (
|
|
340
|
+
<figcaption className="text-muted-foreground mt-3 space-y-1 px-2 text-center text-sm leading-relaxed sm:px-0">
|
|
341
|
+
{article.featuredImageCaption && (
|
|
342
|
+
<p>{article.featuredImageCaption}</p>
|
|
343
|
+
)}
|
|
344
|
+
{(article.featuredImageCreditText ??
|
|
345
|
+
article.featuredImageCreditUrl) && (
|
|
346
|
+
<p className="text-xs">
|
|
347
|
+
<FeaturedImageCredit
|
|
348
|
+
creditText={article.featuredImageCreditText}
|
|
349
|
+
creditUrl={article.featuredImageCreditUrl}
|
|
350
|
+
/>
|
|
351
|
+
</p>
|
|
352
|
+
)}
|
|
353
|
+
</figcaption>
|
|
354
|
+
)}
|
|
355
|
+
</figure>
|
|
252
356
|
)}
|
|
253
357
|
|
|
254
358
|
{/* Article Content */}
|
|
@@ -265,7 +369,7 @@ export default function ArticlePage({
|
|
|
265
369
|
|
|
266
370
|
<div
|
|
267
371
|
id="article-body"
|
|
268
|
-
className="prose prose-sm sm:prose-base lg:prose-lg xl:prose-xl prose-gray dark:prose-invert prose-headings:scroll-mt-20 prose-headings:font-light prose-headings:text-balance prose-headings:text-[var(--blog-text-accent)] prose-h1:text-2xl sm:prose-h1:text-3xl lg:prose-h1:text-4xl prose-h2:text-xl sm:prose-h2:text-2xl lg:prose-h2:text-3xl prose-h3:text-lg sm:prose-h3:text-xl lg:prose-h3:text-2xl prose-p:leading-relaxed prose-p:text-pretty prose-a:text-[var(--blog-text-accent)] prose-a:transition-colors hover:prose-a:text-[var(--blog-text-accent-hover)] max-w-none"
|
|
372
|
+
className="prose prose-sm sm:prose-base lg:prose-lg xl:prose-xl prose-gray dark:prose-invert prose-headings:scroll-mt-20 prose-headings:font-light prose-headings:text-balance prose-headings:text-[var(--blog-text-accent)] prose-h1:text-2xl sm:prose-h1:text-3xl lg:prose-h1:text-4xl prose-h2:text-xl sm:prose-h2:text-2xl lg:prose-h2:text-3xl prose-h3:text-lg sm:prose-h3:text-xl lg:prose-h3:text-2xl prose-p:leading-relaxed prose-p:text-pretty prose-a:text-[var(--blog-text-accent)] prose-a:transition-colors hover:prose-a:text-[var(--blog-text-accent-hover)] [&_figure>p]:!my-0 [&_figcaption]:!mt-2 [&_figcaption]:text-center [&_figcaption]:!text-sm [&_figcaption]:!leading-snug [&_figcaption]:text-muted-foreground [&_figcaption_.blog-image-credit]:mt-1 [&_figcaption_.blog-image-credit]:block [&_figcaption_.blog-image-credit]:text-xs [&_figcaption_.blog-image-credit]:tracking-wide [&_figcaption_.blog-image-credit]:text-muted-foreground/80 [&_figcaption>span:not(.blog-image-credit)]:ml-2 [&_figcaption>span:not(.blog-image-credit)]:border-l [&_figcaption>span:not(.blog-image-credit)]:border-[var(--blog-accent-border)] [&_figcaption>span:not(.blog-image-credit)]:pl-2 [&_figcaption>span:not(.blog-image-credit)]:text-xs [&_figcaption>span:not(.blog-image-credit)]:tracking-wide [&_figcaption>span:not(.blog-image-credit)]:text-muted-foreground/80 max-w-none"
|
|
269
373
|
>
|
|
270
374
|
<MDXRemote
|
|
271
375
|
source={article.content}
|
package/dist/index.d.mts
CHANGED
|
@@ -894,6 +894,63 @@ declare const bpArticles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
894
894
|
}, {}, {
|
|
895
895
|
length: number | undefined;
|
|
896
896
|
}>;
|
|
897
|
+
featuredImageCaption: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
898
|
+
name: "featured_image_caption";
|
|
899
|
+
tableName: "bp_articles";
|
|
900
|
+
dataType: "string";
|
|
901
|
+
columnType: "SQLiteText";
|
|
902
|
+
data: string;
|
|
903
|
+
driverParam: string;
|
|
904
|
+
notNull: false;
|
|
905
|
+
hasDefault: false;
|
|
906
|
+
isPrimaryKey: false;
|
|
907
|
+
isAutoincrement: false;
|
|
908
|
+
hasRuntimeDefault: false;
|
|
909
|
+
enumValues: [string, ...string[]];
|
|
910
|
+
baseColumn: never;
|
|
911
|
+
identity: undefined;
|
|
912
|
+
generated: undefined;
|
|
913
|
+
}, {}, {
|
|
914
|
+
length: number | undefined;
|
|
915
|
+
}>;
|
|
916
|
+
featuredImageCreditText: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
917
|
+
name: "featured_image_credit_text";
|
|
918
|
+
tableName: "bp_articles";
|
|
919
|
+
dataType: "string";
|
|
920
|
+
columnType: "SQLiteText";
|
|
921
|
+
data: string;
|
|
922
|
+
driverParam: string;
|
|
923
|
+
notNull: false;
|
|
924
|
+
hasDefault: false;
|
|
925
|
+
isPrimaryKey: false;
|
|
926
|
+
isAutoincrement: false;
|
|
927
|
+
hasRuntimeDefault: false;
|
|
928
|
+
enumValues: [string, ...string[]];
|
|
929
|
+
baseColumn: never;
|
|
930
|
+
identity: undefined;
|
|
931
|
+
generated: undefined;
|
|
932
|
+
}, {}, {
|
|
933
|
+
length: number | undefined;
|
|
934
|
+
}>;
|
|
935
|
+
featuredImageCreditUrl: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
936
|
+
name: "featured_image_credit_url";
|
|
937
|
+
tableName: "bp_articles";
|
|
938
|
+
dataType: "string";
|
|
939
|
+
columnType: "SQLiteText";
|
|
940
|
+
data: string;
|
|
941
|
+
driverParam: string;
|
|
942
|
+
notNull: false;
|
|
943
|
+
hasDefault: false;
|
|
944
|
+
isPrimaryKey: false;
|
|
945
|
+
isAutoincrement: false;
|
|
946
|
+
hasRuntimeDefault: false;
|
|
947
|
+
enumValues: [string, ...string[]];
|
|
948
|
+
baseColumn: never;
|
|
949
|
+
identity: undefined;
|
|
950
|
+
generated: undefined;
|
|
951
|
+
}, {}, {
|
|
952
|
+
length: number | undefined;
|
|
953
|
+
}>;
|
|
897
954
|
authorJson: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
898
955
|
name: "author_json";
|
|
899
956
|
tableName: "bp_articles";
|
package/dist/index.d.ts
CHANGED
|
@@ -894,6 +894,63 @@ declare const bpArticles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
894
894
|
}, {}, {
|
|
895
895
|
length: number | undefined;
|
|
896
896
|
}>;
|
|
897
|
+
featuredImageCaption: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
898
|
+
name: "featured_image_caption";
|
|
899
|
+
tableName: "bp_articles";
|
|
900
|
+
dataType: "string";
|
|
901
|
+
columnType: "SQLiteText";
|
|
902
|
+
data: string;
|
|
903
|
+
driverParam: string;
|
|
904
|
+
notNull: false;
|
|
905
|
+
hasDefault: false;
|
|
906
|
+
isPrimaryKey: false;
|
|
907
|
+
isAutoincrement: false;
|
|
908
|
+
hasRuntimeDefault: false;
|
|
909
|
+
enumValues: [string, ...string[]];
|
|
910
|
+
baseColumn: never;
|
|
911
|
+
identity: undefined;
|
|
912
|
+
generated: undefined;
|
|
913
|
+
}, {}, {
|
|
914
|
+
length: number | undefined;
|
|
915
|
+
}>;
|
|
916
|
+
featuredImageCreditText: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
917
|
+
name: "featured_image_credit_text";
|
|
918
|
+
tableName: "bp_articles";
|
|
919
|
+
dataType: "string";
|
|
920
|
+
columnType: "SQLiteText";
|
|
921
|
+
data: string;
|
|
922
|
+
driverParam: string;
|
|
923
|
+
notNull: false;
|
|
924
|
+
hasDefault: false;
|
|
925
|
+
isPrimaryKey: false;
|
|
926
|
+
isAutoincrement: false;
|
|
927
|
+
hasRuntimeDefault: false;
|
|
928
|
+
enumValues: [string, ...string[]];
|
|
929
|
+
baseColumn: never;
|
|
930
|
+
identity: undefined;
|
|
931
|
+
generated: undefined;
|
|
932
|
+
}, {}, {
|
|
933
|
+
length: number | undefined;
|
|
934
|
+
}>;
|
|
935
|
+
featuredImageCreditUrl: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
936
|
+
name: "featured_image_credit_url";
|
|
937
|
+
tableName: "bp_articles";
|
|
938
|
+
dataType: "string";
|
|
939
|
+
columnType: "SQLiteText";
|
|
940
|
+
data: string;
|
|
941
|
+
driverParam: string;
|
|
942
|
+
notNull: false;
|
|
943
|
+
hasDefault: false;
|
|
944
|
+
isPrimaryKey: false;
|
|
945
|
+
isAutoincrement: false;
|
|
946
|
+
hasRuntimeDefault: false;
|
|
947
|
+
enumValues: [string, ...string[]];
|
|
948
|
+
baseColumn: never;
|
|
949
|
+
identity: undefined;
|
|
950
|
+
generated: undefined;
|
|
951
|
+
}, {}, {
|
|
952
|
+
length: number | undefined;
|
|
953
|
+
}>;
|
|
897
954
|
authorJson: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
898
955
|
name: "author_json";
|
|
899
956
|
tableName: "bp_articles";
|