@ingram-tech/nk-blog 0.1.5 → 0.1.6

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.
@@ -0,0 +1,24 @@
1
+ import { defineBlogComponents } from "../contract.js";
2
+ import { Callout } from "./callout.js";
3
+ import { Figure } from "./figure.js";
4
+ import { NewsletterSubscribe } from "./newsletter-subscribe.js";
5
+ import { Tweet } from "./tweet.js";
6
+ import { YouTube } from "./youtube.js";
7
+
8
+ export { Callout, Figure, NewsletterSubscribe, Tweet, YouTube };
9
+
10
+ /**
11
+ * The complete default registry. A site's whole obligation is:
12
+ *
13
+ * export const blogComponents = defineBlogComponents({
14
+ * ...unstyled,
15
+ * Callout: BrandCallout, // replaced wholesale where the brand cares
16
+ * });
17
+ */
18
+ export const unstyled = defineBlogComponents({
19
+ Callout,
20
+ Figure,
21
+ YouTube,
22
+ Tweet,
23
+ NewsletterSubscribe,
24
+ });
@@ -0,0 +1,23 @@
1
+ import type { NewsletterSubscribeProps } from "../contract.js";
2
+
3
+ /**
4
+ * Plain HTML form POSTing to the injected endpoint — works with zero client
5
+ * JS. The package never bakes in a newsletter backend.
6
+ */
7
+ export const NewsletterSubscribe: React.FC<NewsletterSubscribeProps> = ({
8
+ action,
9
+ placeholder,
10
+ buttonLabel,
11
+ className,
12
+ }) => (
13
+ <form action={action} method="post" className={className}>
14
+ <input
15
+ type="email"
16
+ name="email"
17
+ required
18
+ placeholder={placeholder ?? "you@example.com"}
19
+ aria-label="Email address"
20
+ />
21
+ <button type="submit">{buttonLabel ?? "Subscribe"}</button>
22
+ </form>
23
+ );
@@ -0,0 +1,12 @@
1
+ import type { TweetProps } from "../contract.js";
2
+
3
+ /**
4
+ * Zero-JS default: the standard `twitter-tweet` blockquote, progressively
5
+ * enhanced if the site loads the platform widget script — otherwise it
6
+ * degrades to a plain link. No data fetching in the package.
7
+ */
8
+ export const Tweet: React.FC<TweetProps> = ({ id, className }) => (
9
+ <blockquote className={["twitter-tweet", className].filter(Boolean).join(" ")}>
10
+ <a href={`https://twitter.com/i/status/${encodeURIComponent(id)}`}>View post</a>
11
+ </blockquote>
12
+ );
@@ -0,0 +1,24 @@
1
+ import type { YouTubeProps } from "../contract.js";
2
+
3
+ /**
4
+ * Privacy-enhanced (youtube-nocookie), lazy-loaded embed with a stable 16:9
5
+ * box (CLS). The inline aspect-ratio is behavior, not styling.
6
+ */
7
+ export const YouTube: React.FC<YouTubeProps> = ({ id, title, start, className }) => {
8
+ const startSeconds = typeof start === "string" ? Number(start) : start;
9
+ const src = `https://www.youtube-nocookie.com/embed/${encodeURIComponent(id)}${
10
+ startSeconds ? `?start=${startSeconds}` : ""
11
+ }`;
12
+ return (
13
+ <iframe
14
+ src={src}
15
+ title={title ?? "YouTube video"}
16
+ loading="lazy"
17
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
18
+ allowFullScreen
19
+ referrerPolicy="strict-origin-when-cross-origin"
20
+ className={className}
21
+ style={{ aspectRatio: "16 / 9", width: "100%", border: 0 }}
22
+ />
23
+ );
24
+ };