@museumwnf/viewer-layout 2.15.1 → 2.16.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/README.md +108 -28
- package/dist/BackLink-LfSIuXnL.js +45 -0
- package/dist/TimelineEventList-D5Hot788.js +1362 -0
- package/dist/{TimelineLookup-DRc43FkL.js → TimelineLookup-D-p1aQ_Z.js} +1 -1
- package/dist/TimelineResultsView-DJo_yYEK.js +1203 -0
- package/dist/{content-DUXrQ-l8.js → content-DncTPD5P.js} +46 -21
- package/dist/content.js +5 -5
- package/dist/dxa.js +418 -562
- package/dist/index.js +5 -5
- package/dist/viewer-layout.css +1 -1
- package/dist/views.js +287 -271
- package/package.json +3 -3
- package/src/tokens.reference.css +26 -0
- package/dist/BackLink-BJ16COHd.js +0 -106
- package/dist/TimelineEventList-BmfLBaTT.js +0 -967
- package/dist/TimelineResultsView-D78PPWk-.js +0 -1220
package/README.md
CHANGED
|
@@ -1,20 +1,67 @@
|
|
|
1
1
|
# @museumwnf/viewer-layout
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
What the pages of an MWNF website are made of: the page frame, the building
|
|
4
|
+
blocks, the composed views, and the pages of the DXA family (the galleries and
|
|
5
|
+
the exhibitions). Every visual value comes from a `--mwnf-*` token, and a
|
|
6
|
+
website sets its own values in `theme/tokens.css`; the package defines none.
|
|
7
|
+
|
|
8
|
+
## Entry points and layers
|
|
9
|
+
|
|
10
|
+
Each entry point belongs to one layer of the platform's
|
|
11
|
+
[architecture reference](https://github.com/museumwithnofrontiers/inventory-app/issues/1510), which says what goes where across
|
|
12
|
+
all the packages:
|
|
13
|
+
|
|
14
|
+
| Entry | Layer | Holds | Reads |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `@museumwnf/viewer-layout` | building blocks | `PageShell` and its seven sections, and every block of `/content` | its props, and the texts and Markdown renderers of `@museumwnf/viewer-core` |
|
|
17
|
+
| `@museumwnf/viewer-layout/content` | building blocks | the blocks alone, without the shell | the same |
|
|
18
|
+
| `@museumwnf/viewer-layout/views` | composed views | whole pages driven by a spec the website declares, with slots it fills | viewer-core's data layer, the site config and the router |
|
|
19
|
+
| `@museumwnf/viewer-layout/components` | composed views | `SiteShell`, the frame composed from `dataset.config.js` | the site config and the current route |
|
|
20
|
+
| `@museumwnf/viewer-layout/dxa` | DXA family layer | the gallery and exhibition pages, `standardRoutes` | the entries above, `@museumwnf/viewer-core` and `@museumwnf/viewer-core/dxa` |
|
|
21
|
+
| `@museumwnf/viewer-layout/style.css` | — | one stylesheet for every entry, the family styles included | — |
|
|
22
|
+
| `@museumwnf/viewer-layout/tokens.reference.css` | — | every token the package reads, with its fallback | — |
|
|
23
|
+
|
|
24
|
+
A block is fed by its props: a plain view-model built by viewer-core or by
|
|
25
|
+
the website. Beyond its props it reads only viewer-core's texts and
|
|
26
|
+
renderers, and at most the one viewer-core helper its job needs
|
|
27
|
+
(`GlossaryTool` searches the glossary, `SourceCredit` builds the page's
|
|
28
|
+
address). It declares no route and reads no spec: that is what a composed
|
|
29
|
+
view does.
|
|
30
|
+
|
|
31
|
+
**Where a new component goes:**
|
|
32
|
+
|
|
33
|
+
1. **Into the lowest layer that fits.** A block comes before a composed view,
|
|
34
|
+
and a composed view before a family page. A block is promoted here when
|
|
35
|
+
several websites need the same thing; a whole page is shared only inside
|
|
36
|
+
the DXA family, under `/dxa`.
|
|
37
|
+
2. **A generic component never defaults to one family's texts.** A block or a
|
|
38
|
+
composed view defaults to a shared entry (`core.*`, `record.*`,
|
|
39
|
+
`partner.*`, …) or takes the entry name as a prop; it never defaults to a
|
|
40
|
+
`gallery.*` or `exhibition.*` entry.
|
|
41
|
+
3. **A component only the DXA family uses belongs under `/dxa`.**
|
|
42
|
+
|
|
43
|
+
**The dependency runs one way.** The root, `/content`, `/views` and
|
|
44
|
+
`/components` never import from `/dxa`. `/dxa` imports only what the other
|
|
45
|
+
entries publish, and `@museumwnf/viewer-core`. A component that moves
|
|
46
|
+
between entries keeps its old export as an alias until the websites have
|
|
47
|
+
moved; a major release then removes the alias.
|
|
48
|
+
|
|
49
|
+
Where the package does not follow these rules yet, milestone M10 moves it:
|
|
50
|
+
`FeaturedPartners`, `SiblingGalleries`, `PopupLogo`, `PictureGallery`,
|
|
51
|
+
`PictureNarrative` (blocks) and `RecordSheetView` (a composed view) are used
|
|
52
|
+
only by the DXA family and move under `/dxa`
|
|
53
|
+
([inventory-app#2017](https://github.com/museumwithnofrontiers/inventory-app/issues/2017));
|
|
54
|
+
`PictureGallery`, `PictureNarrative` and `EssayView` default to
|
|
55
|
+
`exhibition.*` entries, and `FeaturedPartners` to `partner.featured`, which
|
|
56
|
+
does not exist.
|
|
10
57
|
|
|
11
58
|
Two companion docs give a more scannable version of who-owns-what and the
|
|
12
59
|
full slot list: [`docs/designer-contract.md`](docs/designer-contract.md) (the
|
|
13
|
-
four roles — components, tokens/CSS, site designer, translator —
|
|
14
|
-
token → overrides → slot → own-view decision ladder
|
|
15
|
-
[`docs/slot-catalogue.md`](docs/slot-catalogue.md)
|
|
16
|
-
`PageShell`, `SiteShell` and the
|
|
17
|
-
for every `/content` component).
|
|
60
|
+
four roles — components, tokens/CSS, site designer, translator — the
|
|
61
|
+
token → overrides → slot → own-view decision ladder, and where a new
|
|
62
|
+
component goes) and [`docs/slot-catalogue.md`](docs/slot-catalogue.md)
|
|
63
|
+
(every prop and slot of `PageShell`, `SiteShell` and the composed views,
|
|
64
|
+
plus a one-line purpose for every `/content` component).
|
|
18
65
|
|
|
19
66
|
## Install
|
|
20
67
|
|
|
@@ -27,7 +74,7 @@ new version is published there.)
|
|
|
27
74
|
npm install @museumwnf/viewer-layout
|
|
28
75
|
```
|
|
29
76
|
|
|
30
|
-
`@museumwnf/viewer-core` (1.
|
|
77
|
+
`@museumwnf/viewer-core` (2.1.0 or later) is a peer dependency: the layout
|
|
31
78
|
reads its texts from the application's catalogue through it, and renders the
|
|
32
79
|
one Markdown prop it has (the banner headline) through its pipeline.
|
|
33
80
|
|
|
@@ -81,6 +128,12 @@ own `t()`.
|
|
|
81
128
|
|
|
82
129
|
## PageShell
|
|
83
130
|
|
|
131
|
+
`PageShell` covers the needs of every website from props. A website fills the
|
|
132
|
+
sections it has and leaves the rest empty; a slot is for the *content* of a
|
|
133
|
+
section — the mark in the header, the active view — not for rebuilding the
|
|
134
|
+
section. A website that needs something no prop expresses adds the prop
|
|
135
|
+
here, so the next website has it too.
|
|
136
|
+
|
|
84
137
|
Sections render top to bottom in this fixed order. Every section is optional: it renders nothing unless its slot or driving props are set. The default slot (→ `AppContent`) is where the router-view goes.
|
|
85
138
|
|
|
86
139
|
| Section | Slot | Props (on PageShell) | Events |
|
|
@@ -265,7 +318,8 @@ the application registered, without any router coupling here.
|
|
|
265
318
|
| `MediaGallery` | `images: [{ url, alt, caption, photographer, copyright }]`, `start`, `variant: '' \| 'row'` | the current image, thumbnails, caption, a lightbox (Escape closes, arrows move, focus returns); `row` renders every image in a row |
|
|
266
319
|
| `GlossaryPopover` | `term: { word, spelling, definition }`, `html`, `dir`; emits `close` | the definition of a clicked term, fixed in a corner; Escape closes, focus returns |
|
|
267
320
|
| `PartnerMap` | `latitude`, `longitude`, `zoom` (15), `mapTitleEntry` ('partner.map.map'), `mapOfEntry` ('partner.map.mapOf'), `openMapLinkEntry` ('partner.map.openInOpenStreetMap'), `label` | an OpenStreetMap embed centred on coordinates with a zoom level; builds a bounding box for OSM's embed and a full-map link; uses keyless public tiles |
|
|
268
|
-
| `
|
|
321
|
+
| `PartnerPanel` | `partner` (viewer-core's `partnerView()`), `variant: 'line' \| 'summary' \| 'full'`, `layout: 'tabs' \| 'sections'` (`full`), `show: { part: false }` (`logo`, `location`, `count`, `pictures`, `description`, `contact`, `persons`, `logos`, `homepage`, `map`; `actions: true` turns on the line's links, `logo: true` the summary's logo), `heading` (level of the name; 0 = none), `label` (summary: the entry before the name), `objectsLabel` ('partner.item.objectsInSite'), `emptyLabel`, `homepageLabel` ('partner.nav.homepage'), `readMoreLabel` ('partner.action.readMore'), `viewObjectsLabel` ('partner.action.viewObjects'), `dir` | one partner, wherever it appears (decisions D2/D3). `line`: a list's row — logo, the name as a link with its city, the object count or `emptyLabel`, the actions. `summary`: the line under an item's holder text — `label`, the name as a link, "city, country"; with `heading`, the name heads the page over its location. `full`: the partner page — the name and location, a band with the About · Contact · Logo tabs (accessible, arrow keys move along), the ↗ homepage link and the `actions` slot, the pictures beside the open panel, the map below; `sections` shows About, Contact and Logo one after another under their titles. The contact reads in legacy order: address, phone, fax, email, website and links, then the contact persons. Slots `badge`, `meta`, `actions`, `after`, each given `{ partner }`; tokens `--mwnf-partner-*` |
|
|
322
|
+
| `FeaturedPartners` | `records: [{ id, name, logo, city, country, description, route }]`, or `partners` (view-models from viewer-core's `partnerView()`: the first picture or logo, "city, country", the description as plain text cut at `descriptionLength`, 420), `headingEntry` ('partner.featured') | a carousel of partners with bullet controls, rotated on an 8-second timer; the site provides filtered/shuffled records and routes |
|
|
269
323
|
| `SiblingGalleries` | `galleries: [{ id, name, image?, route }]`, `museums: [{ name, to \| href, accent?, textColor? }]`, `galleriesHeadingEntry`, `seeMoreGalleriesEntry`, `seeMoreGalleriesHref`, `museumsHeadingEntry` | two blocks of links: sibling galleries (may be unresolved, rendering as non-clickable tiles) and MWNF virtual museums (text initials over a coloured background) |
|
|
270
324
|
| `PopupLogo` | `content` (Markdown or raw HTML), `rawHtml` (false), `enabled` (true), `closeLabel` ('core.action.close') | a dismissible fixed modal for sponsor notices; renders content through `renderInline` by default (escaping, Markdown); when `rawHtml: true`, passes content as-is (for trusted HTML from the importer) |
|
|
271
325
|
| `BackLink` | `label` ('core.action.back'), `to \| href` (fallback when history is unavailable) | a "back" link that calls `router.back()` when browser history is available (length > 1); falls back to the provided route |
|
|
@@ -289,16 +343,24 @@ The texts they read — `core.action.apply`, `.reset`, `.close`,
|
|
|
289
343
|
`record.media.photograph`, `record.sheet.credits`, `.languages` — are in
|
|
290
344
|
every bundle of `@museumwnf/viewer-i18n` from 1.7.0. `GlossaryTool` also reads
|
|
291
345
|
`record.glossary.instructions`, `.definition` (1.7.0) and `record.glossary.tool`
|
|
292
|
-
(2.3.0); `
|
|
346
|
+
(2.3.0); `PartnerPanel` reads `partner.info.about`, `.contact`, `.logo`,
|
|
347
|
+
`.addresses`, `.phone`, `.fax`, `partner.nav.homepage`,
|
|
348
|
+
`partner.item.objectsInSite` and `partner.action.readMore`, `.viewObjects` (4.2.0); `DynastyPopout` reads `record.dynasty.heading` (2.3.0) and
|
|
293
349
|
`sheet.field.alsoKnownAs`, `.area`, `.history`. `SourceCredit` reads
|
|
294
350
|
`record.source.label` (2.5.0); the footer attribution (`SiteShell`) reads
|
|
295
351
|
`record.source.rightsHolder` and `.termsOfUse` (2.5.0). `PictureGallery`/
|
|
296
352
|
`PictureNarrative` default to `exhibition.theme.seeItemEntry`, `.recordNotInSite`,
|
|
297
353
|
`.additionalContent`, `.addRelatedWorks`, `.hideRelatedWorks` and
|
|
298
|
-
`exhibition.related.items`, `.reciprocal
|
|
299
|
-
`@museumwnf/viewer-i18n`
|
|
300
|
-
|
|
301
|
-
Every other text is a
|
|
354
|
+
`exhibition.related.items`, `.reciprocal`, which only the `exhibition` and
|
|
355
|
+
`standalone` bundles of `@museumwnf/viewer-i18n` carry — a family default
|
|
356
|
+
in a generic entry, which ends when the two move under `/dxa` (see
|
|
357
|
+
[Entry points and layers](#entry-points-and-layers)). Every other text is a
|
|
358
|
+
prop.
|
|
359
|
+
|
|
360
|
+
`FeaturedPartners`, `SiblingGalleries`, `PopupLogo`, `PictureGallery` and
|
|
361
|
+
`PictureNarrative` are used only by the DXA family, and move under `/dxa`
|
|
362
|
+
in milestone M10; their exports here stay as aliases until the websites have
|
|
363
|
+
moved.
|
|
302
364
|
|
|
303
365
|
## Content classes
|
|
304
366
|
|
|
@@ -319,9 +381,11 @@ Building blocks copied from the legacy sites' own `site.css` files, available as
|
|
|
319
381
|
|
|
320
382
|
## Composed views
|
|
321
383
|
|
|
322
|
-
|
|
384
|
+
Whole pages, made of the content components on viewer-core's
|
|
323
385
|
composables and driven by a declaration the website writes instead of a
|
|
324
|
-
page. They are
|
|
386
|
+
page. They are the broad page structures every kind of website shares;
|
|
387
|
+
`RecordSheetView`, used only by the DXA family, moves under `/dxa` with a
|
|
388
|
+
Detail name in milestone M10. They are exported from `@museumwnf/viewer-layout/views` — and only from
|
|
325
389
|
there: they read the records and the engine from `@museumwnf/viewer-core`
|
|
326
390
|
itself, whose entry point carries `.vue` files, and a website's test runner
|
|
327
391
|
that loads this package natively would fail on the first one if the package
|
|
@@ -364,10 +428,10 @@ export default {
|
|
|
364
428
|
| `HomeView` | `config.home` or the same as props: `title`, `intro` (Markdown), `cards: [{ title, description, action, to \| href }]`, `featured: { entity, heading, action, route, eyebrow, meta, seed }` — the pick is `useFeaturedRecord` | `before`, default, `after` |
|
|
365
429
|
| `CatalogueResultsView` | `spec`: `entity`, `keys`, `facets` (viewer-core's facet spec), `facetScope: 'all' \| 'matching'`, `controls: [{ key, type: 'select' \| 'year' \| 'query' \| 'checkbox', label, placeholder, anyLabel, hideEmpty }]`, `filterMode: 'apply' \| 'immediate'`, `scope(record, filters)`, `match(record, filters)`, `narrow(list, filters, helpers)` (a rule over the whole list — a keyword index, say), `dates: { mode, begin, end }`, `sort`, `pageSize`, `variant: 'list' \| 'grid'`, `record(record, helpers)`, `recordRoute`, `summary(context)`, `title`, `filterTitle`, `empty`, `actionLabel`, `pagination` | `before`, `filters`, `actions`, `aside`, `empty`, `after` — each given `{ filters, active, apply, reset, goToPage, matching, pageInfo, options }`, enough to compose the panel in the aside or a second pagination |
|
|
366
430
|
| `RecordView` | `spec` and `id`: `entity`, `translations`, `attribution`, `fields` (viewer-core's `sheetRows` spec, or a function of the context), `sections`, `layout`, `shortDescription`, `media(record, ctx)`, `mediaVariant`, `credits`, `workingNumber`, `citation: { project, permalink: true \| false \| string, heading } \| false` (the permalink is `sourceUrl(currentRoute)` — null, so no address, until the website declares `site.origin` — unless the spec disables it with `false` or overrides it with a string), `related: { variant, heading, record, route } \| false`, `back: { label, to \| href }`, `title(ctx)` | `header`, `before-sheet`, `after-sheet`, `aside`, `source` (under the citation; default `SourceCredit`), `related`, `after`, and one named after every `custom` or `link` row — each given `{ record, text, language, languages, select, dir, glossary, ready, attribution, t, tr }`; `related` also `records` (the rows) and `outside` (the related records the package does not carry) |
|
|
367
|
-
| `RecordSheetView` | Every `RecordView` prop (`spec`, `id`, `entity`) plus `dataGetter(id) => record \| null \| undefined` — a website's own language-subset record lookup (an exhibition's per-build `itemById.get`); omitted, every `id` `RecordView` itself finds is treated as present (the gallery shape); supplied and it reports `id` missing, `NotFoundView` renders before `RecordView` ever mounts (the exhibition shape's per-language-build 404), and it also narrows the related block's `records`/outside-reference split the same way. The DXA gallery/exhibition item sheet's own blocks, on top of `spec`: `sourceDatabase: { label?, chipClass(record, ctx), addToCollection: { label? } \| false } \| false` (the source-database line + `backward_compatibility` code + "add to my collection" link — `chipClass` is a site's own project→colour map, the name comes from `useProjects()`), `notice: { show(record, ctx), label } \| false` (the Explore-partner notice), `museum: { route(partnerId, ctx)
|
|
431
|
+
| `RecordSheetView` | Every `RecordView` prop (`spec`, `id`, `entity`) plus `dataGetter(id) => record \| null \| undefined` — a website's own language-subset record lookup (an exhibition's per-build `itemById.get`); omitted, every `id` `RecordView` itself finds is treated as present (the gallery shape); supplied and it reports `id` missing, `NotFoundView` renders before `RecordView` ever mounts (the exhibition shape's per-language-build 404), and it also narrows the related block's `records`/outside-reference split the same way. The DXA gallery/exhibition item sheet's own blocks, on top of `spec`: `sourceDatabase: { label?, chipClass(record, ctx), addToCollection: { label? } \| false } \| false` (the source-database line + `backward_compatibility` code + "add to my collection" link — `chipClass` is a site's own project→colour map, the name comes from `useProjects()`), `notice: { show(record, ctx), label } \| false` (the Explore-partner notice), `museum: { route(partnerId, ctx) } \| false` (the holding-museum row: the item's holder text, then the partner as `PartnerPanel`'s `summary` — "About {name}, {city}, {country}" — linked through `route`; `route` returning null keeps the name without a link, for a hidden partner; `false` keeps the holder text alone; decision D3), and on `spec.related`: `title`, `description` (entries, above the block), `notInPackageLabel`, `outsideChip(ref, ctx)` (an outside reference's chip — `TODO(#1727)`, no `project_id` on a stub yet), `artisticIntroductionLabel` (with `useProjects().links(record.project_id).artisticIntroductionUrl`), `databaseLabel` (ditto, `.relatedDatabaseUrl`), `overallDatabase: { label, linkLabel } \| false` (`mwnfLinks.overallDatabase`), `onDisplayIn: { linkPendingLabel } \| false` (`record.gallery_references`, by `kind`), `download: false` (default on, `record.action.download`/`.downloadPdf`, prints), `glossary: false` (default on, `GlossaryTool`), `dynasties(record, language, ctx) => { records, tr } \| null` (`DynastyList`), `media: false` (default on, `record.media`, a `SheetSection`), `timeline(record, ctx) => TimelineInfo \| null` (`TimelineLookup` — see `docs/slot-catalogue.md`) | Every `RecordView` slot, forwarded straight through by name, unmodified, **except** `before-sheet`/`museum`/`related`: each always has this view's own default content (above), which a website's own slot still replaces entirely — "a slot fills, the default content renders otherwise" |
|
|
368
432
|
| `EssayView` | `spec` and `id`: `tree` (a `useCollectionTree` result, or `{ purpose \| rootId, childType?, entity?, order? }` / `{ themes: true \| 'themes', childType? }` for the view to build one), `entity` (the tree's items — also the tree's own translations entity when `tree` carries none of its own, a pre-built tree or a declarative form with no `entity`/`themes`; falls back to `'collections'`), `route` (a node's own page: a route name or `(node, ctx) => to \| href`), `heading(ctx)`, `placeholder` (a regex a synthesized title matches, falling back to the English title, then the internal name), `quote` / `body` (a field of the node's translation, a dotted path into it such as `'extra.intro_text'`, or a function `(ctx) => Markdown`; default `'quote'`/`'description'`, `false` to drop), `glossary`, `items: { of(node) => ids, caption(item, node, ctx) => override, meta(item, ctx) => [string] (the grid's caption lines), badge(item, ctx) => string, route }`, `panel: { variants(item, ctx) => [{ id, image, alt, caption: { title, justification, fields: [{ label (entry name), value }] } }], fields(item, node, ctx) => [{ label, value }] (the fallback when a variant carries no fields of its own) } \| false`, `navigation: 'tree' \| 'siblings' \| false` (`tree` crosses a branch boundary, `siblings` stays inside the parent), `breadcrumb`, `tabs: true \| 'siblings' \| 'children'` (the strip: `true`/`'siblings'` — the node's own siblings, the default; `'children'` — the node's own children, e.g. a theme's chapters), `about(node) => boolean \| { panel?, navigation? }` (essay only; a plain boolean drops both the picture panel and the navigation, an object keeps the named piece instead), `aboutKeeps: ['panel' \| 'navigation']` (the spec-wide equivalent, when every about page in this spec keeps the same piece), `numbering: 'roman' \| 'decimal' \| false` (counts a node among its true siblings — for a themes-package tree, whose `root` is `null`, that's every node whose own `tree.parents(id)` is also empty, so a themes tree numbers its top-level themes I, II, III); `previous`, `next`, `backTo`, `inThisTheme`, `seeAll` (entry names, defaulting to `exhibition.theme.previous`/`.next`/`.inThisTheme`/`.seeAllInTheme` and `record.action.backToResults`) | `header`, `before-body`, `after-body`, `panel`, `thumbnails`, `aside`, `justifications`, `navigation`, `after` (default `SourceCredit` — nothing until the website declares `site.origin`) — each given `{ node, text, language, tree, items, selected, select, selectedVariant, selectVariant, breadcrumb, previous, next, t, tr }` |
|
|
369
433
|
| `LinkListView` | `spec`: `title` (entry), `groups: [{ heading (entry), links: [{ label, href \| to, note? }] }] \| (ctx) => groups` (`label`/`note` are Markdown, rendered inline through `mdInline`), `back: { label, to \| href } \| false`, `empty` (entry) | `before`, `group` (given `{ group }`; the default renders the heading and its links — replace it for a citation list that is not link-shaped), `after` |
|
|
370
|
-
| `PartnerListView` | `spec`: `entity` (default `'partners'`), `scope(partner, ctx)` (a site's own axis — museum/institution, a curated project — filtered before grouping), `group: { tier: 'level' \| false, order: 'country' \| 'name' }` (over viewer-core's `groupByCountry`; `'name'`: one flat, alphabetical group, no country carries this today), `orderToggle` (an A-Z/Z-A control, mirrored in the query as `order`; every tier is always sorted by name, the toggle reverses the country order or the one flat list), `nested` (an associated partner rendered under its own parent through `partnerHierarchy`, instead of the flat tier column; one whose parent is missing or in another group stays flat), `label(countryId, ctx)` (a group's own country label, required when `group.order` is `'country'`), `record(partner, ctx) => { name, city, logo, count, route }` (the row), `route` (a route name or `(partner, ctx) => to \| href`, read by the default row only), `variant: 'accordion' \| 'open'`, `count` (the "Partners found: N" line), `associatedLabel`/`foundLabel`/`objectsLabel`/`sortAscendingLabel`/`sortDescendingLabel`/`empty`/`title` (entry names, overriding the shared `partner.*` defaults) | `before`, `group-heading` (given `{ group }`; the default renders `group.label`), `row` (given `{ group, partner, row }`, once per partner — main, associated and, when nested, a child row too), `after` — every slot also given `{ t, locale, groups, orderDir, toggleOrder }` |
|
|
434
|
+
| `PartnerListView` | `spec`: `entity` (default `'partners'`), `scope(partner, ctx)` (a site's own axis — museum/institution, a curated project — filtered before grouping), `group: { tier: 'level' \| false, order: 'country' \| 'name' }` (over viewer-core's `groupByCountry`; `'name'`: one flat, alphabetical group, no country carries this today), `orderToggle` (an A-Z/Z-A control, mirrored in the query as `order`; every tier is always sorted by name, the toggle reverses the country order or the one flat list), `nested` (an associated partner rendered under its own parent through `partnerHierarchy`, instead of the flat tier column; one whose parent is missing or in another group stays flat), `label(countryId, ctx)` (a group's own country label, required when `group.order` is `'country'`), `record(partner, ctx) => { name, city, logo, count, route }` (the row, when a site builds it itself), `route` (a route name or `(partner, ctx) => to \| href`, read by the default row only), `objectsRoute(partner, ctx)` (the line's View objects link), `actions: true` (the line's Read more · View objects links), `emptyLabel` (the line for a partner holding nothing), `variant: 'accordion' \| 'open'`, `count` (the "Partners found: N" line), `associatedLabel`/`foundLabel`/`objectsLabel`/`sortAscendingLabel`/`sortDescendingLabel`/`empty`/`title` (entry names, overriding the shared `partner.*` defaults) | `before`, `group-heading` (given `{ group }`; the default renders `group.label`), `row` (given `{ group, partner, row, view }`, once per partner — main, associated and, when nested, a child row too; the default is `PartnerPanel`'s `line` over `view`, viewer-core's `partnerView()`), `after` — every slot also given `{ t, locale, groups, orderDir, toggleOrder }` |
|
|
371
435
|
| `TextPageView` | `spec`: `heading?` (entry), `body` (entry \| (ctx) => Markdown, `ctx` the same `{ t, tr, language }` shape `EssayView`'s spec functions read), `back: { label, to \| href } \| true \| false` | none |
|
|
372
436
|
| `SearchFormView` | `spec`: `mode: 'rows' \| 'facets' \| 'radio'`, `entity` (records an entity-backed facet or `dates: 'buckets'` read), `rows` (`'rows'`: keyword-row count, default 3), `fields: [{ key, label }]` (`'rows'`: the field select), `operators: [{ key, label }]` (`'rows'`: the AND/OR select, default AND/OR), `dates: { presets } \| 'buckets' \| false` (a from/to year select — `centuryPresets`'s asymmetric boundaries, or one `yearBuckets` list used for both ends), `language: entity \| false` (the search-language select, over `useSearchLanguage`), `extras: [{ key, type: 'checkbox', label }]`, `facets: [{ key, label, type: 'select' \| 'year', options: [{ value, label }] }]` (`'facets'`/`'radio'`: options given directly, or derived from `entity`'s own records when left out; `type: 'year'` is a plain number input), `target` (the results route this form writes into), `submitLabel`, `showAllLabel`, `howTo: routeName \| false` (a link to the search-syntax essay) | `intro`, `before`, `extras`, `actions` — each given `{ mode, submit, showAll }` |
|
|
373
437
|
| `TimelineResultsView` | `spec`: `scope: 'country' \| 'local' \| 'collection'` (viewer-core's `useTimelineEvents` axis), `countryLabel(id)`, `countryIdForCode(code)` (DXA's legacy 2-letter code), `collections(ctx) => [{ value, label }]` (Sharing History's exhibition/PC picker — `'pc'` is the Permanent Collection sentinel), `tr(id)` (an event's translation, the site's own), `timelinesEntity`/`eventsEntity` (data package file names), `keys` (default: every control's key), `controls: [{ key: 'country' \| 'collection' \| 'begin' \| 'end', label, placeholder, anyLabel, hideEmpty, options? }]` (`options` on `'begin'`/`'end'`: an array `[{ value, label }]` or function `(ctx) => [...]` for bucketed year selects; without `options`, a free-year number input), `pageSize`, `entrance: false \| true` (renders the form alone, with validation, navigating to `route` on submit), `route` (the entrance's own target route), `event(event, ctx) => { date, caption, description, media, actions }` (the row, see `TimelineEventList`), `gallery: { route, items(ctx) => count \| array \| boolean, label } \| false` (the "See gallery" cross-link — an item's own shape stays the site's), `summary(ctx)`, `errorSelect`, `errorPeriod` (the entrance's own validation entries), `title`, `filterTitle`, `applyLabel`, `resetLabel`, `submitLabel`, `empty`, `pagination` | `summary`, `cross-link`, `event` (replaces the whole events list), `before`, `after` — each given `{ filters, active, apply, reset, goToPage, events, pageInfo, countries, collections, gallery, t, tr }` |
|
|
@@ -425,11 +489,27 @@ except where noted:
|
|
|
425
489
|
|
|
426
490
|
## DXA family pages
|
|
427
491
|
|
|
428
|
-
`@museumwnf/viewer-layout/dxa`
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
the
|
|
432
|
-
|
|
492
|
+
`@museumwnf/viewer-layout/dxa` is the DXA family layer: the only place
|
|
493
|
+
where whole pages are shared. The galleries are one site with different
|
|
494
|
+
data, and so are the exhibitions — the legacy served each family from one
|
|
495
|
+
application — so a page that is the same on every site of a family lives
|
|
496
|
+
here once, beside the data composables of `@museumwnf/viewer-core/dxa`.
|
|
497
|
+
|
|
498
|
+
What may go here: a page, a component or a style that only the gallery or
|
|
499
|
+
the exhibition family uses, and that is the same on every site of that
|
|
500
|
+
family. A difference between two sites of a family is a config value or a
|
|
501
|
+
token, not a second copy of the page. Nothing outside `/dxa` imports from
|
|
502
|
+
it, and a website can still replace any family page with its own component
|
|
503
|
+
on the same route name. Texts stay in `@museumwnf/viewer-i18n`'s `gallery`
|
|
504
|
+
and `exhibition` sections.
|
|
505
|
+
|
|
506
|
+
It ships each family's pages plus `standardRoutes(family, config)`, the
|
|
507
|
+
RouteRecord factory a site spreads into `extraViews`. One page serves both
|
|
508
|
+
families: `PartnerDetail`, the partner page (`PartnerPanel`'s `full`
|
|
509
|
+
variant), fed by each family's own half — `galleryPartnerDetail` /
|
|
510
|
+
`exhibitionPartnerDetail`, which `standardRoutes` passes as its `family`
|
|
511
|
+
prop; `GalleryPartnerProfile`/`ExhibitionPartnerProfile` are the same page
|
|
512
|
+
under their old names.
|
|
433
513
|
|
|
434
514
|
```js
|
|
435
515
|
import { standardRoutes } from '@museumwnf/viewer-layout/dxa'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { v as e } from "./TimelineEventList-D5Hot788.js";
|
|
2
|
+
import { createBlock as t, createElementBlock as n, createTextVNode as r, openBlock as i, toDisplayString as a, withCtx as o } from "vue";
|
|
3
|
+
import { useRouter as s } from "vue-router";
|
|
4
|
+
//#region src/content/BackLink.vue
|
|
5
|
+
var c = { class: "mwnf-back-link" }, l = {
|
|
6
|
+
__name: "BackLink",
|
|
7
|
+
props: {
|
|
8
|
+
label: {
|
|
9
|
+
type: String,
|
|
10
|
+
default: "core.action.back"
|
|
11
|
+
},
|
|
12
|
+
to: {
|
|
13
|
+
type: [String, Object],
|
|
14
|
+
default: null
|
|
15
|
+
},
|
|
16
|
+
href: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: ""
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
setup(l) {
|
|
22
|
+
let u = s();
|
|
23
|
+
function d() {
|
|
24
|
+
return window.history.length > 1;
|
|
25
|
+
}
|
|
26
|
+
function f(e) {
|
|
27
|
+
d() && (e.preventDefault(), u.back());
|
|
28
|
+
}
|
|
29
|
+
return (s, u) => (i(), n("div", c, [!d() && (l.to || l.href) ? (i(), t(e, {
|
|
30
|
+
key: 0,
|
|
31
|
+
to: l.to,
|
|
32
|
+
href: l.href,
|
|
33
|
+
class: "mwnf-back-link__button"
|
|
34
|
+
}, {
|
|
35
|
+
default: o(() => [r(" ↩ " + a(s.$t(l.label)), 1)]),
|
|
36
|
+
_: 1
|
|
37
|
+
}, 8, ["to", "href"])) : (i(), n("button", {
|
|
38
|
+
key: 1,
|
|
39
|
+
class: "mwnf-back-link__button",
|
|
40
|
+
onClick: f
|
|
41
|
+
}, " ↩ " + a(s.$t(l.label)), 1))]));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { l as t };
|