@acms-subir/core 0.3.46 → 0.3.47

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,36 +1,56 @@
1
1
  ---
2
2
  import Site from '../../../layouts/Site.astro';
3
3
  import { getRepo } from '../../../lib/repo';
4
- import { CALENDAR } from '../../../lib/calendar/config';
4
+ import { siteLang } from '../../../lib/dates';
5
+ import { I18N, localePath } from '../../../lib/i18n';
6
+ import { isExtraLocale } from '../../../lib/translations';
7
+ import { eventStrings } from '../../../lib/calendar/event-words';
8
+ import { CALENDAR, eventUrl } from '../../../lib/calendar/config';
5
9
  import { calendarWindow, renderCalendarView } from '../../../lib/calendar/render';
6
10
  import { collectViewEvents } from '../../../lib/calendar/data';
7
11
  import { upcomingEvents, eventCardHtml } from '../../../lib/calendar/cards';
12
+ import { readEventFilter, resolveEventFilter } from '../../../lib/calendar/filter';
8
13
 
9
14
  // Embeddable calendar for other websites:
10
15
  // <iframe src="https://site/embed/calendar/all?view=month" …>
11
16
  // slug 'all' = every public calendar. view: month | week | list | cards.
12
- // Links open in the parent window; height is posted to the parent so a
13
- // small script can auto-size the iframe.
17
+ // The /calendar page's filters work here too (?tag=Class, ?notag=,
18
+ // ?cal=a,b to add calendars, ?room=), and ?lang=es picks one of the site's
19
+ // languages (embeds are never under /es). Links open in the parent window;
20
+ // height is posted to the parent so a small script can auto-size the iframe.
14
21
  if (!CALENDAR.enabled) return new Response(null, { status: 404 });
15
22
  const repo = await getRepo(Astro.locals);
16
- const settings = await repo.getSettings();
23
+ const base = await repo.getSettings();
17
24
  const slug = Astro.params.slug ?? 'all';
18
25
  const cal = slug === 'all' ? null : await repo.getCalendarBySlug(slug);
19
26
  if (slug !== 'all' && (!cal || cal.visibility === 'private')) return new Response(null, { status: 404 });
27
+ const langParam = Astro.url.searchParams.get('lang') ?? '';
28
+ const reqLocale = I18N.enabled ? (I18N.locales.includes(langParam) ? langParam : I18N.defaultLocale) : '';
29
+ // the layout's <html lang> reads the request's language
30
+ if (reqLocale) (Astro.locals as { acmsLocale?: string }).acmsLocale = reqLocale;
31
+ const settings = isExtraLocale(reqLocale) ? { ...base, locale: reqLocale } : base;
32
+ const lang = reqLocale || siteLang(settings);
33
+ const w = eventStrings(lang).calendar;
34
+
35
+ const query = readEventFilter(Astro.url.searchParams);
36
+ const filter = cal ? { ...query, cal: [cal.slug, ...query.cal] } : query;
37
+ const [calendars, resources] = await Promise.all([repo.listCalendars(), filter.room.length ? repo.listResources() : []]);
38
+ const resolved = resolveEventFilter(filter, { calendars, resources });
20
39
  const view = (['month', 'week', 'list', 'cards'] as const).find((v) => v === Astro.url.searchParams.get('view')) ?? 'month';
21
40
  const now = Date.now();
22
41
  let html: string;
23
42
  if (view === 'cards') {
24
- const items = await upcomingEvents(repo, settings, now, { calendarIds: cal ? [cal.id] : undefined, limit: Math.min(12, Number(Astro.url.searchParams.get('limit')) || 6) });
25
- html = `<section class="pc-ev-cards" data-layout="grid">${items.map((o) => eventCardHtml(o, settings, { showImage: true })).join('') || '<p class="pc-ev-empty">No upcoming events.</p>'}</section>`;
43
+ const items = await upcomingEvents(repo, settings, now, { filter: resolved, locale: lang, limit: Math.min(12, Number(Astro.url.searchParams.get('limit')) || 6) });
44
+ const cards = items.map((o) => eventCardHtml(o, settings, { showImage: true, href: localePath(eventUrl(o.event.slug), reqLocale) })).join('');
45
+ html = '<section class="pc-ev-cards" data-layout="grid">' + (cards || '<p class="pc-ev-empty">' + w.noUpcoming + '</p>') + '</section>';
26
46
  } else {
27
- const { events, calendars } = await collectViewEvents(repo, settings, calendarWindow(settings, now), { audience: 'public', ...(cal ? { calendarIds: [cal.id] } : {}) });
28
- html = renderCalendarView(events, settings, now, { view: view === 'list' ? 'upcoming' : view, limit: 30, multi: !cal && calendars.length > 1 });
47
+ const { events, calendars: shown } = await collectViewEvents(repo, settings, calendarWindow(settings, now), { audience: 'public', filter: resolved, locale: lang });
48
+ html = renderCalendarView(events, settings, now, { view: view === 'list' ? 'upcoming' : view, limit: 30, multi: shown.length > 1 });
29
49
  }
30
50
  Astro.response.headers.set('Content-Security-Policy', "frame-ancestors *");
31
51
  ---
32
52
 
33
- <Site title={cal?.name ?? 'Calendar'} bare noindex>
53
+ <Site title={cal?.name ?? w.title} bare noindex>
34
54
  <base target="_top" />
35
55
  <div class="pc-embed" set:html={html} />
36
56
  <script is:inline>
@@ -930,6 +930,16 @@ li::marker { color: var(--muted); }
930
930
  .pc-calpage-chips a:hover { color: var(--ink); }
931
931
  .pc-calpage-chips a.is-on { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 var(--ink); }
932
932
  .pc-calpage-chips i { width: 7px; height: 7px; border-radius: 2px; }
933
+ /* active filters from the address (tag, left-out tag, room): removable chips */
934
+ .pc-calpage-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: -2px 0 16px; }
935
+ .pc-calpage-filter {
936
+ display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 11px; border-radius: var(--r-sm);
937
+ background: var(--soft); color: var(--ink); font-size: 13px; font-weight: 550; text-decoration: none;
938
+ }
939
+ .pc-calpage-filter svg { width: 13px; height: 13px; color: var(--muted); }
940
+ .pc-calpage-filter:hover svg { color: var(--ink); }
941
+ .pc-calpage-clear { padding: 0 6px; font-size: 13px; color: var(--muted); text-decoration: none; }
942
+ .pc-calpage-clear:hover { color: var(--ink); }
933
943
  .pc-calpage-tools { display: flex; gap: 8px; align-items: center; margin-left: auto; }
934
944
  .pc-calpage-views { display: inline-flex; background: var(--soft); border-radius: 10px; padding: 3px; }
935
945
  .pc-calpage-views a { padding: 5px 12px; border-radius: 7px; font-size: 13px; font-weight: 550; color: var(--muted); text-decoration: none; }