forked from cms/tibi-svelte-starter
✨ feat: enhance medialib image handling and add asset URL resolution
- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base. - Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties. - Enhanced image loading behavior with improved width measurement and focal point handling. - Added placeholder image handling and improved accessibility with alt text. - Introduced new test script for auditing broken links in skill documentation. - Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews. - Improved global setup and teardown logging for clarity on seeded content management.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: admin-ui-config
|
||||
description: Configure the admin UI for collections — meta labels, preview/viewHint, field widgets, inputProps, sidebar layout, choices, foreign references, and image handling. Use when setting up or customizing collection admin views.
|
||||
description: Configure the admin UI for collections and project-level Nova behavior — meta labels, preview/viewHint, sidebar layout, collectionGroups, i18n, field widgets, foreign references, and image handling. Use when setting up or customizing admin views.
|
||||
---
|
||||
|
||||
# admin-ui-config
|
||||
@@ -24,6 +24,46 @@ Treat this skill as Nova-first. Use current Nova concepts such as `preview`, `si
|
||||
|
||||
---
|
||||
|
||||
## Project-level admin contracts
|
||||
|
||||
Not every important Nova contract lives in a collection YAML file. Some of the most important admin behaviors are configured at project level in `api/config.yml` under `meta:`.
|
||||
|
||||
Current starter example:
|
||||
|
||||
```yaml
|
||||
meta:
|
||||
imageUrl:
|
||||
eval: "$projectBase + '_/assets/img/admin-pic.svg'"
|
||||
i18n:
|
||||
defaultLanguage: de
|
||||
languages:
|
||||
- code: de
|
||||
label: Deutsch
|
||||
- code: en
|
||||
label: English
|
||||
collectionGroups:
|
||||
- name: content
|
||||
label: { de: "Inhalte", en: "Content" }
|
||||
icon: article
|
||||
- name: media
|
||||
label: { de: "Medien", en: "Media" }
|
||||
icon: image_multiple
|
||||
```
|
||||
|
||||
Treat these as part of the admin design, not as optional polish:
|
||||
|
||||
- `meta.imageUrl` — project card/preview imagery in the admin
|
||||
- `meta.i18n` — project-wide language model for field-level and entry-level translation workflows
|
||||
- `meta.collectionGroups` — ordered collection groups for the sidebar
|
||||
|
||||
Important rule:
|
||||
|
||||
- collection-level `meta.group` must reference one of the project-level `meta.collectionGroups[].name` values if the collection should appear inside an explicit group
|
||||
|
||||
If project-level `meta.i18n` is missing or inconsistent, even well-modeled collections can become confusing in Nova.
|
||||
|
||||
---
|
||||
|
||||
## Collection meta configuration
|
||||
|
||||
The `meta` key in a collection YAML controls how the collection appears in the admin sidebar and collection/list UI.
|
||||
@@ -84,6 +124,42 @@ meta:
|
||||
- `preview.select` can reduce lookup work for preview table columns.
|
||||
- `meta.subNavigation` defines filtered entry tabs in the sidebar.
|
||||
|
||||
### Sub-navigation tabs
|
||||
|
||||
Use `meta.subNavigation` when one collection needs multiple curated views in the admin without splitting into multiple collections.
|
||||
|
||||
```yaml
|
||||
meta:
|
||||
subNavigation:
|
||||
- name: pages
|
||||
label: { de: "Seiten", en: "Pages" }
|
||||
muiIcon: article
|
||||
filter:
|
||||
type: page
|
||||
defaultSort:
|
||||
field: insertTime
|
||||
order: DESC
|
||||
setDefault:
|
||||
field: type
|
||||
value: page
|
||||
- name: news
|
||||
label: { de: "News", en: "News" }
|
||||
muiIcon: feed
|
||||
filter:
|
||||
type: news
|
||||
setDefault:
|
||||
field: type
|
||||
value: news
|
||||
```
|
||||
|
||||
Use sub-navigation when:
|
||||
|
||||
- one collection has several stable editorial slices
|
||||
- the underlying schema is still shared enough to stay one collection
|
||||
- authors benefit from filtered entry views and sensible defaults
|
||||
|
||||
Do not use sub-navigation to hide a bad collection model. If the workflows truly diverge, split the collection instead.
|
||||
|
||||
---
|
||||
|
||||
## Field configuration
|
||||
@@ -247,6 +323,8 @@ Use `foreign.id: id` for the outward FK field identity. Only Mongo-style filters
|
||||
imageEditor: true # Enable crop/rotate editor
|
||||
```
|
||||
|
||||
This field config controls the editor widget, not the filesystem target. Configure file storage once at collection level via top-level `uploadPath` (for this starter typically `../media/<collection>`), not on the individual file field.
|
||||
|
||||
---
|
||||
|
||||
## Layout: position, sections, sidebar
|
||||
@@ -466,13 +544,9 @@ import BlockRenderer from "./blocks/BlockRenderer.svelte"
|
||||
// Creates a block definition that renders the same Svelte component
|
||||
// used in the public frontend. The block is mounted inside Shadow DOM
|
||||
// for style isolation.
|
||||
function createContentBlockDefinition(presentation: {
|
||||
label: string
|
||||
icon: string
|
||||
color: string
|
||||
}) {
|
||||
function createContentBlockDefinition(presentation: { label: string; icon: string; color: string }) {
|
||||
return {
|
||||
css: [previewCssUrl], // CSS files to inject into Shadow DOM
|
||||
css: [previewCssUrl], // CSS files to inject into Shadow DOM
|
||||
label: presentation.label,
|
||||
icon: presentation.icon,
|
||||
color: presentation.color,
|
||||
@@ -517,6 +591,7 @@ export { blockRegistry }
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- Each registry entry wraps the Svelte `BlockRenderer` to render the block in the admin preview.
|
||||
- The `row` object is the block data (same shape as `ContentBlockEntry`).
|
||||
- Preview data may contain hydrated `_lookup.<fieldPath>` foreign key data and absolute file URLs — do not prepend `apiBase` or attempt re-fetching.
|
||||
@@ -665,7 +740,7 @@ indexes:
|
||||
- name: price_sort
|
||||
key: [price]
|
||||
- name: category_active
|
||||
key: [category, -active] # -prefix for descending
|
||||
key: [category, -active] # -prefix for descending
|
||||
- name: slug_unique
|
||||
key: [slug]
|
||||
unique: true
|
||||
@@ -682,9 +757,26 @@ search:
|
||||
|
||||
See `tibi-server/docs/04-collections.md` (sections on indexes and search config) for full reference.
|
||||
|
||||
## Checklist-facing verification
|
||||
|
||||
For a real project, do not stop after writing the YAML. Validate the authoring contract explicitly.
|
||||
|
||||
Minimum review points:
|
||||
|
||||
1. project-level `meta.i18n` and `meta.collectionGroups` are coherent
|
||||
2. each collection has a readable `meta.preview`
|
||||
3. list views show meaningful columns instead of raw IDs or empty rows
|
||||
4. foreign references render with readable previews
|
||||
5. sidebars and `containerProps.layout` produce usable forms
|
||||
6. pagebuilder collections expose both a working chooser and working preview path
|
||||
|
||||
Committed admin Playwright coverage is preferred for stable contracts that should not regress.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
- **`meta.label` supports both strings and i18n objects** — Use i18n objects only when the collection or field label must be localized.
|
||||
- **Project-level admin config is easy to forget** — `collectionGroups` and project-level `meta.i18n` live in `api/config.yml`, not in individual collection files.
|
||||
- **`meta.group` without a matching project group** — The collection still exists, but the sidebar grouping model becomes inconsistent.
|
||||
- **`choices.id` must match stored value** — The `id` in choices is what gets saved to the database.
|
||||
- **`inputProps` depends on widget** — Not all props work with all widgets. Check tibi-admin-nova source if unsure.
|
||||
- **`position: sidebar` without group** — Fields go to an ungrouped area. Use `position: "sidebar:GroupName"` for grouping.
|
||||
|
||||
Reference in New Issue
Block a user