@half-built/astro 0.9.0 → 0.10.0
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/README.md
CHANGED
|
@@ -57,20 +57,37 @@ consumer config itself.
|
|
|
57
57
|
|
|
58
58
|
## WhenPublished and PostLink
|
|
59
59
|
|
|
60
|
-
`content/WhenPublished.astro` renders its children only when the post
|
|
61
|
-
at `slug` is visible, so a published post can tease one still in
|
|
62
|
-
draft and the passage appears on its own when the target ships.
|
|
63
60
|
`content/PostLink.astro` links to a post by slug and resolves the
|
|
64
61
|
href at build time through `postPath`, so a re-dated post does not
|
|
65
|
-
strand the links pointing at it.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
strand the links pointing at it. While the target is hidden (a draft, with the
|
|
63
|
+
draft gate off) it renders its text alone, with no element and no
|
|
64
|
+
styling, and becomes a link on its own when the post ships. That makes
|
|
65
|
+
it the right tool for a draft's name in published prose.
|
|
66
|
+
|
|
67
|
+
`content/WhenPublished.astro` renders its children only when the post
|
|
68
|
+
at `slug` is visible. Use it when a whole phrase only makes sense once
|
|
69
|
+
the post exists ("its own post", "see it here"). An optional `fallback`
|
|
70
|
+
slot renders while the target is hidden:
|
|
71
|
+
|
|
72
|
+
```mdx
|
|
73
|
+
<WhenPublished slug="my-draft">
|
|
74
|
+
It has <PostLink slug="my-draft">its own post</PostLink> now.
|
|
75
|
+
<Fragment slot="fallback">A post on it is coming.</Fragment>
|
|
76
|
+
</WhenPublished>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Both take the consumer's collection as the `posts` prop (the full
|
|
80
|
+
collection, drafts included, so an unknown slug can throw instead of
|
|
81
|
+
hiding as "still a draft") and the consumer's draft gate as
|
|
82
|
+
`showDrafts`. `showDrafts` defaults to false, so a preview build must
|
|
83
|
+
pass its own draft gate through to `PostLink` to keep draft links
|
|
84
|
+
live. `PostLink` also accepts an optional `tip` carried as
|
|
85
|
+
`data-tooltip` for the link-tip island; a hidden `PostLink` drops it. A
|
|
86
|
+
consumer wraps each in a one-line site component that injects
|
|
87
|
+
`getCollection` and its own gate, the way the blog does. The resolvers
|
|
88
|
+
(`postLinkHref`, `resolvePostHref`, `forwardLinkVisible`) live in
|
|
89
|
+
`lib/drafts.ts` for consumers that want the logic without the
|
|
90
|
+
components.
|
|
74
91
|
|
|
75
92
|
## Derived excerpts
|
|
76
93
|
|
package/package.json
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { postLinkHref, type Linkable } from "../../lib/drafts";
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
5
|
slug: string;
|
|
6
6
|
posts: Linkable[];
|
|
7
|
+
showDrafts?: boolean;
|
|
7
8
|
tip?: string;
|
|
8
9
|
class?: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const { slug, posts, tip, class: className } = Astro.props;
|
|
12
|
-
const href =
|
|
12
|
+
const { slug, posts, showDrafts = false, tip, class: className } = Astro.props;
|
|
13
|
+
const href = postLinkHref(slug, posts, showDrafts);
|
|
13
14
|
---
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
{href ? (
|
|
17
|
+
<a href={href} data-tooltip={tip} class={className}>
|
|
18
|
+
<slot />
|
|
19
|
+
</a>
|
|
20
|
+
) : (
|
|
21
|
+
<slot />
|
|
22
|
+
)}
|
package/src/lib/drafts.ts
CHANGED
|
@@ -43,17 +43,21 @@ export function forwardLinkVisible(
|
|
|
43
43
|
/* Post links by slug. A hand-typed post URL bakes in the target's date,
|
|
44
44
|
so a re-dated draft silently breaks every earlier link to it. The
|
|
45
45
|
PostLink content component resolves the slug through postPath() at
|
|
46
|
-
build time instead.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
build time instead. postLinkHref() is its policy: a visible target
|
|
47
|
+
gets its href, a hidden one gets null and the component renders its
|
|
48
|
+
text with no link (owner decision 2026-09-26), so a draft's name can
|
|
49
|
+
sit in published prose and becomes a link on its own when the draft
|
|
50
|
+
ships. resolvePostHref() still resolves drafts: consumers use it for
|
|
51
|
+
lookups keyed by href, and Astro renders MDX slot children eagerly,
|
|
52
|
+
so a PostLink inside a hidden WhenPublished still runs. The
|
|
53
|
+
deploy-build guard against a link to a draft stays a consumer test
|
|
54
|
+
(no draft slug in any built page). Unknown slugs throw for the same
|
|
55
|
+
reason forwardLinkVisible's do. */
|
|
52
56
|
|
|
53
57
|
import { postPath } from "./slug";
|
|
54
58
|
|
|
55
59
|
export interface Linkable {
|
|
56
|
-
data: { slug: string; date: Date };
|
|
60
|
+
data: { slug: string; date: Date; draft?: boolean };
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
export function resolvePostHref(slug: string, posts: Linkable[]): string {
|
|
@@ -61,3 +65,14 @@ export function resolvePostHref(slug: string, posts: Linkable[]): string {
|
|
|
61
65
|
if (!target) throw new Error(`PostLink: no post has slug "${slug}"`);
|
|
62
66
|
return postPath(target);
|
|
63
67
|
}
|
|
68
|
+
|
|
69
|
+
export function postLinkHref(
|
|
70
|
+
slug: string,
|
|
71
|
+
posts: Linkable[],
|
|
72
|
+
showDrafts: boolean,
|
|
73
|
+
): string | null {
|
|
74
|
+
const target = posts.find((p) => p.data.slug === slug);
|
|
75
|
+
if (!target) throw new Error(`PostLink: no post has slug "${slug}"`);
|
|
76
|
+
if (target.data.draft && !showDrafts) return null;
|
|
77
|
+
return resolvePostHref(slug, posts);
|
|
78
|
+
}
|