Skip to content

Design: card / detail layout customization config (deferred) #53

Description

@ronaldtse

What

Card / detail page layout customization is currently code-driven. Consumers can hide elements via CSS or fork components, but there's no config surface to reorder or selectively render card meta items / detail page sections.

The README's ## Known limitations section already documents this. This issue captures the design space so we have something to point at when a real consumer asks for it.

Why now / not now

YAGNI: none of the three current consumers need it.

  • isotc184sc4 uses the default UI and hasn't asked for layout changes.
  • tc154 uses the default UI alongside custom HTML pages in content/pages/ — no conflicts.
  • OIML has a fully custom site (OimlLayout.astro, custom utilities) and doesn't use the package's UI components at all.

Adding speculative API surface now means:

  • Test surface we maintain for a feature nobody uses
  • Backwards-compat constraints if we get the shape wrong
  • More for new consumers to learn

The right time to add this is when at least one consumer says "I want to hide section X" or "I want to swap component Y" — then we design the API around a concrete need.

Design space (when the need arises)

Three patterns, in increasing scope:

Option A — Visibility + order via list config (smallest)

components: {
  meetingCard: {
    metaItems: ['date', 'type', 'committee', 'count']
    // 'status' omitted -> hidden. Order honored.
  },
  meetingDetail: {
    sections: ['when', 'venue', 'officers', 'agenda', 'decisions']
  },
  decisionDetail: {
    sections: ['actions', 'approvals', 'considerations']
  },
}
  • Pro: simple, declarative, covers the common case (hide + reorder)
  • Con: list is closed (consumer can't add new item types)
  • Effort: ~1 day. MeetingCard is a clean refactor. MeetingDetail + DecisionDetail sections are inline with complex conditionals — extraction is bigger.

Option B — Component registry via Vite alias (medium)

components: {
  MeetingCard: './src/MyMeetingCard.astro',
  MeetingDetail: './src/MyMeetingDetail.astro',
}

Resolves at build time via Vite alias rewriting @edoxen/browser/MeetingCard → consumer's path.

  • Pro: full component swap, unlimited customization
  • Con: tightest coupling to Vite internals; Astro doesn't standardly support this in integrations; consumer needs to understand the full prop contract of each component they replace
  • Effort: ~2-3 days. Needs a contract test that the consumer's component accepts the same props as the default.

Option C — Astro slot overrides (largest)

Each default component exposes named slots that consumers override via children:

<MeetingCard item={m}>
  <span slot="meta-item" class="my-custom">Custom</span>
</MeetingCard>
  • Pro: most Astro-idiomatic, no alias magic
  • Con: requires consumers to fork their pages to use the slot API; doesn't fit the "config is SSOT" model
  • Effort: ~3-5 days. Requires re-architecting how pages compose with components.

Recommendation

When a real consumer need appears, start with Option A for MeetingCard only (smallest scope, biggest UX win). Defer detail-page section config until a second consumer need arises — those sections have complex inline logic and would benefit from extraction to per-section components first.

Existing workarounds (documented in README)

  1. CSS-onlytheme.customCss pointing at an override stylesheet. Hide elements, reorder within a flex/grid, restyle. Works for visual tweaks.
  2. Consumer Astro app (Mode A) — fork any component by dropping a replacement into src/components/. Full layout freedom; loses auto-updates of the forked component.
  3. Fork the package — for wholesale layout changes.

Trigger criteria

Close this issue when:

  • A consumer explicitly requests config-driven card / detail layout, OR
  • We extract detail-page sections into per-section components for some other reason (then Option A becomes cheap).

Until then, leave the README's "Known limitations" section as the canonical answer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions