Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
89f6c57
wip(site-chrome): portal schema and content API serve the header sear…
rubenvdlinde Oct 5, 2026
e2eec02
chore: untrack two local dependency links committed by mistake
rubenvdlinde Oct 5, 2026
7e33da5
wip(site-chrome): designed header (search, account button, person chi…
rubenvdlinde Oct 5, 2026
7e89d90
wip(site-chrome): node tests for the header tools, footer, sign-in ca…
rubenvdlinde Oct 5, 2026
71da6f8
wip(site-chrome): one signed-out block, the person helper in the lazy…
rubenvdlinde Oct 5, 2026
3a42b1c
wip(site-chrome): designed footer columns, fonts, openspec change
rubenvdlinde Oct 5, 2026
4fe43f3
wip(resident-menu): per-record rows as items with a subtitle, counts …
rubenvdlinde Oct 5, 2026
aab2925
wip(resident-menu): tests, openspec change, card label projected
rubenvdlinde Oct 5, 2026
a80f8e6
fix(site-chrome): no inline ifs in the shell projection
rubenvdlinde Oct 5, 2026
17d668d
fix(resident-menu): no inline ifs in the shell projection
rubenvdlinde Oct 5, 2026
e71adf6
Merge remote-tracking branch 'origin/feat/site-chrome-follows-the-des…
rubenvdlinde Oct 5, 2026
727b7c9
feat(site-chrome): a declared header search shows without enabled, wi…
rubenvdlinde Oct 5, 2026
c1951e7
Merge site-chrome-follows-the-design into resident-menu-badges-and-cards
rubenvdlinde Oct 5, 2026
663dfcf
fix(site-chrome): the brand column keeps the design's spacing
rubenvdlinde Oct 5, 2026
0d1318c
fix(resident-menu): carry the brand column spacing
rubenvdlinde Oct 5, 2026
cce40cc
test(site-chrome): import order
rubenvdlinde Oct 5, 2026
6450631
refactor(site-chrome): the sign-in text in its own class, logo varian…
rubenvdlinde Oct 5, 2026
bac2f89
Merge remote-tracking branch 'origin/feat/site-chrome-follows-the-des…
rubenvdlinde Oct 5, 2026
533cc3f
Merge site-chrome-follows-the-design; the card label projected by its…
rubenvdlinde Oct 5, 2026
1ce1f1f
fix(site-chrome): on a phone the motif runs under the masthead while …
rubenvdlinde Oct 5, 2026
8994b1c
fix: carry the phone motif rule
rubenvdlinde Oct 5, 2026
f35170e
fix(site-chrome): controller test knows the logo variants; docblock l…
rubenvdlinde Oct 5, 2026
8f832d8
fix(site-chrome): the sign-in page fits a phone
rubenvdlinde Oct 5, 2026
8df8962
fix: carry the phone fit of the sign-in page
rubenvdlinde Oct 5, 2026
524b939
fix(site-chrome): the breadcrumb starts under the motif
rubenvdlinde Oct 5, 2026
7f9a86d
fix: carry the breadcrumb spacing
rubenvdlinde Oct 5, 2026
f7cafde
docs(site-chrome): live check done
rubenvdlinde Oct 5, 2026
c4f3f89
Merge remote-tracking branch 'origin/feat/site-chrome-follows-the-des…
rubenvdlinde Oct 5, 2026
0b9c748
docs(resident-menu): live check done
rubenvdlinde Oct 5, 2026
4e526db
Merge origin/development into feat/site-chrome-follows-the-design; re…
rubenvdlinde Oct 5, 2026
4df314c
Merge site-chrome-follows-the-design (with development) into resident…
rubenvdlinde Oct 5, 2026
97940aa
fix(site-chrome): the new button links ship their stylesheet; the por…
rubenvdlinde Oct 5, 2026
c1c07af
Merge site-chrome-follows-the-design into resident-menu-badges-and-ca…
rubenvdlinde Oct 5, 2026
c70218f
Merge origin/development into feat/site-chrome-follows-the-design
rubenvdlinde Oct 5, 2026
0c0b857
Merge site-chrome-follows-the-design (development with the badge key)…
rubenvdlinde Oct 5, 2026
59b712b
Merge origin/development (with #1202 squashed) into resident-menu-bad…
rubenvdlinde Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions css/site-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -1021,3 +1021,91 @@
grid-template-columns: minmax(0, 1fr);
}
}

/*
* THE RESIDENT MENU AS THE SCHOOL DESIGNS DRAW IT
* (resident-menu-badges-and-cards, G-05, G-06).
*
* Group names small and spaced in capitals, entries in the link colour, the
* page on screen on the accent's light wash in bold ink, counts in the
* accent. Three classes, so these beat the component's scoped rules (two
* classes and an attribute), which load after this sheet.
*/
.pq-site .pq-account .pq-resident-menu__title {
color: var(--nldesign-color-text-muted, var(--utrecht-document-color));
font-size: 0.8125rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}

.pq-site .pq-account .pq-resident-menu__link {
padding-block: 12px;
border-inline-start: 0;
border-radius: var(--nldesign-website-border-radius, 0);
color: var(--nldesign-color-link, var(--utrecht-link-color));
font-size: 1.0625rem;
font-weight: 600;
}

.pq-site .pq-account .pq-resident-menu__link--current {
background-color: var(
--thematiq-accent-light-color,
var(--nldesign-color-primary-light)
);
color: var(--nldesign-color-text, var(--utrecht-document-color));
font-weight: 700;
box-shadow: inset 4px 0 0
var(--thematiq-accent-color, var(--nldesign-color-primary));
}

.pq-site .pq-account .pq-resident-menu__subline {
display: block;
color: var(--nldesign-color-text, var(--utrecht-document-color));
font-size: 0.875rem;
font-weight: 400;
}

.pq-site .pq-account .pq-resident-menu__badge,
.pq-site .pq-account .pq-resident-menu__toggle-badge {
background-color: var(
--thematiq-badge-background-color,
var(--utrecht-document-color)
);
color: var(--thematiq-badge-color, var(--utrecht-document-background-color));
font-weight: 700;
}

.pq-site .pq-account .pq-resident-menu__toggle-badge {
margin-inline-start: auto;
padding-inline: 8px;
border-radius: 999px;
font-size: 0.8125rem;
}

.pq-site .pq-account .pq-resident-menu__card {
margin-block-end: 24px;
padding: 16px;
border-radius: var(--nldesign-website-border-radius, 4px);
background-color: var(
--nldesign-color-background-hover,
var(--tilburg-color-gray-100)
);
}

.pq-site .pq-account .pq-resident-menu__card p {
margin: 0;
}

.pq-site .pq-account .pq-resident-menu__card-label {
color: var(--nldesign-color-text-muted, var(--utrecht-document-color));
font-size: 0.8125rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}

.pq-site .pq-account .pq-resident-menu__card-title {
font-size: 1.0625rem;
font-weight: 700;
}
6 changes: 5 additions & 1 deletion l10n/en.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion l10n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2223,7 +2223,11 @@
"totalField": "totalField",
"unit": "unit",
"valueField": "valueField",
"valuesField": "valuesField"
"valuesField": "valuesField",
"Menu of the own area": "Menu of the own area",
"How the menu beside the visitor's own pages opens.": "How the menu beside the visitor's own pages opens.",
"Card label": "Card label",
"The line above the organisation's name at the top of the menu, shown while the visitor acts for an organisation, such as U regelt het voor. Empty shows no card.": "The line above the organisation's name at the top of the menu, shown while the visitor acts for an organisation, such as U regelt het voor. Empty shows no card."
},
"plurals": "",
"pluralForm": "nplurals=2; plural=(n != 1);"
Expand Down
6 changes: 5 additions & 1 deletion l10n/nl.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion l10n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -2288,7 +2288,11 @@
"totalField": "veld met het totaal",
"unit": "eenheid",
"valueField": "veld met de waarde",
"valuesField": "veld met de waarden"
"valuesField": "veld met de waarden",
"Menu of the own area": "Menu van de eigen omgeving",
"How the menu beside the visitor's own pages opens.": "Hoe het menu naast de eigen pagina's van de bezoeker begint.",
"Card label": "Regel boven de naam",
"The line above the organisation's name at the top of the menu, shown while the visitor acts for an organisation, such as U regelt het voor. Empty shows no card.": "De regel boven de naam van de organisatie bovenaan het menu, getoond als de bezoeker voor een organisatie handelt, bijvoorbeeld U regelt het voor. Leeg toont geen kaart."
},
"plurals": "",
"pluralForm": "nplurals=2; plural=(n != 1);"
Expand Down
28 changes: 27 additions & 1 deletion lib/Service/Cms/PortalShell.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ public function __construct(
*
* @param array<string, mixed> $portal The portal record.
*
* @return array<string, mixed> `authentication`, `headerVariant`, `headerSearch`, `accountLabel`, `footer` and `regions`.
* @return array<string, mixed> `authentication`, `headerVariant`, `headerSearch`, `accountLabel`, `residentMenu`, `footer` and `regions`.
*
* @spec openspec/changes/resident-menu-badges-and-cards/specs/site-resident-menu/spec.md#requirement-the-menu-may-open-with-whom-the-resident-acts-for
*
* @spec openspec/changes/portal-theme-blocks-and-contributed-pages/specs/portaliq-cms/spec.md#requirement-the-header-must-be-a-block-whose-shape-the-portal-chooses-req-ptb-004
* @spec openspec/changes/site-chrome-follows-the-design/specs/site-chrome/spec.md#requirement-the-header-must-carry-the-search-box-and-one-way-to-the-own-area
Expand All @@ -68,11 +70,35 @@ public function project(array $portal): array {
'headerVariant' => $this->headerVariant(portal: $portal),
'headerSearch' => $this->headerSearch(portal: $portal),
'accountLabel' => $this->text(value: ($portal['accountLabel'] ?? '')),
'residentMenu' => $this->residentMenu(portal: $portal),
'footer' => $this->footer(portal: $portal),
'regions' => $this->publicRegions(portal: $portal),
];
}//end project()

/**
* The resident menu's card label, when the portal names one.
*
* @param array<string, mixed> $portal The portal record.
*
* @return array<string, string> `{cardLabel?}`.
*
* @spec openspec/changes/resident-menu-badges-and-cards/specs/site-resident-menu/spec.md#requirement-the-menu-may-open-with-whom-the-resident-acts-for
*/
private function residentMenu(array $portal): array {
$menu = $portal['residentMenu'] ?? [];
$label = '';
if (is_array($menu) === true) {
$label = $this->text(value: ($menu['cardLabel'] ?? ''));
}

if ($label === '') {
return [];
}

return ['cardLabel' => $label];
}//end residentMenu()

/**
* The search box in the header: whether it shows (a declared box shows
* unless `enabled` is false), its accessible name, its hint and the
Expand Down
19 changes: 16 additions & 3 deletions lib/Settings/portaliq_register.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "Portaliq Register",
"description": "Portaliq — the fleet's shared external portal for clients and suppliers (ADR-046). Holds every portal account, page, session, submission, message, notification, audit entry, traffic record, form and landing-page submission the app reads and writes.",
"version": "0.65.0"
"version": "0.66.0"
},
"x-openregister": {
"type": "application",
Expand All @@ -20,7 +20,7 @@
"slug": "portaliq",
"title": "Portaliq Register",
"description": "Portaliq — the fleet's shared external portal for clients and suppliers (ADR-046). Holds every portal account, page, session, submission, message, notification, audit entry and traffic record the app reads and writes.",
"version": "0.65.0",
"version": "0.66.0",
"schemas": [
"exampleDocument",
"glossaryTerm",
Expand Down Expand Up @@ -2442,7 +2442,7 @@
"portal": {
"slug": "portal",
"icon": "Web",
"version": "0.10.0",
"version": "0.11.0",
"title": "Portal",
"authorization": {
"read": [
Expand Down Expand Up @@ -3009,6 +3009,19 @@
"description": "The text of one button in the header that opens the visitor's own area, where they choose how to sign in. Empty shows a link for each way to sign in instead.",
"example": "Mijn Wilgenboom"
},
"residentMenu": {
"title": "Menu of the own area",
"type": "object",
"description": "How the menu beside the visitor's own pages opens.",
"properties": {
"cardLabel": {
"title": "Card label",
"type": "string",
"description": "The line above the organisation's name at the top of the menu, shown while the visitor acts for an organisation, such as U regelt het voor. Empty shows no card.",
"example": "U regelt het voor"
}
}
},
"locales": {
"title": "Locales",
"type": "array",
Expand Down
29 changes: 29 additions & 0 deletions openspec/changes/resident-menu-badges-and-cards/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Why

The resident menu of the school designs (MijnMenu board, all four schools) shows each child as an
entry with a second line ("Vera, Groep 7 · Meester Daan"), counts beside entries ("Berichten 2",
"Oudergesprekken 1"), the total on the phone button ("Mijn Wilgenboom, 2 nieuw"), the page on
screen on the accent's light wash, and for an employer a card at the top ("U regelt het voor,
Jansen Installatietechniek BV"). The menu could show a count for the inbox only, listed a
per-record page as a group per row, and had no card. Gaps G-05 and G-06 of the school portal plan.
Follows `site-resident-menu` and `site-mijn-omgeving-components` REQ-SMO-006 and REQ-SMO-020.

## What Changes

- A `perRecord` page that declares `group` lists each row as an item of that group, named by the
row's title fields, with its `records.subtitleFields` joined by " · " as a second line. Without
`group` the menu keeps a group per row.
- A page may declare `badge: {collection, label?}`: the menu loads that collection with the
per-record ones and shows the number of rows as a count, `label` (with `{count}`) for screen
readers. The server keeps the key only once lane L2 adds it to `PageMenuKeys` (requested).
- The phone button shows the portal's `accountLabel` and the total of the counts ("2 nieuw").
- Portal key `residentMenu.cardLabel`: while the session acts for an organisation
(`session.organisationName`) the menu opens with a card: the label and the organisation's name.
- Styling in `css/site-theme.css`: capital group names, the current entry on
`--thematiq-accent-light-color` with a bar in `--thematiq-accent-color`, counts in
`--thematiq-badge-*`.

## Impact

Additive. Menus of portals and contributions that declare none of the keys render as before apart
from styling. Stacked on `site-chrome-follows-the-design` (same branch base); merge that first.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## ADDED Requirements

### Requirement: A per-record page in a group lists each row with its subtitle

When a contributed page declares `perRecord` and `group`, the resident menu MUST list each row of
that collection as one item of the group, named by the row's title fields, linking to the page with
that row chosen, with the row's `records.subtitleFields` joined by " · " as a second line. Without
`group` it MUST keep one group per row.

#### Scenario: The children of a guardian
@e2e exclude Rendered in node: tests/resident-menu-badges.spec.mjs
- GIVEN a page "Mijn kind" in group "Mijn kinderen", per record of the children, subtitle fields cohort and teacher
- WHEN the menu renders for Vera (Groep 7, Meester Daan) and Sami (Groep 4)
- THEN "Mijn kinderen" holds "Vera" with "Groep 7 · Meester Daan" and "Sami" with "Groep 4"

### Requirement: A menu entry may show the count of a collection

When a page declares `badge.collection`, one of its contribution's collections, the menu MUST
load that collection's rows for the resident and show their number beside the entry when it is
more than 0, with `badge.label` (`{count}` replaced) as its text for screen readers. The phone
button MUST show the total of all counts.

#### Scenario: Conferences to plan
@e2e exclude Rendered in node: tests/resident-menu-badges.spec.mjs
- GIVEN a page "Oudergesprekken" with a badge on a collection holding one row
- WHEN the menu renders
- THEN the entry shows "1" and reads "1 te plannen"

#### Scenario: Rows not known yet
@e2e exclude Rendered in node: tests/resident-menu-badges.spec.mjs
- GIVEN the badge collection has not loaded
- WHEN the menu renders
- THEN the entry shows no count

### Requirement: The menu may open with whom the resident acts for

When the portal declares `residentMenu.cardLabel` and the session acts for an organisation
(`organisationName`), the menu MUST open with a card showing the label and the organisation's
name. Otherwise it MUST show no card.

#### Scenario: An employer
@e2e exclude Rendered in node: tests/resident-menu-badges.spec.mjs; PortalShell projection by PHPUnit
- GIVEN a portal with card label "U regelt het voor" and a session for Jansen Installatietechniek BV
- WHEN the menu renders
- THEN it opens with "U regelt het voor" and "Jansen Installatietechniek BV"
9 changes: 9 additions & 0 deletions openspec/changes/resident-menu-badges-and-cards/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Tasks: resident menu badges and cards

- [x] 1. `residentMenu.js`: grouped per-record rows with sublines; `badge` counts; badge collections loaded with the per-record rows.
- [x] 2. `ResidentMenu.vue`: sublines, the organisation card, the phone button total.
- [x] 3. `AccountArea.vue`: the card and the button label; `PortalShell` projects `residentMenu.cardLabel`; schema and l10n.
- [x] 4. Styling in `css/site-theme.css`.
- [x] 5. Tests: `tests/resident-menu-badges.spec.mjs`; `mijn-home.spec.mjs` allows the subline anchor.
- [ ] 6. Lane L2 keeps `badge` in `lib/Contribution/PageMenuKeys.php`; lane L3 declares group, subtitle fields and badges in learniq.
- [x] 7. Live check with the school sets (menu styling, phone button total, chip); group, subtitles and badges wait on lanes L2 and L3.
Loading
Loading