---
path: /domains/nyx/events
surface: customer
domain: nyx
auth: signed-in
source: apps/oshun/web/src/app/domains/nyx/events/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content
  re-verified 2026-06-03 against current source'
---

# Nyx · Celestial Events Calendar

## Purpose

Canonical Nyx event calendar with cross-domain bridges — lists upcoming sky
events with importance filtering, Nisaba/Veritas/Tara/Concept-graph focus panels
for the lead event, and per-event save / follow / reminder / ICS calendar-export
actions. Page is a `'use client'` shell
(`apps/oshun/web/src/app/domains/nyx/events/page.tsx`) that mounts
`<EventCalendarOverlay onClose={() => router.replace('/domains/nyx?origin=explore')} origin="explore" stack={[]} />`
under an `sr-only` `<h1>Celestial Events · Nyx · OSHUN</h1>`. The hydrated shell
variant at `/domains/nyx?origin=...&path=%2Fevents` closes by removing only the
`path` query while preserving `origin` and `stack`.

## Entry points

- **Direct URL / bookmark** — yes (signed-in)
- **In-app navigation** — verify the entry points (Nyx hub link, cross-domain
  explore rail)
- **Event detail back-link** — `NyxEventDetailWorkspace` shows "Return to Nyx
  events" → `/domains/nyx?origin=explore&path=%2Fevents` (so a detour through
  the domain root, not the `/domains/nyx/events` URL)
- **Close affordance** — direct `/domains/nyx/events` arrivals replace to the
  canonical `/domains/nyx?origin=explore` shell; hydrated-shell arrivals remove
  only `path` and preserve the incoming shell context

## Layout regions

`EventCalendarOverlay`
(`apps/oshun/web/src/components/domains/nyx/EventCalendarOverlay.tsx`) renders
inside an `OverlaySheet` with `variant="fullscreen"`,
`title="Celestial Calendar"`,
`description="Upcoming astronomical events and viewing windows."`

- **`sr-only` heading**: page-level `<h1>Celestial Events · Nyx · OSHUN</h1>`
- **OverlaySheet header**: title + description + close button (sheet affordance)
- **Timezone hint**: `Times shown in: <Intl timezone>`
- **Importance filter radio group**: chips `All | Major | Notable | Minor`
  (`role="radiogroup"`, `aria-label="Filter by importance"`)
- **Count line**: `<N> event(s)`
- **`SkyTextJourneyRail`** — cross-domain breadcrumb rail wired to the active
  stage `open-cosmology-and-texts` ("Open cosmology and texts"). The rail
  renders the four canonical stages in order: "Hold the sky moment", "Frame the
  observation", "Open cosmology and texts", and "Preserve the sky thread"; the
  active stage's primary action is "Open cosmology passage".
- **Nisaba overlay focus panel** ("Nisaba overlay focus",
  `data-testid="nyx-calendar-nisaba-focus"`, ~190; if
  `focusEvent.nisabaOverlays.length > 0`)
- **Veritas evidence focus panel** ("Veritas evidence focus",
  `data-testid="nyx-calendar-veritas-focus"`, ~252; if
  `focusEvent.veritasExplainers.length > 0`)
- **Tara perspective focus panel** ("Tara perspective focus",
  `data-testid="nyx-calendar-tara-focus"`, ~310; if
  `focusEvent.taraRecommendations.length > 0`)
- **Concept-graph focus panel** ("Concept graph focus",
  `data-testid="nyx-calendar-concept-graph-focus"`, ~372; if
  `focusEvent.conceptGraphThreads.length > 0`)
- **Event rows**: each row shows time, importance pill, event-type chip,
  window/countdown/visibility line, summary, badges, action buttons, and a "View
  event page" link

## States

- [ ] **Loading** — bundled model from `listNyxEventPageModels()`; no fetch
- [ ] **Populated (All filter)** — every model returned by
      `listNyxEventPageModels({ origin, stack })`
- [ ] **Filtered (Major / Notable / Minor)** — filter narrows the list
- [ ] **Empty (filter excludes all)** — count reads `0 events`; verify empty
      state copy
- [ ] **Focus event with Nisaba overlays** — Nisaba focus panel renders
- [ ] **Focus event with Veritas explainers** — Veritas focus panel renders
- [ ] **Focus event with Tara recommendations** — Tara perspective focus panel
      renders
- [ ] **Focus event with concept-graph threads** — Concept-graph focus panel
      renders
- [ ] **Focus event with none of the above** — each of the four focus panels is
      independently omitted when its array is empty
- [ ] **Reminder enabled** — `NyxEventReminderControls` (compact) expands under
      the action row
- [ ] **Offline** — static client computation; reminder/save state lives in
      `useNyxEventActionState` (verify persistence)
- [ ] **Standalone PWA** — overlay sheet covers full viewport

## Interactions

### OverlaySheet chrome

