dineway 0.1.3 → 0.1.4
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/package.json +6 -3
- package/src/astro/routes/PluginRegistry.tsx +21 -0
- package/src/astro/routes/admin.astro +83 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
- package/src/astro/routes/api/admin/bylines/index.ts +72 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +64 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +62 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +86 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +221 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +120 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +84 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +88 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +119 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +68 -0
- package/src/astro/routes/api/auth/signup/complete.ts +87 -0
- package/src/astro/routes/api/auth/signup/request.ts +77 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +311 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +105 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
- package/src/astro/routes/api/content/[collection]/index.ts +59 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +531 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +296 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +357 -0
- package/src/astro/routes/api/manifest.ts +63 -0
- package/src/astro/routes/api/mcp.ts +124 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[...key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +137 -0
- package/src/astro/routes/api/media.ts +202 -0
- package/src/astro/routes/api/menus/[name]/items.ts +87 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
- package/src/astro/routes/api/menus/[name].ts +65 -0
- package/src/astro/routes/api/menus/index.ts +47 -0
- package/src/astro/routes/api/oauth/authorize.ts +417 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +55 -0
- package/src/astro/routes/api/oauth/device/token.ts +69 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +184 -0
- package/src/astro/routes/api/openapi.json.ts +32 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +84 -0
- package/src/astro/routes/api/redirects/index.ts +52 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
- package/src/astro/routes/api/schema/collections/index.ts +47 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +51 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +49 -0
- package/src/astro/routes/api/sections/[slug].ts +84 -0
- package/src/astro/routes/api/sections/index.ts +52 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +67 -0
- package/src/astro/routes/api/setup/admin-verify.ts +102 -0
- package/src/astro/routes/api/setup/admin.ts +96 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +200 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +127 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +76 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
- package/src/astro/routes/api/taxonomies/index.ts +59 -0
- package/src/astro/routes/api/themes/preview.ts +78 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +69 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +45 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +38 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +72 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
- package/src/astro/routes/api/widget-areas/[name].ts +87 -0
- package/src/astro/routes/api/widget-areas/index.ts +99 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +81 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
- package/src/astro/routes/sitemap.xml.ts +92 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/DinewayBodyEnd.astro +32 -0
- package/src/components/DinewayBodyStart.astro +32 -0
- package/src/components/DinewayHead.astro +53 -0
- package/src/components/DinewayImage.astro +178 -0
- package/src/components/DinewayMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1937 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +108 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +116 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/ui.ts +75 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { sanitizeHref } from "../utils/url.js";
|
|
3
|
+
import { sanitizeContent } from "../utils/sanitize.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Portable Text Embed block component
|
|
7
|
+
*
|
|
8
|
+
* Renders embeds from YouTube, Vimeo, Twitter, etc.
|
|
9
|
+
*/
|
|
10
|
+
export interface Props {
|
|
11
|
+
node: {
|
|
12
|
+
_type: "embed";
|
|
13
|
+
_key: string;
|
|
14
|
+
url: string;
|
|
15
|
+
provider?: string;
|
|
16
|
+
html?: string;
|
|
17
|
+
caption?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { node } = Astro.props;
|
|
22
|
+
|
|
23
|
+
if (!node?.url) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { url: rawUrl, provider, html, caption } = node;
|
|
28
|
+
const url = sanitizeHref(rawUrl);
|
|
29
|
+
|
|
30
|
+
const YOUTUBE_ID_PATTERN = /(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
|
|
31
|
+
const VIMEO_ID_PATTERN = /vimeo\.com\/(\d+)/;
|
|
32
|
+
|
|
33
|
+
// Extract video ID for common providers
|
|
34
|
+
function getYouTubeId(input: string): string | null {
|
|
35
|
+
const match = input.match(YOUTUBE_ID_PATTERN);
|
|
36
|
+
return match?.[1] || null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getVimeoId(input: string): string | null {
|
|
40
|
+
const match = input.match(VIMEO_ID_PATTERN);
|
|
41
|
+
return match?.[1] || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const youtubeId = getYouTubeId(url);
|
|
45
|
+
const vimeoId = getVimeoId(url);
|
|
46
|
+
|
|
47
|
+
// Check if this is a self-hosted video or audio
|
|
48
|
+
const isSelfHostedVideo = provider === "video";
|
|
49
|
+
const isSelfHostedAudio = provider === "audio";
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
<figure class="dineway-embed">
|
|
53
|
+
{
|
|
54
|
+
isSelfHostedVideo ? (
|
|
55
|
+
<div class="dineway-embed-video">
|
|
56
|
+
<video controls preload="metadata">
|
|
57
|
+
<source src={url} />
|
|
58
|
+
Your browser does not support the video element.
|
|
59
|
+
</video>
|
|
60
|
+
</div>
|
|
61
|
+
) : isSelfHostedAudio ? (
|
|
62
|
+
<div class="dineway-embed-audio">
|
|
63
|
+
<audio controls preload="metadata">
|
|
64
|
+
<source src={url} />
|
|
65
|
+
Your browser does not support the audio element.
|
|
66
|
+
</audio>
|
|
67
|
+
</div>
|
|
68
|
+
) : youtubeId ? (
|
|
69
|
+
<div class="dineway-embed-video">
|
|
70
|
+
<iframe
|
|
71
|
+
src={`https://www.youtube.com/embed/${youtubeId}`}
|
|
72
|
+
title="YouTube video"
|
|
73
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
74
|
+
allowfullscreen
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
) : vimeoId ? (
|
|
78
|
+
<div class="dineway-embed-video">
|
|
79
|
+
<iframe
|
|
80
|
+
src={`https://player.vimeo.com/video/${vimeoId}`}
|
|
81
|
+
title="Vimeo video"
|
|
82
|
+
allow="autoplay; fullscreen; picture-in-picture"
|
|
83
|
+
allowfullscreen
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
) : html ? (
|
|
87
|
+
<div class="dineway-embed-html" set:html={sanitizeContent(html)} />
|
|
88
|
+
) : (
|
|
89
|
+
<a href={url} target="_blank" rel="noopener noreferrer">
|
|
90
|
+
{url}
|
|
91
|
+
</a>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
{caption && <figcaption>{caption}</figcaption>}
|
|
95
|
+
</figure>
|
|
96
|
+
|
|
97
|
+
<style>
|
|
98
|
+
.dineway-embed {
|
|
99
|
+
margin: 1.5rem 0;
|
|
100
|
+
}
|
|
101
|
+
.dineway-embed-video {
|
|
102
|
+
position: relative;
|
|
103
|
+
padding-bottom: 56.25%; /* 16:9 */
|
|
104
|
+
height: 0;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
}
|
|
107
|
+
.dineway-embed-video iframe,
|
|
108
|
+
.dineway-embed-video video {
|
|
109
|
+
position: absolute;
|
|
110
|
+
top: 0;
|
|
111
|
+
left: 0;
|
|
112
|
+
width: 100%;
|
|
113
|
+
height: 100%;
|
|
114
|
+
border: 0;
|
|
115
|
+
}
|
|
116
|
+
.dineway-embed-audio {
|
|
117
|
+
width: 100%;
|
|
118
|
+
}
|
|
119
|
+
.dineway-embed-audio audio {
|
|
120
|
+
width: 100%;
|
|
121
|
+
}
|
|
122
|
+
.dineway-embed figcaption {
|
|
123
|
+
font-size: 0.875rem;
|
|
124
|
+
color: #666;
|
|
125
|
+
margin-top: 0.5rem;
|
|
126
|
+
text-align: center;
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { sanitizeHref } from "../utils/url.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Portable Text File block component
|
|
6
|
+
*
|
|
7
|
+
* Renders a downloadable file link from WordPress imports.
|
|
8
|
+
*/
|
|
9
|
+
export interface Props {
|
|
10
|
+
node: {
|
|
11
|
+
_type: "file";
|
|
12
|
+
_key: string;
|
|
13
|
+
url: string;
|
|
14
|
+
filename?: string;
|
|
15
|
+
showDownloadButton?: boolean;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { node } = Astro.props;
|
|
20
|
+
const { url: rawUrl, filename, showDownloadButton = true } = node ?? {};
|
|
21
|
+
const url = sanitizeHref(rawUrl);
|
|
22
|
+
|
|
23
|
+
// Extract filename from URL if not provided
|
|
24
|
+
const displayName = filename || url?.split("/").pop()?.split("?")[0] || "Download";
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<div class="dineway-file">
|
|
28
|
+
<a href={url} class="dineway-file__link" download={filename}>
|
|
29
|
+
<svg
|
|
30
|
+
class="dineway-file__icon"
|
|
31
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
32
|
+
viewBox="0 0 24 24"
|
|
33
|
+
fill="none"
|
|
34
|
+
stroke="currentColor"
|
|
35
|
+
stroke-width="2"
|
|
36
|
+
stroke-linecap="round"
|
|
37
|
+
stroke-linejoin="round"
|
|
38
|
+
>
|
|
39
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
40
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
41
|
+
</svg>
|
|
42
|
+
<span class="dineway-file__name">{displayName}</span>
|
|
43
|
+
</a>
|
|
44
|
+
{
|
|
45
|
+
showDownloadButton && (
|
|
46
|
+
<a href={url} class="dineway-file__download" download={filename} aria-label="Download file">
|
|
47
|
+
<svg
|
|
48
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
fill="none"
|
|
51
|
+
stroke="currentColor"
|
|
52
|
+
stroke-width="2"
|
|
53
|
+
stroke-linecap="round"
|
|
54
|
+
stroke-linejoin="round"
|
|
55
|
+
>
|
|
56
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
57
|
+
<polyline points="7 10 12 15 17 10" />
|
|
58
|
+
<line x1="12" y1="15" x2="12" y2="3" />
|
|
59
|
+
</svg>
|
|
60
|
+
</a>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<style>
|
|
66
|
+
.dineway-file {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 0.75rem;
|
|
70
|
+
padding: 1rem;
|
|
71
|
+
margin: 1rem 0;
|
|
72
|
+
background-color: var(--dineway-file-bg, #f5f5f5);
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
border: 1px solid var(--dineway-file-border, #e0e0e0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.dineway-file__link {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
gap: 0.5rem;
|
|
81
|
+
flex: 1;
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
color: var(--dineway-file-color, #333);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.dineway-file__link:hover {
|
|
87
|
+
text-decoration: underline;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.dineway-file__icon {
|
|
91
|
+
width: 1.5rem;
|
|
92
|
+
height: 1.5rem;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
color: var(--dineway-file-icon-color, #666);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.dineway-file__name {
|
|
98
|
+
font-weight: 500;
|
|
99
|
+
word-break: break-all;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.dineway-file__download {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
width: 2.5rem;
|
|
107
|
+
height: 2.5rem;
|
|
108
|
+
background-color: var(--dineway-button-bg, #0073aa);
|
|
109
|
+
color: var(--dineway-button-color, #fff);
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
transition: background-color 0.2s;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.dineway-file__download:hover {
|
|
115
|
+
background-color: var(--dineway-button-bg-hover, #005177);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.dineway-file__download svg {
|
|
119
|
+
width: 1.25rem;
|
|
120
|
+
height: 1.25rem;
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Portable Text Gallery block component
|
|
4
|
+
*
|
|
5
|
+
* Renders image galleries from WordPress imports.
|
|
6
|
+
* Uses Astro's Image component for optimization when dimensions are available.
|
|
7
|
+
*/
|
|
8
|
+
import { Image as AstroImage } from "astro:assets";
|
|
9
|
+
|
|
10
|
+
export interface Props {
|
|
11
|
+
node: {
|
|
12
|
+
_type: "gallery";
|
|
13
|
+
_key: string;
|
|
14
|
+
images: Array<{
|
|
15
|
+
_type: "image";
|
|
16
|
+
_key: string;
|
|
17
|
+
asset: {
|
|
18
|
+
_ref: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
};
|
|
21
|
+
alt?: string;
|
|
22
|
+
caption?: string;
|
|
23
|
+
width?: number;
|
|
24
|
+
height?: number;
|
|
25
|
+
}>;
|
|
26
|
+
columns?: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { node } = Astro.props;
|
|
31
|
+
const images = node?.images ?? [];
|
|
32
|
+
const columns = node?.columns ?? 3;
|
|
33
|
+
|
|
34
|
+
if (!images.length) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
<div class="dineway-gallery" style={`--columns: ${columns}`}>
|
|
40
|
+
{
|
|
41
|
+
images.map((image) => {
|
|
42
|
+
const src =
|
|
43
|
+
image.asset.url ||
|
|
44
|
+
`/_dineway/api/media/file/${image.asset._ref}`;
|
|
45
|
+
const hasSize = image.width && image.height;
|
|
46
|
+
return (
|
|
47
|
+
<figure class="dineway-gallery-item">
|
|
48
|
+
{hasSize ? (
|
|
49
|
+
<AstroImage
|
|
50
|
+
src={src}
|
|
51
|
+
alt={image.alt || ""}
|
|
52
|
+
width={image.width!}
|
|
53
|
+
height={image.height!}
|
|
54
|
+
layout="constrained"
|
|
55
|
+
/>
|
|
56
|
+
) : (
|
|
57
|
+
<img src={src} alt={image.alt || ""} loading="lazy" decoding="async" />
|
|
58
|
+
)}
|
|
59
|
+
{image.caption && <figcaption>{image.caption}</figcaption>}
|
|
60
|
+
</figure>
|
|
61
|
+
);
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
.dineway-gallery {
|
|
68
|
+
display: grid;
|
|
69
|
+
grid-template-columns: repeat(var(--columns, 3), 1fr);
|
|
70
|
+
gap: 1rem;
|
|
71
|
+
margin: 1.5rem 0;
|
|
72
|
+
}
|
|
73
|
+
.dineway-gallery-item {
|
|
74
|
+
margin: 0;
|
|
75
|
+
}
|
|
76
|
+
.dineway-gallery-item img {
|
|
77
|
+
width: 100%;
|
|
78
|
+
height: auto;
|
|
79
|
+
object-fit: cover;
|
|
80
|
+
aspect-ratio: 1;
|
|
81
|
+
}
|
|
82
|
+
.dineway-gallery-item figcaption {
|
|
83
|
+
font-size: 0.75rem;
|
|
84
|
+
color: #666;
|
|
85
|
+
margin-top: 0.25rem;
|
|
86
|
+
text-align: center;
|
|
87
|
+
}
|
|
88
|
+
@media (max-width: 640px) {
|
|
89
|
+
.dineway-gallery {
|
|
90
|
+
grid-template-columns: repeat(2, 1fr);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Portable Text HTML block component
|
|
4
|
+
*
|
|
5
|
+
* Renders raw HTML blocks that couldn't be converted to Portable Text.
|
|
6
|
+
* Sanitizes HTML to prevent XSS attacks.
|
|
7
|
+
*/
|
|
8
|
+
import { sanitizeContent } from "../utils/sanitize.js";
|
|
9
|
+
|
|
10
|
+
export interface Props {
|
|
11
|
+
node: {
|
|
12
|
+
_type: "htmlBlock";
|
|
13
|
+
_key: string;
|
|
14
|
+
html: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { node } = Astro.props;
|
|
19
|
+
|
|
20
|
+
if (!node?.html) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sanitized = sanitizeContent(node.html);
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<div class="dineway-html-block" set:html={sanitized} />
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.dineway-html-block {
|
|
31
|
+
margin: 1.5rem 0;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Portable Text Image block component
|
|
4
|
+
*
|
|
5
|
+
* Renders image blocks from WordPress imports and Dineway media.
|
|
6
|
+
* Uses the provider's getSrc function for responsive srcset generation.
|
|
7
|
+
*/
|
|
8
|
+
import type { ImageEmbed } from "../media/types.js";
|
|
9
|
+
import { getMediaProvider } from "../media/provider-loader.js";
|
|
10
|
+
// Standard responsive breakpoints
|
|
11
|
+
const BREAKPOINTS = [640, 750, 828, 960, 1080, 1280, 1600, 1920];
|
|
12
|
+
|
|
13
|
+
export interface Props {
|
|
14
|
+
node: {
|
|
15
|
+
_type: "image";
|
|
16
|
+
_key: string;
|
|
17
|
+
asset: {
|
|
18
|
+
_ref: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
/** Provider ID for external media (e.g., "image-cdn") */
|
|
21
|
+
provider?: string;
|
|
22
|
+
/** Provider metadata (blurhash, dominantColor, etc.) */
|
|
23
|
+
meta?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
alt?: string;
|
|
26
|
+
caption?: string;
|
|
27
|
+
/** Original image width */
|
|
28
|
+
width?: number;
|
|
29
|
+
/** Original image height */
|
|
30
|
+
height?: number;
|
|
31
|
+
/** Display width for this instance (overrides original) */
|
|
32
|
+
displayWidth?: number;
|
|
33
|
+
/** Display height for this instance (overrides original) */
|
|
34
|
+
displayHeight?: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generate srcset using provider's getSrc function
|
|
40
|
+
*/
|
|
41
|
+
function generateSrcset(
|
|
42
|
+
getSrc: NonNullable<ImageEmbed["getSrc"]>,
|
|
43
|
+
maxWidth: number,
|
|
44
|
+
aspectRatio?: number,
|
|
45
|
+
): string {
|
|
46
|
+
return BREAKPOINTS.filter((w) => w <= maxWidth * 2)
|
|
47
|
+
.map((w) => {
|
|
48
|
+
const h = aspectRatio ? Math.round(w / aspectRatio) : undefined;
|
|
49
|
+
return `${getSrc({ width: w, height: h })} ${w}w`;
|
|
50
|
+
})
|
|
51
|
+
.join(", ");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { node } = Astro.props;
|
|
55
|
+
|
|
56
|
+
if (!node?.asset) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { asset, alt = "", caption, width, height, displayWidth, displayHeight } = node;
|
|
61
|
+
|
|
62
|
+
// Calculate aspect ratio from original dimensions
|
|
63
|
+
const aspectRatio = width && height ? width / height : undefined;
|
|
64
|
+
|
|
65
|
+
// Calculate render dimensions
|
|
66
|
+
let renderWidth: number | undefined;
|
|
67
|
+
let renderHeight: number | undefined;
|
|
68
|
+
|
|
69
|
+
if (displayWidth && displayHeight) {
|
|
70
|
+
renderWidth = displayWidth;
|
|
71
|
+
renderHeight = displayHeight;
|
|
72
|
+
} else if (displayWidth && aspectRatio) {
|
|
73
|
+
renderWidth = displayWidth;
|
|
74
|
+
renderHeight = Math.round(displayWidth / aspectRatio);
|
|
75
|
+
} else if (displayHeight && aspectRatio) {
|
|
76
|
+
renderWidth = Math.round(displayHeight * aspectRatio);
|
|
77
|
+
renderHeight = displayHeight;
|
|
78
|
+
} else {
|
|
79
|
+
renderWidth = width;
|
|
80
|
+
renderHeight = height;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Get the image source URL and srcset
|
|
84
|
+
let src = "";
|
|
85
|
+
let srcset: string | undefined;
|
|
86
|
+
let sizes: string | undefined;
|
|
87
|
+
const providerId = asset.provider;
|
|
88
|
+
|
|
89
|
+
if (providerId && providerId !== "local") {
|
|
90
|
+
// External provider
|
|
91
|
+
const provider = await getMediaProvider(providerId);
|
|
92
|
+
if (provider) {
|
|
93
|
+
try {
|
|
94
|
+
const mediaValue = {
|
|
95
|
+
provider: providerId,
|
|
96
|
+
id: asset._ref,
|
|
97
|
+
width: renderWidth,
|
|
98
|
+
height: renderHeight,
|
|
99
|
+
alt,
|
|
100
|
+
};
|
|
101
|
+
const result = provider.getEmbed(mediaValue, {
|
|
102
|
+
width: renderWidth,
|
|
103
|
+
height: renderHeight,
|
|
104
|
+
});
|
|
105
|
+
const embed = result instanceof Promise ? await result : result;
|
|
106
|
+
if (embed.type === "image") {
|
|
107
|
+
src = embed.src;
|
|
108
|
+
|
|
109
|
+
// Generate srcset if provider supports dynamic sizing
|
|
110
|
+
if (embed.getSrc) {
|
|
111
|
+
const maxWidth = renderWidth || 1200;
|
|
112
|
+
const ar = renderWidth && renderHeight ? renderWidth / renderHeight : aspectRatio;
|
|
113
|
+
srcset = generateSrcset(embed.getSrc, maxWidth, ar);
|
|
114
|
+
sizes = renderWidth
|
|
115
|
+
? `(min-width: ${renderWidth}px) ${renderWidth}px, 100vw`
|
|
116
|
+
: "100vw";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.warn(`Failed to get embed for image ${asset._ref}:`, error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Fallback for local provider — prefer stored URL (includes storage key with extension),
|
|
126
|
+
// fall back to _ref (bare ULID, works if media file endpoint supports ID lookup)
|
|
127
|
+
if (!src) {
|
|
128
|
+
src = asset.url || `/_dineway/api/media/file/${asset._ref}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Build placeholder background style
|
|
132
|
+
const blurhash = asset.meta?.blurhash as string | undefined;
|
|
133
|
+
const dominantColor = asset.meta?.dominantColor as string | undefined;
|
|
134
|
+
|
|
135
|
+
let placeholderStyle = "";
|
|
136
|
+
if (blurhash) {
|
|
137
|
+
const { blurhashToImageCssString } = await import("@unpic/placeholder");
|
|
138
|
+
placeholderStyle = blurhashToImageCssString(blurhash);
|
|
139
|
+
} else if (dominantColor) {
|
|
140
|
+
placeholderStyle = `background-color: ${dominantColor};`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const baseStyle = aspectRatio
|
|
144
|
+
? `aspect-ratio: ${aspectRatio}; max-width: 100%; height: auto;`
|
|
145
|
+
: "max-width: 100%; height: auto;";
|
|
146
|
+
const imgStyle = placeholderStyle ? `${baseStyle} ${placeholderStyle}` : baseStyle;
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
<figure class="dineway-image">
|
|
150
|
+
<img
|
|
151
|
+
src={src}
|
|
152
|
+
srcset={srcset}
|
|
153
|
+
sizes={sizes}
|
|
154
|
+
alt={alt}
|
|
155
|
+
width={renderWidth}
|
|
156
|
+
height={renderHeight}
|
|
157
|
+
loading="lazy"
|
|
158
|
+
decoding="async"
|
|
159
|
+
style={imgStyle}
|
|
160
|
+
/>
|
|
161
|
+
{caption && <figcaption>{caption}</figcaption>}
|
|
162
|
+
</figure>
|
|
163
|
+
|
|
164
|
+
<style>
|
|
165
|
+
.dineway-image {
|
|
166
|
+
margin: 1.5rem 0;
|
|
167
|
+
}
|
|
168
|
+
.dineway-image img {
|
|
169
|
+
max-width: 100%;
|
|
170
|
+
height: auto;
|
|
171
|
+
}
|
|
172
|
+
.dineway-image figcaption {
|
|
173
|
+
font-size: 0.875rem;
|
|
174
|
+
color: #666;
|
|
175
|
+
margin-top: 0.5rem;
|
|
176
|
+
text-align: center;
|
|
177
|
+
}
|
|
178
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper for the inline Portable Text editor.
|
|
4
|
+
*
|
|
5
|
+
* This exists as a separate .astro component so that the static import
|
|
6
|
+
* of the React component is visible to Astro's build pipeline — required
|
|
7
|
+
* for `client:load` to find a matching renderer.
|
|
8
|
+
*/
|
|
9
|
+
import { InlinePortableTextEditor } from "./InlinePortableTextEditor";
|
|
10
|
+
|
|
11
|
+
export interface Props {
|
|
12
|
+
value: unknown[];
|
|
13
|
+
collection: string;
|
|
14
|
+
entryId: string;
|
|
15
|
+
field: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { value, collection, entryId, field } = Astro.props;
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<InlinePortableTextEditor
|
|
22
|
+
client:only="react"
|
|
23
|
+
value={value}
|
|
24
|
+
collection={collection}
|
|
25
|
+
entryId={entryId}
|
|
26
|
+
field={field}
|
|
27
|
+
/>
|