@riebeckite/plugin-share 0.0.24 → 0.0.26

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.
@@ -1,6 +1,6 @@
1
1
  import type { ShareLink } from "../src/types.js";
2
2
  export type ShareControlsProps = {
3
- readonly links: readonly ShareLink[];
3
+ readonly links?: readonly ShareLink[];
4
4
  readonly copyUrl?: string;
5
5
  readonly ariaLabel?: string;
6
6
  readonly className?: string;
@@ -8,5 +8,5 @@ export type ShareControlsProps = {
8
8
  readonly copiedLabel?: string;
9
9
  readonly copyFailedLabel?: string;
10
10
  };
11
- declare const ShareControls: ({ links, copyUrl, ariaLabel, className, copyLabel, copiedLabel, copyFailedLabel, }: Readonly<ShareControlsProps>) => import("hono/jsx/jsx-dev-runtime").JSX.Element;
11
+ declare const ShareControls: (props: Readonly<ShareControlsProps>) => Promise<import("hono/utils/html").HtmlEscapedString>;
12
12
  export default ShareControls;
@@ -1,15 +1,183 @@
1
+ // components/share-controls.tsx
2
+ import { useArticleContext, useSiteContext } from "@riebeckite/ui";
3
+ import { html } from "hono/html";
4
+
5
+ // index.ts
6
+ import {
7
+ createClientEntry,
8
+ createStyleAsset,
9
+ definePlugin
10
+ } from "@riebeckite/core";
11
+
12
+ // src/services.ts
13
+ function buildAbsoluteUrl(config, pathOrUrl) {
14
+ if (!pathOrUrl) return config.site.baseUrl;
15
+ if (/^https?:\/\//i.test(pathOrUrl)) return pathOrUrl;
16
+ return new URL(
17
+ pathOrUrl,
18
+ config.site.baseUrl || "https://example.com"
19
+ ).toString();
20
+ }
21
+ function normalizeMastodonInstance(value) {
22
+ if (typeof value !== "string") return "";
23
+ const trimmed = value.trim();
24
+ if (trimmed === "") return "";
25
+ const withoutScheme = trimmed.replace(/^https?:\/\//i, "");
26
+ const host = withoutScheme.split(/[/?#]/, 1)[0] ?? "";
27
+ return host.replace(/\.+$/, "");
28
+ }
29
+ function buildShareUrl(service, target, mastodonInstance = "") {
30
+ const url = target.url;
31
+ const title = target.title;
32
+ const composed = title ? `${title} ${url}` : url;
33
+ switch (service) {
34
+ case "x":
35
+ return `https://twitter.com/intent/tweet?url=${encode(url)}&text=${encode(title)}`;
36
+ case "bluesky":
37
+ return `https://bsky.app/intent/compose?text=${encode(composed)}`;
38
+ case "mastodon": {
39
+ const instance = normalizeMastodonInstance(mastodonInstance);
40
+ if (instance === "") return null;
41
+ return `https://${instance}/share?text=${encode(composed)}`;
42
+ }
43
+ case "facebook":
44
+ return `https://www.facebook.com/sharer/sharer.php?u=${encode(url)}`;
45
+ case "linkedin":
46
+ return `https://www.linkedin.com/sharing/share-offsite/?url=${encode(url)}`;
47
+ case "hatena":
48
+ return `https://b.hatena.ne.jp/add?mode=confirm&url=${encode(url)}&title=${encode(title)}`;
49
+ case "copy":
50
+ return null;
51
+ }
52
+ }
53
+ function buildShareLinks(options, target) {
54
+ const links = [];
55
+ for (const service of options.services) {
56
+ const url = buildShareUrl(service, target, options.mastodonInstance);
57
+ if (url === null) continue;
58
+ links.push({ service, label: options.labels[service], url });
59
+ }
60
+ return links;
61
+ }
62
+ function encode(value) {
63
+ return encodeURIComponent(value);
64
+ }
65
+
66
+ // src/types.ts
67
+ var SHARE_SERVICES = [
68
+ "x",
69
+ "bluesky",
70
+ "mastodon",
71
+ "facebook",
72
+ "linkedin",
73
+ "hatena",
74
+ "copy"
75
+ ];
76
+
77
+ // src/options.ts
78
+ var DEFAULT_SHARE_SERVICES = [
79
+ "x",
80
+ "bluesky",
81
+ "facebook",
82
+ "linkedin",
83
+ "hatena",
84
+ "copy"
85
+ ];
86
+ var DEFAULT_SHARE_LABELS = {
87
+ x: "X",
88
+ bluesky: "Bluesky",
89
+ mastodon: "Mastodon",
90
+ facebook: "Facebook",
91
+ linkedin: "LinkedIn",
92
+ hatena: "Hatena Bookmark",
93
+ copy: "Copy link"
94
+ };
95
+ var DEFAULT_SHARE_ARIA_LABEL = "Share";
96
+ var DEFAULT_SHARE_COPIED_LABEL = "Copied";
97
+ var DEFAULT_SHARE_COPY_FAILED_LABEL = "Copy failed";
98
+ function resolveShareOptions(options = {}) {
99
+ return {
100
+ services: normalizeServices(options.services),
101
+ mastodonInstance: normalizeMastodonInstance(options.mastodonInstance),
102
+ className: normalizeNonEmpty(options.className, ""),
103
+ ariaLabel: normalizeNonEmpty(options.ariaLabel, DEFAULT_SHARE_ARIA_LABEL),
104
+ labels: { ...DEFAULT_SHARE_LABELS, ...sanitizeLabels(options.labels) },
105
+ copiedLabel: normalizeNonEmpty(
106
+ options.copiedLabel,
107
+ DEFAULT_SHARE_COPIED_LABEL
108
+ ),
109
+ copyFailedLabel: normalizeNonEmpty(
110
+ options.copyFailedLabel,
111
+ DEFAULT_SHARE_COPY_FAILED_LABEL
112
+ )
113
+ };
114
+ }
115
+ function normalizeServices(services) {
116
+ const source = services ?? DEFAULT_SHARE_SERVICES;
117
+ const seen = /* @__PURE__ */ new Set();
118
+ const resolved = [];
119
+ for (const service of source) {
120
+ if (!SHARE_SERVICES.includes(service)) continue;
121
+ if (seen.has(service)) continue;
122
+ seen.add(service);
123
+ resolved.push(service);
124
+ }
125
+ return resolved;
126
+ }
127
+ function sanitizeLabels(labels) {
128
+ if (!labels || typeof labels !== "object") return {};
129
+ const resolved = {};
130
+ for (const service of SHARE_SERVICES) {
131
+ const value = labels[service];
132
+ if (typeof value === "string" && value.trim() !== "") {
133
+ resolved[service] = value.trim();
134
+ }
135
+ }
136
+ return resolved;
137
+ }
138
+ function normalizeNonEmpty(value, fallback) {
139
+ if (typeof value !== "string") return fallback;
140
+ const trimmed = value.trim();
141
+ return trimmed === "" ? fallback : trimmed;
142
+ }
143
+
144
+ // src/render.ts
145
+ import { escapeHtml, escapeHtmlAttribute } from "@riebeckite/core";
146
+ var SHARE_ROOT_CLASS = "rr-share";
147
+
148
+ // index.ts
149
+ var getShareLinks = ({ entry, site, options }) => {
150
+ const resolved = resolveShareOptions(options);
151
+ const url = buildAbsoluteUrl(site, entry.permalink);
152
+ return {
153
+ links: buildShareLinks(resolved, { url, title: entry.title }),
154
+ ...resolved.services.includes("copy") ? { copyUrl: url } : {},
155
+ ariaLabel: resolved.ariaLabel,
156
+ className: resolved.className || SHARE_ROOT_CLASS,
157
+ copyLabel: resolved.labels.copy,
158
+ copiedLabel: resolved.copiedLabel,
159
+ copyFailedLabel: resolved.copyFailedLabel
160
+ };
161
+ };
162
+
1
163
  // components/share-controls.tsx
2
164
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
3
- var ShareControls = (({
4
- links,
5
- copyUrl,
6
- ariaLabel = "Share",
7
- className = "rr-share",
8
- copyLabel = "Copy link",
9
- copiedLabel = "Copied",
10
- copyFailedLabel = "Copy failed"
11
- }) => {
12
- if (links.length === 0 && !copyUrl) return null;
165
+ var ShareControls = (async (props) => {
166
+ const site = useSiteContext();
167
+ const article = useArticleContext();
168
+ const resolved = props.links === void 0 && site && article?.entry ? await getShareLinks({
169
+ entry: article.entry,
170
+ site: site.config,
171
+ options: findShareOptions(site.config.plugins)
172
+ }) : void 0;
173
+ const links = props.links ?? resolved?.links ?? [];
174
+ const copyUrl = props.copyUrl ?? resolved?.copyUrl;
175
+ const ariaLabel = props.ariaLabel ?? resolved?.ariaLabel ?? "Share";
176
+ const className = props.className ?? resolved?.className ?? "rr-share";
177
+ const copyLabel = props.copyLabel ?? resolved?.copyLabel ?? "Copy link";
178
+ const copiedLabel = props.copiedLabel ?? resolved?.copiedLabel ?? "Copied";
179
+ const copyFailedLabel = props.copyFailedLabel ?? resolved?.copyFailedLabel ?? "Copy failed";
180
+ if (links.length === 0 && !copyUrl) return html``;
13
181
  const rootClass = className === "rr-share" ? className : `rr-share ${className}`;
14
182
  return /* @__PURE__ */ jsxs("nav", { class: rootClass, "data-rr-share": true, "aria-label": ariaLabel, children: [
15
183
  /* @__PURE__ */ jsxs("ul", { class: "rr-share__list", children: [
@@ -42,6 +210,9 @@ var ShareControls = (({
42
210
  ] });
43
211
  });
44
212
  var share_controls_default = ShareControls;
213
+ function findShareOptions(plugins) {
214
+ return plugins.find((plugin) => plugin.name === "share")?.options;
215
+ }
45
216
  export {
46
217
  share_controls_default as default
47
218
  };
package/dist/index.js CHANGED
@@ -229,17 +229,25 @@ function renderCopyItem(options, target) {
229
229
  }
230
230
 
231
231
  // components/share-controls.tsx
232
+ import { useArticleContext, useSiteContext } from "@riebeckite/ui";
233
+ import { html } from "hono/html";
232
234
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
233
- var ShareControls = (({
234
- links,
235
- copyUrl,
236
- ariaLabel = "Share",
237
- className = "rr-share",
238
- copyLabel = "Copy link",
239
- copiedLabel = "Copied",
240
- copyFailedLabel = "Copy failed"
241
- }) => {
242
- if (links.length === 0 && !copyUrl) return null;
235
+ var ShareControls = (async (props) => {
236
+ const site = useSiteContext();
237
+ const article = useArticleContext();
238
+ const resolved = props.links === void 0 && site && article?.entry ? await getShareLinks({
239
+ entry: article.entry,
240
+ site: site.config,
241
+ options: findShareOptions(site.config.plugins)
242
+ }) : void 0;
243
+ const links = props.links ?? resolved?.links ?? [];
244
+ const copyUrl = props.copyUrl ?? resolved?.copyUrl;
245
+ const ariaLabel = props.ariaLabel ?? resolved?.ariaLabel ?? "Share";
246
+ const className = props.className ?? resolved?.className ?? "rr-share";
247
+ const copyLabel = props.copyLabel ?? resolved?.copyLabel ?? "Copy link";
248
+ const copiedLabel = props.copiedLabel ?? resolved?.copiedLabel ?? "Copied";
249
+ const copyFailedLabel = props.copyFailedLabel ?? resolved?.copyFailedLabel ?? "Copy failed";
250
+ if (links.length === 0 && !copyUrl) return html``;
243
251
  const rootClass = className === "rr-share" ? className : `rr-share ${className}`;
244
252
  return /* @__PURE__ */ jsxs("nav", { class: rootClass, "data-rr-share": true, "aria-label": ariaLabel, children: [
245
253
  /* @__PURE__ */ jsxs("ul", { class: "rr-share__list", children: [
@@ -272,6 +280,9 @@ var ShareControls = (({
272
280
  ] });
273
281
  });
274
282
  var share_controls_default = ShareControls;
283
+ function findShareOptions(plugins) {
284
+ return plugins.find((plugin) => plugin.name === "share")?.options;
285
+ }
275
286
 
276
287
  // src/client.ts
277
288
  var COPY_SELECTOR = "[data-rr-share-copy]";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/plugin-share",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,8 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "hono": "^4.12.25",
31
- "@riebeckite/core": "0.0.24"
31
+ "@riebeckite/core": "0.0.26",
32
+ "@riebeckite/ui": "0.0.26"
32
33
  },
33
34
  "devDependencies": {
34
35
  "tsx": "^4.22.4"