- [x] **Close button** (sheet-level) — `nyx-full-journey` verifies direct-route
      close lands on `/domains/nyx?origin=explore` and hydrated-shell close
      removes `path` while preserving `origin=home&stack=tara`

### Importance filter

- [ ] **"All" radio chip** (`role="radio"`, `aria-checked`)
  - Function: `setFilter('All')`
- [ ] **"Major" radio chip** — colored with `var(--l-alert)`
- [ ] **"Notable" radio chip** — colored with `var(--l-warn)`
- [ ] **"Minor" radio chip** — colored with `L.muted`

### Focus panels

- [x] **`SkyTextJourneyRail`** — cross-domain rail with stage labels from
      `OSHUN_SKY_TEXT_STAGE_MODEL`: "Hold the sky moment", "Frame the
      observation", "Open cosmology and texts", and "Preserve the sky thread".
      Step action targets are produced by
      `apps/oshun/web/src/navigation/sky-text-journey.ts`:
      `sky-nyx-nightly-highlights` → Nyx nightly highlights,
      `sky-nyx-event-calendar` → Nyx events, `sky-nyx-sky-map` → Nyx sky map,
      `sky-nyx-observation-log` → Nyx observations,
      `sky-nisaba-cosmology-passage` → Nisaba cosmology passage,
      `sky-nisaba-calendar-source` → Nisaba calendar source,
      `sky-nisaba-compare-texts` → Nisaba compare, `sky-nisaba-notebook` →
      Nisaba notebook, and `sky-library-save` → Library notebook filter.
- [ ] **`NisabaFocusLink`** (each overlay) — link to Nisaba surface
- [ ] **`VeritasFocusLink`** (each explainer) — link to a Veritas explainer
- [ ] **`TaraFocusLink`** (each `taraRecommendations` entry) — link into a Tara
      practice
- [ ] **`ConceptGraphFocusThread`** (each `conceptGraphThreads` entry) — link
      into the cross-domain concept graph

### Per-event row (each event in `filteredEvents`)

- [ ] **Importance pill** — read-only badge with `event.importanceLabel`
- [ ] **Event-type chip** — read-only with `event.eventTypeLabel`
- [ ] **Summary line** —
      `event.windowLabel · event.countdownLabel ·     event.visibilityLabel`
- [ ] **Save toggle** (button, `data-testid="nyx-event-save-toggle-<eventId>"`)
  - Function: `toggleSaved` — flips saved state
  - Label: "Save" → "Saved"
- [ ] **Follow toggle** (button,
      `data-testid="nyx-event-follow-toggle-<eventId>"`)
  - Label: "Follow" → "Following"
- [ ] **Reminder toggle** (button,
      `data-testid="nyx-event-reminder-toggle-<eventId>"`)
  - Label: "Remind" → "Reminder on"
- [ ] **"Add to Calendar (.ics)" button**
  - Function: `downloadNyxEventICalFile(event.eventId)` — triggers ICS file
    download
  - Screen reader: `aria-label='Add "<event.title>" to calendar'`
- [ ] **"View event page" link** (`data-testid="nyx-event-open-<eventId>"`)
  - Function: navigates to `event.domainHref` (`/domains/nyx/events/<id>`)
- [ ] **Reminder cadence + channels controls** (when reminder enabled)
  - Compact `NyxEventReminderControls` with `setReminderCadence` and
    `setReminderChannels`

## Data & contracts

- **Reads**: `listNyxEventPageModels({ origin, stack })` from
  `nyxEventPageModels` — bundled event index
- **Writes**: ICS file download via `downloadNyxEventICalFile(eventId)`; save /
  follow / reminder state via `useNyxEventActionState` (verify persistence:
  localStorage vs server)
- **Realtime**: none
- **Caching**: client bundle, static
- **Auth/role check**: middleware enforces signed-in for `/domains/*`

## Cross-references

- Detail view:
  [`domains-nyx-events-eventId.md`](./domains-nyx-events-eventId.md)
- Domain hub: [`nyx.md`](./nyx.md)
- Component source:
  `apps/oshun/web/src/components/domains/nyx/EventCalendarOverlay.tsx`
- Model source:
  `apps/oshun/web/src/components/domains/nyx/nyxEventPageModels.ts`
- Action hook:
  `apps/oshun/web/src/components/domains/nyx/useNyxEventActionState.ts`

## Open questions / known gaps

- [ ] Confirm whether save / follow / reminder state persists across reloads
      (`useNyxEventActionState` storage strategy)
- [ ] Document the cross-domain bridge — `domainHref` from the rail (the event
      domain target) versus `/domains/nyx/events/[eventId]` page
- [x] Confirm whether `OverlaySheet` close emits a route navigation or just
      hides the sheet — fixed and verified 2026-06-24. Direct route close
      replaces to `/domains/nyx?origin=explore`; hydrated shell close removes
      only `path` and keeps the rest of the shell context.
- [ ] Verify whether unfiltered list contains a virtualized scroll for large
      catalogs
