@acms-subir/core 0.2.0 → 0.3.1
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/CHANGELOG.md +87 -0
- package/cli/common.mjs +35 -0
- package/cli/legacy.mjs +317 -0
- package/cli/main.mjs +66 -0
- package/cli/palette.mjs +4 -0
- package/cli/preview.mjs +50 -0
- package/cli/remote.mjs +55 -0
- package/cli/themes.mjs +127 -0
- package/cli.mjs +2 -369
- package/deploy/Caddyfile +8 -0
- package/deploy/Dockerfile +34 -0
- package/deploy/compose.https.yml +21 -0
- package/deploy/compose.yml +46 -0
- package/docs/live-video.md +91 -0
- package/docs/theme-authoring.md +103 -0
- package/email-runner.mjs +32 -0
- package/integration.mjs +189 -2
- package/ops-check.mjs +27 -0
- package/package.json +27 -5
- package/src/actions/index.ts +578 -49
- package/src/components/AiCleaner.tsx +291 -0
- package/src/components/AiSettings.tsx +575 -0
- package/src/components/CommandPalette.tsx +200 -0
- package/src/components/ContentList.astro +246 -0
- package/src/components/DesignAccess.tsx +182 -0
- package/src/components/DesignManager.tsx +418 -46
- package/src/components/EmailSettings.tsx +521 -0
- package/src/components/EventPage.astro +178 -0
- package/src/components/LegalPage.astro +27 -0
- package/src/components/LinksManager.tsx +119 -58
- package/src/components/LiveCard.astro +174 -0
- package/src/components/LiveManager.tsx +910 -0
- package/src/components/NavManager.tsx +42 -43
- package/src/components/ThemeScript.astro +50 -0
- package/src/components/ThemeSections.astro +58 -0
- package/src/components/ThemeSectionsEditor.tsx +513 -0
- package/src/components/WidgetRenderer.astro +3 -0
- package/src/components/booking/BookingFlow.astro +150 -0
- package/src/components/booking/HoursEditor.astro +63 -0
- package/src/components/builder/PageBuilder.tsx +10 -2
- package/src/components/editor/EventPanel.tsx +401 -0
- package/src/components/editor/FormatDock.tsx +81 -0
- package/src/components/editor/LivePane.tsx +122 -0
- package/src/components/editor/MobileToolbar.tsx +93 -0
- package/src/components/editor/PostEditor.tsx +605 -223
- package/src/components/editor/PreviewOverlay.tsx +242 -43
- package/src/components/editor/extensions/calendar.tsx +51 -7
- package/src/components/editor/extensions/events.tsx +153 -0
- package/src/components/editor/extensions/slash.tsx +7 -1
- package/src/components/site/Pager.astro +24 -0
- package/src/components/site/PostCard.astro +64 -0
- package/src/components/site/TagLabel.astro +11 -0
- package/src/layouts/Admin.astro +289 -49
- package/src/layouts/Site.astro +352 -59
- package/src/lib/agent-api.ts +13 -0
- package/src/lib/agent-discovery.ts +40 -0
- package/src/lib/agent.ts +114 -0
- package/src/lib/ai-config.ts +58 -0
- package/src/lib/ai-schema.ts +22 -0
- package/src/lib/ai.ts +90 -0
- package/src/lib/api-keys.ts +65 -0
- package/src/lib/api.ts +56 -0
- package/src/lib/auth.ts +25 -5
- package/src/lib/backup/content.ts +36 -0
- package/src/lib/backup/unzip.ts +12 -1
- package/src/lib/backup/zip.ts +1 -1
- package/src/lib/booking/agent.ts +108 -0
- package/src/lib/booking/availability.ts +221 -0
- package/src/lib/booking/emails.ts +115 -0
- package/src/lib/booking/forms.ts +77 -0
- package/src/lib/booking/service.ts +277 -0
- package/src/lib/booking/view.ts +54 -0
- package/src/lib/calendar/agent-schema.ts +48 -0
- package/src/lib/calendar/agent.ts +136 -0
- package/src/lib/calendar/api.ts +81 -0
- package/src/lib/calendar/cards.ts +102 -0
- package/src/lib/calendar/config.ts +52 -0
- package/src/lib/calendar/data.ts +130 -0
- package/src/lib/calendar/events.ts +261 -0
- package/src/lib/calendar/feeds.ts +43 -0
- package/src/lib/calendar/hooks.ts +38 -0
- package/src/lib/calendar/http.ts +30 -0
- package/src/lib/calendar/ics-write.ts +120 -0
- package/src/lib/calendar/ics.ts +15 -5
- package/src/lib/calendar/import.ts +203 -0
- package/src/lib/calendar/render.ts +120 -37
- package/src/lib/calendar/rrule.ts +149 -0
- package/src/lib/calendar/seo.ts +48 -0
- package/src/lib/design-service.ts +58 -0
- package/src/lib/designDiff.ts +145 -0
- package/src/lib/designPreview.ts +110 -12
- package/src/lib/documents/cleanup.ts +31 -0
- package/src/lib/documents/extract.ts +154 -0
- package/src/lib/documents/vendor.d.ts +4 -0
- package/src/lib/drafts.ts +60 -6
- package/src/lib/dynamicBlocks.ts +40 -8
- package/src/lib/email/accounts.ts +55 -0
- package/src/lib/email/config.ts +86 -0
- package/src/lib/email/migration.ts +24 -0
- package/src/lib/email/providers.ts +89 -0
- package/src/lib/email/service.ts +78 -0
- package/src/lib/email/store.ts +167 -0
- package/src/lib/email/templates.ts +18 -0
- package/src/lib/email/types.ts +32 -0
- package/src/lib/email/webhooks.ts +87 -0
- package/src/lib/email.ts +15 -0
- package/src/lib/env.ts +1 -1
- package/src/lib/legal/index.ts +25 -0
- package/src/lib/live/client.ts +88 -0
- package/src/lib/live/crypto.ts +28 -0
- package/src/lib/live/migration.ts +15 -0
- package/src/lib/live/providers.ts +152 -0
- package/src/lib/live/service.ts +170 -0
- package/src/lib/live/signals.ts +89 -0
- package/src/lib/live/store.ts +49 -0
- package/src/lib/live/types.ts +52 -0
- package/src/lib/live/view.ts +78 -0
- package/src/lib/mobile/bookings.ts +73 -0
- package/src/lib/mobile/calendar.ts +85 -0
- package/src/lib/mobile/content.ts +85 -0
- package/src/lib/mobile/http.ts +63 -0
- package/src/lib/mobile/route.ts +20 -0
- package/src/lib/ops.ts +8 -0
- package/src/lib/preview.ts +21 -1
- package/src/lib/repo/migrations.ts +221 -0
- package/src/lib/repo/sql.ts +907 -68
- package/src/lib/repo/types.ts +125 -5
- package/src/lib/scheduler.ts +27 -0
- package/src/lib/schema.ts +316 -1
- package/src/lib/search-i18n.ts +3 -0
- package/src/lib/socialIcons.ts +32 -0
- package/src/lib/tagColor.ts +11 -0
- package/src/lib/theme.ts +59 -40
- package/src/lib/themeTokens.ts +183 -0
- package/src/lib/umami.ts +108 -0
- package/src/lib/webhook-sql.ts +68 -0
- package/src/lib/webhooks.ts +147 -0
- package/src/lib/widgets.ts +1 -0
- package/src/middleware.ts +45 -3
- package/src/pages/404.astro +23 -0
- package/src/pages/[...slug].astro +14 -5
- package/src/pages/account/[action].astro +53 -0
- package/src/pages/admin/ai.astro +12 -0
- package/src/pages/admin/c/[collection]/[id].astro +4 -1
- package/src/pages/admin/c/[collection]/index.astro +127 -92
- package/src/pages/admin/calendar/bookings.astro +400 -0
- package/src/pages/admin/calendar/calendars.astro +265 -0
- package/src/pages/admin/calendar/events/[id].astro +56 -0
- package/src/pages/admin/calendar/events/index.astro +408 -0
- package/src/pages/admin/calendar/index.ts +4 -0
- package/src/pages/admin/calendar/integrations.astro +4 -0
- package/src/pages/admin/calendar/resources/[id].astro +180 -0
- package/src/pages/admin/calendar/resources/index.astro +106 -0
- package/src/pages/admin/calendar/resources/link.astro +196 -0
- package/src/pages/admin/design.astro +10 -3
- package/src/pages/admin/email.astro +13 -0
- package/src/pages/admin/index.astro +232 -85
- package/src/pages/admin/integrations.astro +237 -0
- package/src/pages/admin/links.astro +3 -3
- package/src/pages/admin/live.astro +12 -0
- package/src/pages/admin/login.astro +14 -10
- package/src/pages/admin/navigation.astro +8 -2
- package/src/pages/admin/pages/[id].astro +4 -1
- package/src/pages/admin/pages/index.astro +41 -48
- package/src/pages/admin/settings.astro +418 -367
- package/src/pages/admin/tags.astro +4 -4
- package/src/pages/admin/users.astro +38 -28
- package/src/pages/api/agent/docs.ts +33 -0
- package/src/pages/api/agent/index.ts +21 -0
- package/src/pages/api/ai/clean.ts +13 -0
- package/src/pages/api/ai/draft.ts +14 -0
- package/src/pages/api/ai/settings.ts +53 -0
- package/src/pages/api/ai/test.ts +12 -0
- package/src/pages/api/backup.ts +8 -21
- package/src/pages/api/calendar/availability.ts +35 -0
- package/src/pages/api/calendar/bookings/[id].ts +49 -0
- package/src/pages/api/calendar/bookings/index.ts +73 -0
- package/src/pages/api/calendar/calendars.ts +35 -0
- package/src/pages/api/calendar/docs.ts +66 -0
- package/src/pages/api/calendar/events/[id].ts +63 -0
- package/src/pages/api/calendar/events/index.ts +112 -0
- package/src/pages/api/calendar/resources.ts +34 -0
- package/src/pages/api/design/capabilities.ts +10 -0
- package/src/pages/api/design/index.ts +58 -0
- package/src/pages/api/design/keys.ts +24 -0
- package/src/pages/api/design/media.ts +32 -0
- package/src/pages/api/email/run.ts +11 -0
- package/src/pages/api/email/settings.ts +61 -0
- package/src/pages/api/email/webhooks/[provider].ts +4 -0
- package/src/pages/api/live/oauth/youtube/callback.ts +19 -0
- package/src/pages/api/live/settings.ts +45 -0
- package/src/pages/api/live/status.ts +7 -0
- package/src/pages/api/live/thumb.ts +48 -0
- package/src/pages/api/mcp.ts +59 -0
- package/src/pages/api/media/upload.ts +2 -2
- package/src/pages/api/ops/status.ts +39 -0
- package/src/pages/api/restore.ts +27 -37
- package/src/pages/api/search.ts +18 -4
- package/src/pages/api/v1/availability.ts +7 -0
- package/src/pages/api/v1/bookings.ts +17 -0
- package/src/pages/api/v1/calendars.ts +7 -0
- package/src/pages/api/v1/content/[id].ts +7 -0
- package/src/pages/api/v1/content/index.ts +7 -0
- package/src/pages/api/v1/events.ts +7 -0
- package/src/pages/api/v1/resources.ts +7 -0
- package/src/pages/api/webhooks/docs.ts +61 -0
- package/src/pages/author/[slug].astro +43 -35
- package/src/pages/blog/[slug].astro +137 -66
- package/src/pages/blog/index.astro +95 -30
- package/src/pages/blog/tag/[slug].astro +45 -40
- package/src/pages/book/[resource]/[link].astro +70 -0
- package/src/pages/book/[resource]/index.astro +63 -0
- package/src/pages/book/[resource].ics.ts +38 -0
- package/src/pages/book/index.astro +47 -0
- package/src/pages/book/manage/[token].astro +108 -0
- package/src/pages/calendar/[slug].ics.ts +27 -0
- package/src/pages/calendar/feed.ics.ts +15 -0
- package/src/pages/calendar/index.astro +191 -0
- package/src/pages/embed/book/[resource]/[link].astro +33 -0
- package/src/pages/embed/calendar/[slug].astro +43 -0
- package/src/pages/events/[slug].astro +74 -0
- package/src/pages/events/[slug].ics.ts +25 -0
- package/src/pages/index.astro +12 -3
- package/src/pages/legal/privacy.astro +4 -0
- package/src/pages/legal/terms.astro +4 -0
- package/src/pages/links.astro +29 -3
- package/src/pages/llms.txt.ts +4 -0
- package/src/pages/preview/[type]/[id].astro +27 -6
- package/src/pages/search.astro +40 -20
- package/src/pages/sitemap.xml.ts +16 -1
- package/src/styles/admin.css +924 -105
- package/src/styles/cards.css +92 -74
- package/src/styles/editor.css +492 -114
- package/src/styles/email-settings.css +117 -0
- package/src/styles/live-admin.css +126 -0
- package/src/styles/live.css +199 -0
- package/src/styles/sections.css +12 -0
- package/src/styles/site.css +938 -281
- package/src/styles/theme-editor.css +135 -0
- package/src/theme-sdk/contract.d.mts +619 -0
- package/src/theme-sdk/contract.mjs +81 -0
- package/src/theme-sdk/index.ts +15 -0
- package/src/theme-sdk/tokens.d.mts +148 -0
- package/src/theme-sdk/tokens.mjs +55 -0
- package/src/themes/editorial/templates/home.astro +4 -4
- package/src/themes/editorial/templates/post-minimal.astro +2 -2
- package/src/themes/editorial/theme.css +27 -37
- package/src/themes/editorial/theme.json +25 -3
- package/src/themes/field/theme.json +27 -9
- package/src/themes/ink/theme.json +30 -12
- package/src/themes/night/theme.css +4 -7
- package/src/themes/night/theme.json +28 -10
- package/src/virtual.d.ts +14 -0
- package/src/worker.ts +5 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getRepo } from '../lib/repo';
|
|
3
|
+
import { liveState, publicSnapshot } from '../lib/live/service';
|
|
4
|
+
import { liveView } from '../lib/live/view';
|
|
5
|
+
import '../styles/live.css';
|
|
6
|
+
|
|
7
|
+
// One component for every live placement. Layout:
|
|
8
|
+
// compact (links page) → 'links'; display 'player' → 'split' with an
|
|
9
|
+
// in-page player; otherwise the owner's card style (poster/split/row).
|
|
10
|
+
// Theme hooks: .pc-live-* classes, --live-* tokens, [data-layout], [data-status].
|
|
11
|
+
interface Props { compact?: boolean; display?: string }
|
|
12
|
+
const { compact = false, display = 'card' } = Astro.props;
|
|
13
|
+
const { config, snapshot: raw } = await liveState(await getRepo(Astro.locals));
|
|
14
|
+
const snapshot = publicSnapshot(raw, config);
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
const v = liveView(snapshot, now);
|
|
17
|
+
const player = !compact && display === 'player';
|
|
18
|
+
const layout = compact ? 'links' : player ? 'split' : config.display.style;
|
|
19
|
+
---
|
|
20
|
+
<section
|
|
21
|
+
class="pc-live"
|
|
22
|
+
data-live-card
|
|
23
|
+
data-layout={layout}
|
|
24
|
+
data-player={player ? '' : undefined}
|
|
25
|
+
data-pin={compact ? '' : undefined}
|
|
26
|
+
data-status={v?.status ?? 'offline'}
|
|
27
|
+
data-snapshot={JSON.stringify(snapshot)}
|
|
28
|
+
data-server-now={now}
|
|
29
|
+
hidden={!v}
|
|
30
|
+
aria-label="Live video"
|
|
31
|
+
>
|
|
32
|
+
<div class="pc-live-off">
|
|
33
|
+
<i class="pc-live-off-dot" aria-hidden="true"></i>
|
|
34
|
+
<span>Not live right now</span>
|
|
35
|
+
<a data-live-watch href={v?.watchUrl || '#'} target="_blank" rel="noopener noreferrer">{v?.watchLabel}</a>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="pc-live-body">
|
|
38
|
+
<div class="pc-live-media">
|
|
39
|
+
<a class="pc-live-poster" data-live-poster href={v?.watchUrl || '#'} target="_blank" rel="noopener noreferrer" aria-label={v ? `${v.watchLabel.replace(' ↗', '')}: ${v.title}` : undefined}>
|
|
40
|
+
<span class="pc-live-ph" aria-hidden="true">
|
|
41
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="2" /><path d="M16.2 7.8a6 6 0 0 1 0 8.4M7.8 16.2a6 6 0 0 1 0-8.4M19 5a10 10 0 0 1 0 14M5 19A10 10 0 0 1 5 5" /></svg>
|
|
42
|
+
</span>
|
|
43
|
+
<img data-live-thumb src={v?.thumbUrl || undefined} alt="" loading="lazy" decoding="async" hidden={!v?.thumbUrl} />
|
|
44
|
+
<span class="pc-live-tag" data-live-tag>{v?.tag}</span>
|
|
45
|
+
<span class="pc-live-viewers" data-live-viewers hidden={!v?.viewers}>{v?.viewers}</span>
|
|
46
|
+
<span class="pc-live-play" data-live-playicon aria-hidden="true" hidden></span>
|
|
47
|
+
</a>
|
|
48
|
+
<div class="pc-live-player" data-live-player hidden></div>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="pc-live-info">
|
|
51
|
+
<span class="pc-live-kicker" data-live-kicker>{v?.kicker}</span>
|
|
52
|
+
<h2 class="pc-live-title"><span class="pc-live-title-text" data-live-title>{v?.title}</span></h2>
|
|
53
|
+
<p class="pc-live-meta" data-live-meta hidden={!v?.meta}>{v?.meta}</p>
|
|
54
|
+
<div class="pc-live-actions">
|
|
55
|
+
<button type="button" class="pc-live-btn" data-live-load hidden>Play here</button>
|
|
56
|
+
<a class="pc-live-btn" data-live-watch href={v?.watchUrl || '#'} target="_blank" rel="noopener noreferrer">{v?.watchLabel}</a>
|
|
57
|
+
</div>
|
|
58
|
+
<small class="pc-live-privacy" data-live-privacy hidden></small>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
<script>
|
|
63
|
+
import { subscribeLive, currentLive, serverNow } from '../lib/live/client';
|
|
64
|
+
import { liveView, PROVIDER_NAMES } from '../lib/live/view';
|
|
65
|
+
import type { PublicLiveSnapshot } from '../lib/live/types';
|
|
66
|
+
|
|
67
|
+
const q = <T extends HTMLElement>(root: Element, sel: string) => root.querySelector<T>(sel)!;
|
|
68
|
+
const qa = <T extends HTMLElement>(root: Element, sel: string) => Array.from(root.querySelectorAll<T>(sel));
|
|
69
|
+
|
|
70
|
+
function setupLiveCards() {
|
|
71
|
+
const cards = Array.from(document.querySelectorAll<HTMLElement>('[data-live-card]')).filter((c) => !c.dataset.initialized);
|
|
72
|
+
for (const card of cards) {
|
|
73
|
+
card.dataset.initialized = 'true';
|
|
74
|
+
let shownKey = '';
|
|
75
|
+
// the links page lifts its live block to the top while live; a marker
|
|
76
|
+
// remembers where the owner placed it
|
|
77
|
+
const home = card.hasAttribute('data-pin') ? document.createComment('live-block') : null;
|
|
78
|
+
if (home) card.before(home);
|
|
79
|
+
|
|
80
|
+
const media = q(card, '.pc-live-media');
|
|
81
|
+
const poster = q<HTMLAnchorElement>(card, '[data-live-poster]');
|
|
82
|
+
const player = q(card, '[data-live-player]');
|
|
83
|
+
const load = q(card, '[data-live-load]');
|
|
84
|
+
const img = q<HTMLImageElement>(card, '[data-live-thumb]');
|
|
85
|
+
img.addEventListener('load', () => { img.hidden = false; });
|
|
86
|
+
img.addEventListener('error', () => { img.hidden = true; });
|
|
87
|
+
|
|
88
|
+
const eligible = (s: PublicLiveSnapshot | null) =>
|
|
89
|
+
card.hasAttribute('data-player') && !!s?.embedId && s.status === 'live' &&
|
|
90
|
+
(s.provider === 'youtube' || (s.provider === 'twitch' && media.clientWidth >= 400));
|
|
91
|
+
|
|
92
|
+
function reset() {
|
|
93
|
+
player.replaceChildren();
|
|
94
|
+
player.hidden = true;
|
|
95
|
+
poster.hidden = false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function play() {
|
|
99
|
+
const s = currentLive();
|
|
100
|
+
if (!s || !eligible(s)) return false;
|
|
101
|
+
let src = '';
|
|
102
|
+
if (s.provider === 'youtube' && /^[\w-]{11}$/.test(s.embedId)) src = `https://www.youtube-nocookie.com/embed/${s.embedId}?autoplay=0`;
|
|
103
|
+
if (s.provider === 'twitch' && /^[a-z0-9_]{1,25}$/.test(s.embedId)) {
|
|
104
|
+
const u = new URL('https://player.twitch.tv/');
|
|
105
|
+
u.searchParams.set('channel', s.embedId);
|
|
106
|
+
u.searchParams.set('parent', location.hostname);
|
|
107
|
+
u.searchParams.set('autoplay', 'false');
|
|
108
|
+
src = u.href;
|
|
109
|
+
}
|
|
110
|
+
if (!src) return false;
|
|
111
|
+
const iframe = document.createElement('iframe');
|
|
112
|
+
iframe.src = src;
|
|
113
|
+
iframe.title = s.title || 'Live video';
|
|
114
|
+
iframe.allowFullscreen = true;
|
|
115
|
+
iframe.allow = 'fullscreen; picture-in-picture; encrypted-media';
|
|
116
|
+
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
|
|
117
|
+
player.replaceChildren(iframe);
|
|
118
|
+
player.hidden = false;
|
|
119
|
+
poster.hidden = true;
|
|
120
|
+
load.hidden = true;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
poster.addEventListener('click', (e) => { if (play()) e.preventDefault(); });
|
|
124
|
+
load.addEventListener('click', () => { play(); });
|
|
125
|
+
|
|
126
|
+
function pin(live: boolean) {
|
|
127
|
+
if (!home) return;
|
|
128
|
+
const slot = document.querySelector('[data-live-slot]');
|
|
129
|
+
if (live && slot) slot.after(card);
|
|
130
|
+
else if (!live && home.isConnected) home.after(card);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function render(s: PublicLiveSnapshot | null, now: number) {
|
|
134
|
+
const v = liveView(s, now);
|
|
135
|
+
card.hidden = !v;
|
|
136
|
+
const key = s ? `${s.provider}:${s.id}:${s.status}:${s.embedId}` : '';
|
|
137
|
+
if (key !== shownKey || !eligible(s)) { if (!player.hidden) reset(); }
|
|
138
|
+
shownKey = key;
|
|
139
|
+
pin(v?.status === 'live');
|
|
140
|
+
if (!v) return;
|
|
141
|
+
card.dataset.status = v.status;
|
|
142
|
+
q(card, '[data-live-tag]').textContent = v.tag;
|
|
143
|
+
q(card, '[data-live-kicker]').textContent = v.kicker;
|
|
144
|
+
q(card, '[data-live-title]').textContent = v.title;
|
|
145
|
+
const meta = q(card, '[data-live-meta]');
|
|
146
|
+
meta.textContent = v.meta;
|
|
147
|
+
meta.hidden = !v.meta;
|
|
148
|
+
const viewers = q(card, '[data-live-viewers]');
|
|
149
|
+
viewers.textContent = v.viewers;
|
|
150
|
+
viewers.hidden = !v.viewers;
|
|
151
|
+
for (const a of [poster, ...qa<HTMLAnchorElement>(card, '[data-live-watch]')]) a.href = v.watchUrl;
|
|
152
|
+
for (const a of qa(card, '[data-live-watch]')) a.textContent = v.watchLabel;
|
|
153
|
+
if (!v.thumbUrl) { img.hidden = true; img.removeAttribute('src'); }
|
|
154
|
+
else if (img.getAttribute('src') !== v.thumbUrl) img.src = v.thumbUrl;
|
|
155
|
+
const canPlay = eligible(s);
|
|
156
|
+
const name = PROVIDER_NAMES[v.provider] || 'the platform';
|
|
157
|
+
poster.setAttribute('aria-label', canPlay ? `Play ${v.title} here` : `${v.watchLabel.replace(' ↗', '')}: ${v.title}`);
|
|
158
|
+
q(card, '[data-live-playicon]').hidden = !canPlay;
|
|
159
|
+
load.hidden = !canPlay || !player.hidden;
|
|
160
|
+
const privacy = q(card, '[data-live-privacy]');
|
|
161
|
+
privacy.hidden = !canPlay;
|
|
162
|
+
privacy.textContent = `Playing loads video from ${name}.`;
|
|
163
|
+
card.dataset.playable = canPlay ? 'true' : 'false';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let initial: PublicLiveSnapshot | null = null;
|
|
167
|
+
try { initial = JSON.parse(card.dataset.snapshot || 'null'); } catch { /* no initial state */ }
|
|
168
|
+
subscribeLive(card, render, { snapshot: initial, serverNow: Number(card.dataset.serverNow) || Date.now() });
|
|
169
|
+
new ResizeObserver(() => render(currentLive(), serverNow())).observe(media);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
setupLiveCards();
|
|
173
|
+
document.addEventListener('astro:page-load', setupLiveCards);
|
|
174
|
+
</script>
|