astro-theme-popular 0.12.0 → 0.13.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/package.json
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
/** Calendar subscribe buttons for the events feed: a webcal link that opens
|
|
3
|
+
* the user's calendar app subscribed to the live feed (Apple Calendar,
|
|
4
|
+
* Outlook, Thunderbird), a Google Calendar deep link (Google registers no
|
|
5
|
+
* webcal handler on the web or Android), and the plain .ics download as the
|
|
6
|
+
* universal fallback for "add calendar from URL" flows. webcal needs an
|
|
7
|
+
* absolute URL, so the feed path goes through absoluteUrl. Mirrors Hugo's
|
|
8
|
+
* partials/calendar-subscribe.html; callers supply the wrapping .g-row. */
|
|
9
|
+
import { STRINGS } from 'popular:config';
|
|
10
|
+
import { withBase, absoluteUrl } from '../lib/url';
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
small?: boolean;
|
|
14
|
+
}
|
|
15
|
+
const { small = false } = Astro.props;
|
|
16
|
+
|
|
17
|
+
const feedPath = '/events/calendar.ics';
|
|
18
|
+
const webcal = absoluteUrl(feedPath, Astro.site ?? Astro.url).replace(/^https?:/, 'webcal:');
|
|
19
|
+
const google = `https://calendar.google.com/calendar/render?cid=${encodeURIComponent(webcal)}`;
|
|
20
|
+
const size = small ? ' g-btn--sm' : '';
|
|
21
|
+
---
|
|
22
|
+
<a class={`g-btn g-btn--outline${size}`} href={webcal}><i class="fa-solid fa-calendar-plus" aria-hidden="true"></i> {STRINGS.subscribeCalendar}</a>
|
|
23
|
+
<a class={`g-btn g-btn--outline${size}`} href={google} rel="noopener" target="_blank"><i class="fa-brands fa-google" aria-hidden="true"></i> {STRINGS.subscribeGoogle}</a>
|
|
24
|
+
<a class={`g-btn g-btn--ghost${size}`} href={withBase(feedPath)} download><i class="fa-solid fa-download" aria-hidden="true"></i> {STRINGS.downloadCalendar}</a>
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
/** Designed empty state for zero upcoming events (§5). Shown on the home page
|
|
3
3
|
* and events list instead of a blank section: a message, then the chat CTA
|
|
4
|
-
* (if SITE.community.chat is set, §4) and the calendar-subscribe
|
|
5
|
-
* The calendar
|
|
4
|
+
* (if SITE.community.chat is set, §4) and the calendar-subscribe buttons.
|
|
5
|
+
* The calendar feed mirrors Hugo's OutputFormats "Calendar" endpoint. */
|
|
6
6
|
import { SITE, STRINGS } from 'popular:config';
|
|
7
7
|
import { withBase } from '../lib/url';
|
|
8
|
+
import CalendarSubscribe from './CalendarSubscribe.astro';
|
|
8
9
|
|
|
9
10
|
const chat = (SITE as Record<string, any>).community?.chat;
|
|
10
|
-
const calendar = '/events/calendar.ics';
|
|
11
11
|
const external = (url: string) => !url.startsWith('/');
|
|
12
12
|
---
|
|
13
13
|
<div class="g-empty">
|
|
14
14
|
<span class="g-medallion g-medallion--lg"><i class="fa-solid fa-calendar-day" aria-hidden="true"></i></span>
|
|
15
15
|
<p class="g-lead">{STRINGS.noUpcomingEvents}</p>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
{chat
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</div>
|
|
25
|
-
)}
|
|
16
|
+
<div class="g-row" style="justify-content:center">
|
|
17
|
+
{chat?.url && (
|
|
18
|
+
<a class="g-btn g-btn--primary" href={withBase(chat.url)} {...(external(chat.url) ? { rel: 'noopener', target: '_blank' } : {})}>
|
|
19
|
+
<i class="fa-solid fa-comments" aria-hidden="true"></i> {chat.label ?? STRINGS.joinChat}
|
|
20
|
+
</a>
|
|
21
|
+
)}
|
|
22
|
+
<CalendarSubscribe />
|
|
23
|
+
</div>
|
|
26
24
|
</div>
|
package/src/lib/ical.ts
CHANGED
|
@@ -61,6 +61,10 @@ export function buildIcs(
|
|
|
61
61
|
L.push(fold('CALSCALE:GREGORIAN'));
|
|
62
62
|
L.push(fold('METHOD:PUBLISH'));
|
|
63
63
|
L.push(fold(`X-WR-CALNAME:${opts.siteTitle} events`));
|
|
64
|
+
/* Subscription refresh hints (RFC 7986 + the Apple/Outlook legacy twin).
|
|
65
|
+
Google Calendar ignores both and polls on its own schedule. */
|
|
66
|
+
L.push(fold('REFRESH-INTERVAL;VALUE=DURATION:PT12H'));
|
|
67
|
+
L.push(fold('X-PUBLISHED-TTL:PT12H'));
|
|
64
68
|
for (const e of events) {
|
|
65
69
|
L.push(fold('BEGIN:VEVENT'));
|
|
66
70
|
L.push(fold(`UID:${e.permalink}`));
|
|
@@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
|
4
4
|
import PageHero from 'popular:component/PageHero';
|
|
5
5
|
import EventRow from 'popular:component/EventRow';
|
|
6
6
|
import Pagination from '../../components/Pagination.astro';
|
|
7
|
-
import
|
|
7
|
+
import CalendarSubscribe from '../../components/CalendarSubscribe.astro';
|
|
8
8
|
import EventsEmpty from '../../components/EventsEmpty.astro';
|
|
9
9
|
import { SECTIONS, STRINGS, PAGINATION } from 'popular:config';
|
|
10
10
|
|
|
@@ -54,7 +54,7 @@ const groupByYear = (events: EventEntry[]) => {
|
|
|
54
54
|
<span class="g-eyebrow">{STRINGS.comingUp}</span>
|
|
55
55
|
<h2>{STRINGS.upcomingEvents}</h2>
|
|
56
56
|
<p class="g-lead">{STRINGS.upcomingLead}</p>
|
|
57
|
-
<div class="g-row" style="margin-top:var(--space-3)"><
|
|
57
|
+
<div class="g-row" style="margin-top:var(--space-3)"><CalendarSubscribe small /></div>
|
|
58
58
|
</div>
|
|
59
59
|
<div class="g-stack" style="margin-top:var(--space-4);gap:var(--space-3)">
|
|
60
60
|
{groupByYear(upcoming).map((group) => (
|