diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html
new file mode 100644
index 0000000000..f95b4c8ad4
--- /dev/null
+++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html
@@ -0,0 +1,132 @@
+
Notification panel
+
+Basic notification panel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @for (item of basicItems; track item.id) {
+
+
+ }
+
+
+
+With urgent notifications
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @for (item of urgentItems; track item.id) {
+
+
+ }
+
+
+
+Notification type badges
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @for (item of allTypeItems; track item.id) {
+
+
+ }
+
+
diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts
new file mode 100644
index 0000000000..be1994aede
--- /dev/null
+++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts
@@ -0,0 +1,192 @@
+import { Component } from "@angular/core";
+import {
+ GoabWorkSideMenu,
+ GoabWorkSideMenuItem,
+ GoabWorkSideNotificationItem,
+ GoabWorkSideNotificationPanel,
+} from "@abgov/angular-components";
+import type {
+ GoabWorkSideNotificationItemType,
+ GoabWorkSideNotificationPriority,
+ GoabWorkSideNotificationReadStatus,
+} from "@abgov/ui-components-common";
+
+interface NotificationItem {
+ id: string;
+ title: string;
+ description: string;
+ timestamp: string;
+ type: GoabWorkSideNotificationItemType;
+ readStatus: GoabWorkSideNotificationReadStatus;
+ priority: GoabWorkSideNotificationPriority;
+}
+
+@Component({
+ standalone: true,
+ selector: "abgov-docs-work-side-notification-panel",
+ templateUrl: "./work-side-notification-panel.component.html",
+ imports: [
+ GoabWorkSideMenu,
+ GoabWorkSideMenuItem,
+ GoabWorkSideNotificationItem,
+ GoabWorkSideNotificationPanel,
+ ],
+})
+export class DocsWorkSideNotificationPanelComponent {
+ basicItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "New case assigned",
+ description: "Case #12345 has been assigned to you for review.",
+ timestamp: "2025-03-15T10:30:00Z",
+ type: "info",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "2",
+ title: "Document uploaded",
+ description: "A new document was uploaded to Case #12340.",
+ timestamp: "2025-03-15T09:15:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "3",
+ title: "Case resolved",
+ description: "Case #12330 has been marked as resolved.",
+ timestamp: "2025-03-14T16:00:00Z",
+ type: "success",
+ readStatus: "read",
+ priority: "normal",
+ },
+ ];
+
+ urgentItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "System maintenance",
+ description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.",
+ timestamp: "2025-03-15T14:00:00Z",
+ type: "critical",
+ readStatus: "unread",
+ priority: "urgent",
+ },
+ {
+ id: "2",
+ title: "Deadline approaching",
+ description: "Case #12345 response is due in 2 hours.",
+ timestamp: "2025-03-15T12:00:00Z",
+ type: "warning",
+ readStatus: "unread",
+ priority: "urgent",
+ },
+ {
+ id: "3",
+ title: "New comment on case",
+ description: "A team member commented on Case #12340.",
+ timestamp: "2025-03-15T11:00:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ ];
+
+ allTypeItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "New comment on case",
+ description: "A team member commented on Case #12340.",
+ timestamp: "2025-03-15T10:00:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "2",
+ title: "Case #12345 assigned",
+ description: "Case #12345 has been assigned to you for review.",
+ timestamp: "2025-03-15T09:00:00Z",
+ type: "info",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "3",
+ title: "Case resolved",
+ description: "Case #12330 has been marked as resolved.",
+ timestamp: "2025-03-15T08:00:00Z",
+ type: "success",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "4",
+ title: "Deadline approaching",
+ description: "Case #12345 response is due in 2 hours.",
+ timestamp: "2025-03-15T07:00:00Z",
+ type: "warning",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "5",
+ title: "System maintenance",
+ description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.",
+ timestamp: "2025-03-15T06:00:00Z",
+ type: "critical",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ ];
+
+ handleNavigate(path: string): void {
+ console.log("navigate", path);
+ }
+
+ // --- Basic notification panel handlers ---
+ handleMarkAllBasicNotificationsRead(): void {
+ this.basicItems = this.basicItems.map((item) => ({ ...item, readStatus: "read" }));
+ }
+
+ handleViewAllBasicNotifications(): void {
+ console.log("view all basic notifications");
+ }
+
+ handleClickBasicNotification(id: string): void {
+ this.basicItems = this.basicItems.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ );
+ }
+
+ // --- Urgent notification panel handlers ---
+ handleMarkAllUrgentNotificationsRead(): void {
+ this.urgentItems = this.urgentItems.map((item) => ({ ...item, readStatus: "read" }));
+ }
+
+ handleViewAllUrgentNotifications(): void {
+ console.log("view all urgent notifications");
+ }
+
+ handleClickUrgentNotification(id: string): void {
+ this.urgentItems = this.urgentItems.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ );
+ }
+
+ // --- Notification type badges panel handlers ---
+ handleMarkAllNotificationTypesRead(): void {
+ this.allTypeItems = this.allTypeItems.map((item) => ({ ...item, readStatus: "read" }));
+ }
+
+ handleViewAllNotificationTypes(): void {
+ console.log("view all notification types");
+ }
+
+ handleClickNotificationType(id: string): void {
+ this.allTypeItems = this.allTypeItems.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ );
+ }
+}
diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json
new file mode 100644
index 0000000000..0d8549afe6
--- /dev/null
+++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json
@@ -0,0 +1,6 @@
+{
+ "type": "docs",
+ "id": "work-side-notification-panel",
+ "path": "docs/work-side-notification-panel",
+ "title": "Notification Panel"
+}
diff --git a/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts b/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts
new file mode 100644
index 0000000000..909d1dfce3
--- /dev/null
+++ b/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts
@@ -0,0 +1,10 @@
+import { DocsWorkSideNotificationPanelRoute } from "../../../routes/docs/work-side-notification-panel/work-side-notification-panel";
+import type { PrRouteDefinition } from "../../route-manifest";
+
+export default {
+ type: "docs",
+ id: "work-side-notification-panel",
+ path: "docs/work-side-notification-panel",
+ title: "Notification Panel",
+ component: DocsWorkSideNotificationPanelRoute,
+} satisfies PrRouteDefinition;
diff --git a/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx b/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx
new file mode 100644
index 0000000000..610e067253
--- /dev/null
+++ b/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx
@@ -0,0 +1,299 @@
+import { useState } from "react";
+import {
+ GoabWorkSideMenu,
+ GoabWorkSideMenuItem,
+ GoabWorkSideNotificationItem,
+ GoabWorkSideNotificationPanel,
+ type GoabWorkSideNotificationItemProps,
+} from "@abgov/react-components";
+
+type NotificationItem = GoabWorkSideNotificationItemProps & { id: string };
+
+const initialBasicItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "New case assigned",
+ description: "Case #12345 has been assigned to you for review.",
+ timestamp: "2025-03-15T10:30:00Z",
+ type: "info",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "2",
+ title: "Document uploaded",
+ description: "A new document was uploaded to Case #12340.",
+ timestamp: "2025-03-15T09:15:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "3",
+ title: "Case resolved",
+ description: "Case #12330 has been marked as resolved.",
+ timestamp: "2025-03-14T16:00:00Z",
+ type: "success",
+ readStatus: "read",
+ priority: "normal",
+ },
+];
+
+const initialUrgentItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "System maintenance",
+ description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.",
+ timestamp: "2025-03-15T14:00:00Z",
+ type: "critical",
+ readStatus: "unread",
+ priority: "urgent",
+ },
+ {
+ id: "2",
+ title: "Deadline approaching",
+ description: "Case #12345 response is due in 2 hours.",
+ timestamp: "2025-03-15T12:00:00Z",
+ type: "warning",
+ readStatus: "unread",
+ priority: "urgent",
+ },
+ {
+ id: "3",
+ title: "New comment on case",
+ description: "A team member commented on Case #12340.",
+ timestamp: "2025-03-15T11:00:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+];
+
+const initialAllTypeItems: NotificationItem[] = [
+ {
+ id: "1",
+ title: "New comment on case",
+ description: "A team member commented on Case #12340.",
+ timestamp: "2025-03-15T10:00:00Z",
+ type: "default",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "2",
+ title: "Case #12345 assigned",
+ description: "Case #12345 has been assigned to you for review.",
+ timestamp: "2025-03-15T09:00:00Z",
+ type: "info",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "3",
+ title: "Case resolved",
+ description: "Case #12330 has been marked as resolved.",
+ timestamp: "2025-03-15T08:00:00Z",
+ type: "success",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "4",
+ title: "Deadline approaching",
+ description: "Case #12345 response is due in 2 hours.",
+ timestamp: "2025-03-15T07:00:00Z",
+ type: "warning",
+ readStatus: "unread",
+ priority: "normal",
+ },
+ {
+ id: "5",
+ title: "System maintenance",
+ description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.",
+ timestamp: "2025-03-15T06:00:00Z",
+ type: "critical",
+ readStatus: "unread",
+ priority: "normal",
+ },
+];
+
+export function DocsWorkSideNotificationPanelRoute() {
+ const [basicItems, setBasicItems] = useState(initialBasicItems);
+ const [urgentItems, setUrgentItems] = useState(initialUrgentItems);
+ const [allTypeItems, setAllTypeItems] = useState(initialAllTypeItems);
+
+ function navigate(path: string) {
+ console.log("navigate", path);
+ }
+
+ // --- Basic notification panel handlers ---
+ function handleMarkAllBasicNotificationsRead() {
+ setBasicItems((items) =>
+ items.map((item) => ({ ...item, readStatus: "read" })),
+ );
+ }
+
+ function handleViewAllBasicNotifications() {
+ console.log("view all basic notifications");
+ }
+
+ function handleClickBasicNotification(id: string) {
+ setBasicItems((items) =>
+ items.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ ),
+ );
+ }
+
+ // --- Urgent notification panel handlers ---
+ function handleMarkAllUrgentNotificationsRead() {
+ setUrgentItems((items) =>
+ items.map((item) => ({ ...item, readStatus: "read" })),
+ );
+ }
+
+ function handleViewAllUrgentNotifications() {
+ console.log("view all urgent notifications");
+ }
+
+ function handleClickUrgentNotification(id: string) {
+ setUrgentItems((items) =>
+ items.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ ),
+ );
+ }
+
+ // --- Notification type badges panel handlers ---
+ function handleMarkAllNotificationTypesRead() {
+ setAllTypeItems((items) =>
+ items.map((item) => ({ ...item, readStatus: "read" })),
+ );
+ }
+
+ function handleViewAllNotificationTypes() {
+ console.log("view all notification types");
+ }
+
+ function handleClickNotificationType(id: string) {
+ setAllTypeItems((items) =>
+ items.map((item) =>
+ item.id === id ? { ...item, readStatus: "read" } : item,
+ ),
+ );
+ }
+
+ return (
+
+
Notification panel
+
+ Basic notification panel
+ navigate(path)}
+ primaryContent={
+ <>
+
+
+ >
+ }
+ secondaryContent={
+ handleMarkAllBasicNotificationsRead()}
+ onViewAll={() => handleViewAllBasicNotifications()}
+ >
+ {basicItems.map(({ id, ...item }) => (
+ handleClickBasicNotification(id)}
+ />
+ ))}
+
+ }
+ />
+ }
+ />
+
+ With urgent notifications
+ navigate(path)}
+ primaryContent={
+ <>
+
+
+ >
+ }
+ secondaryContent={
+ handleMarkAllUrgentNotificationsRead()}
+ onViewAll={() => handleViewAllUrgentNotifications()}
+ >
+ {urgentItems.map(({ id, ...item }) => (
+ handleClickUrgentNotification(id)}
+ />
+ ))}
+
+ }
+ />
+ }
+ />
+
+ Notification type badges
+ navigate(path)}
+ primaryContent={
+
+ }
+ secondaryContent={
+ handleMarkAllNotificationTypesRead()}
+ onViewAll={() => handleViewAllNotificationTypes()}
+ >
+ {allTypeItems.map(({ id, ...item }) => (
+ handleClickNotificationType(id)}
+ />
+ ))}
+
+ }
+ />
+ }
+ />
+
+ );
+}
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 6599ce45c9..34768508c7 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -219,6 +219,13 @@ export const buttonConfigurations: ComponentConfigurations = {
This is a common source of errors when writing configuration code since all three are in the same file.
+**Preview customization:** Two optional fields on `ComponentConfigurations` let you customize the sandbox preview without affecting the code snippet users see:
+
+- `previewStyle` — CSS applied to the preview container (e.g. background color, flex layout). Example: workspace components use a grey background with a content card to simulate the app layout.
+- `previewWrapper` — HTML template that wraps the component code in the preview only. Use `{{slot}}` as the placeholder for the component code. The code snippet shown to users contains just the component code, not the wrapper.
+
+See `work-side-notification-panel.ts` or `work-side-menu.ts` for examples.
+
---
## How to: common changes
@@ -289,19 +296,11 @@ Result: the Tabs page shows "Tab Props", "Tab Slots" (and "Tab Events" if any ex
2. Add its slug to the parent's `relatedComponents` array
3. Ensure API data exists. If the Svelte component has its own directory (`libs/web-components/src/components/my-sub/`), the extraction script handles it automatically. If it's a nested file inside the parent's directory (like `WorkSideMenuGroup.svelte` inside `work-side-menu/`), you need to manually create the API JSON in `generated/component-apis/my-sub.json`
-**Current subcomponent mappings:**
-
-| Parent | Subcomponents |
-| -------------- | ----------------------------------------- |
-| Header | App Header Menu |
-| File uploader | File Upload Card |
-| Footer | Footer Meta Section, Footer Nav Section |
-| Form stepper | Form Step |
-| Menu button | Menu Action |
-| Radio | Radio Item |
-| Side menu | Side Menu Group, Side Menu Heading |
-| Tabs | Tab |
-| Work Side Menu | Work Side Menu Group, Work Side Menu Item |
+To see all current subcomponent mappings, search for `subcomponent: true` in the MDX files:
+
+```bash
+grep -rl "subcomponent: true" docs/src/content/components/
+```
### Hide a component from navigation
diff --git a/docs/generated/component-apis/work-side-notification-item.json b/docs/generated/component-apis/work-side-notification-item.json
new file mode 100644
index 0000000000..c0fa451679
--- /dev/null
+++ b/docs/generated/component-apis/work-side-notification-item.json
@@ -0,0 +1,76 @@
+{
+ "componentSlug": "work-side-notification-item",
+ "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideNotificationItem.svelte",
+ "props": [
+ {
+ "name": "type",
+ "type": "\"default\" | \"success\" | \"critical\" | \"warning\" | \"info\"",
+ "typeLabel": "GoabWorkSideNotificationItemType",
+ "values": ["default", "success", "critical", "warning", "info"],
+ "required": false,
+ "default": "default",
+ "description": ""
+ },
+ {
+ "name": "timestamp",
+ "type": "string",
+ "required": false,
+ "default": "",
+ "description": ""
+ },
+ {
+ "name": "title",
+ "type": "string",
+ "required": false,
+ "default": "",
+ "description": ""
+ },
+ {
+ "name": "description",
+ "type": "string",
+ "required": true,
+ "default": null,
+ "description": ""
+ },
+ {
+ "name": "readStatus",
+ "type": "\"read\" | \"unread\"",
+ "typeLabel": "GoabWorkSideNotificationReadStatus",
+ "values": ["read", "unread"],
+ "required": false,
+ "default": "unread",
+ "description": ""
+ },
+ {
+ "name": "priority",
+ "type": "\"normal\" | \"urgent\"",
+ "typeLabel": "GoabWorkSideNotificationPriority",
+ "values": ["normal", "urgent"],
+ "required": false,
+ "default": "normal",
+ "description": ""
+ },
+ {
+ "name": "testId",
+ "type": "string",
+ "required": false,
+ "default": "",
+ "description": ""
+ }
+ ],
+ "events": [
+ {
+ "name": "onClick",
+ "type": "(event: Event) => void",
+ "description": "",
+ "frameworks": ["react"]
+ },
+ {
+ "name": "_click",
+ "type": "CustomEvent",
+ "description": "",
+ "frameworks": ["angular", "web-component"]
+ }
+ ],
+ "slots": []
+}
diff --git a/docs/generated/component-apis/work-side-notification-panel.json b/docs/generated/component-apis/work-side-notification-panel.json
new file mode 100644
index 0000000000..81b59544e9
--- /dev/null
+++ b/docs/generated/component-apis/work-side-notification-panel.json
@@ -0,0 +1,61 @@
+{
+ "componentSlug": "work-side-notification-panel",
+ "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideNotificationPanel.svelte",
+ "props": [
+ {
+ "name": "heading",
+ "type": "string",
+ "required": false,
+ "default": "Notifications",
+ "description": ""
+ },
+ {
+ "name": "activeTab",
+ "type": "\"unread\" | \"urgent\" | \"all\"",
+ "typeLabel": "GoabWorkSideNotificationActiveTabType",
+ "values": ["unread", "urgent", "all"],
+ "required": false,
+ "default": "unread",
+ "description": ""
+ },
+ {
+ "name": "testId",
+ "type": "string",
+ "required": false,
+ "default": "",
+ "description": ""
+ }
+ ],
+ "events": [
+ {
+ "name": "onMarkAllRead",
+ "type": "() => void",
+ "description": "",
+ "frameworks": ["react"]
+ },
+ {
+ "name": "_markAllRead",
+ "type": "CustomEvent",
+ "description": "",
+ "frameworks": ["angular", "web-component"]
+ },
+ {
+ "name": "onViewAll",
+ "type": "() => void",
+ "description": "",
+ "frameworks": ["react"]
+ },
+ {
+ "name": "_viewAll",
+ "type": "CustomEvent",
+ "description": "",
+ "frameworks": ["angular", "web-component"]
+ }
+ ],
+ "slots": [
+ {
+ "name": "default",
+ "description": ""
+ }
+ ]
+}
diff --git a/docs/public/search-index.json b/docs/public/search-index.json
index 7978aa13a8..2cab6011ee 100644
--- a/docs/public/search-index.json
+++ b/docs/public/search-index.json
@@ -11,8 +11,7 @@
"blind",
"collapse",
"content layout",
- "expandable panel",
- "expand"
+ "expandable panel"
],
"slug": "accordion"
},
@@ -179,7 +178,14 @@
"description": "Advanced table with sorting and selection.",
"status": "stable",
"category": "content-layout",
- "tags": [],
+ "tags": [
+ "table",
+ "grid",
+ "content layout",
+ "data table",
+ "sorting",
+ "selection"
+ ],
"slug": "data-grid"
},
{
@@ -246,7 +252,7 @@
"name": "Drawer",
"description": "A panel that slides in from the side of the screen to display additional content or actions without navigating away from the current view.",
"status": "stable",
- "category": "content-layout",
+ "category": "structure-and-navigation",
"tags": [
"sections",
"structure and navigation",
@@ -734,6 +740,96 @@
"tags": [],
"slug": "work-side-menu"
},
+ {
+ "type": "component",
+ "id": "work-side-notification-panel",
+ "name": "Notification Panel",
+ "description": "A notification center panel that displays notification items within a work side menu, with tabs for filtering by unread, urgent, and all notifications.",
+ "status": "stable",
+ "category": "structure-and-navigation",
+ "tags": [
+ "notifications",
+ "work side menu",
+ "panel"
+ ],
+ "slug": "work-side-notification-panel"
+ },
+ {
+ "type": "example",
+ "id": "401-error-page",
+ "title": "Restricted access (401)",
+ "description": "A full page that tells the user they cannot access the requested resource, with a clear next step and a way to contact support.",
+ "status": "published",
+ "categories": [
+ "content-layout"
+ ],
+ "tags": [
+ "error",
+ "page-structure",
+ "\"401\""
+ ],
+ "components": [
+ "page-block",
+ "block",
+ "text",
+ "icon",
+ "link",
+ "button"
+ ],
+ "scale": "page",
+ "userType": "both",
+ "slug": "401-error-page"
+ },
+ {
+ "type": "example",
+ "id": "404-error-page",
+ "title": "Page not found (404)",
+ "description": "A full page that tells the user a page can't be found, with an action to get them back on track.",
+ "status": "published",
+ "categories": [
+ "content-layout"
+ ],
+ "tags": [
+ "error",
+ "page-structure",
+ "\"404\""
+ ],
+ "components": [
+ "page-block",
+ "block",
+ "text",
+ "icon",
+ "button"
+ ],
+ "scale": "page",
+ "userType": "both",
+ "slug": "404-error-page"
+ },
+ {
+ "type": "example",
+ "id": "500-error-page",
+ "title": "Server problem (500)",
+ "description": "A full page that tells the user the service is temporarily unable to respond, with an action to try again or return home.",
+ "status": "published",
+ "categories": [
+ "content-layout"
+ ],
+ "tags": [
+ "error",
+ "page-structure",
+ "\"500\""
+ ],
+ "components": [
+ "page-block",
+ "block",
+ "text",
+ "icon",
+ "button"
+ ],
+ "scale": "page",
+ "userType": "both",
+ "slug": "500-error-page"
+ },
{
"type": "example",
"id": "add-a-filter-chip",
@@ -1104,28 +1200,6 @@
"userType": "worker",
"slug": "card-view-of-case-files"
},
- {
- "type": "example",
- "id": "communicate-a-future-service-outage",
- "title": "Communicate a future service outage",
- "description": "Display a clear message to inform users about an upcoming service outage, including the date, time, and expected impact on service availability.",
- "status": "published",
- "categories": [
- "feedback-and-alerts"
- ],
- "tags": [
- "notification",
- "maintenance",
- "alerts",
- "system-status"
- ],
- "components": [
- "notification"
- ],
- "scale": "task",
- "userType": "both",
- "slug": "communicate-a-future-service-outage"
- },
{
"type": "example",
"id": "confirm-a-change",
@@ -1491,8 +1565,8 @@
},
{
"type": "example",
- "id": "give-background-information-before-asking-a-question",
- "title": "Give background information before asking a question",
+ "id": "give-more-information-before-asking-a-question-a",
+ "title": "Give more information before asking a question (a)",
"description": "Provide explanatory context before asking a question to help users understand what is being asked.",
"status": "published",
"categories": [
@@ -1513,12 +1587,12 @@
],
"scale": "task",
"userType": "citizen",
- "slug": "give-background-information-before-asking-a-question"
+ "slug": "give-more-information-before-asking-a-question-a"
},
{
"type": "example",
- "id": "give-context-before-asking-a-long-answer-question",
- "title": "Give context before asking a long answer question",
+ "id": "give-more-information-before-asking-a-question-b",
+ "title": "Give more information before asking a question (b)",
"description": "Provide context and guidance before a long-answer text field to help users provide relevant information.",
"status": "published",
"categories": [
@@ -1541,7 +1615,7 @@
],
"scale": "task",
"userType": "citizen",
- "slug": "give-context-before-asking-a-long-answer-question"
+ "slug": "give-more-information-before-asking-a-question-b"
},
{
"type": "example",
@@ -1725,6 +1799,28 @@
"userType": "both",
"slug": "link-to-an-external-page"
},
+ {
+ "type": "example",
+ "id": "notify-the-user-of-a-future-service-outage",
+ "title": "Notify the user of a future service outage",
+ "description": "Display a clear message to inform users about an upcoming service outage, including the date, time, and expected impact on service availability.",
+ "status": "published",
+ "categories": [
+ "feedback-and-alerts"
+ ],
+ "tags": [
+ "notification",
+ "maintenance",
+ "alerts",
+ "system-status"
+ ],
+ "components": [
+ "notification"
+ ],
+ "scale": "task",
+ "userType": "both",
+ "slug": "notify-the-user-of-a-future-service-outage"
+ },
{
"type": "example",
"id": "public-form",
@@ -1741,7 +1837,7 @@
"pattern"
],
"components": [],
- "scale": "service",
+ "scale": "product",
"userType": "citizen",
"slug": "public-form"
},
@@ -2714,5 +2810,37 @@
"scale": "task",
"userType": "both",
"slug": "warn-a-user-of-a-deadline"
+ },
+ {
+ "type": "example",
+ "id": "workspace",
+ "title": "Workspace",
+ "description": "The workspace is for productivity-focused services used by service delivery staff as a daily tool to review information, manage records, and complete tasks. The design prioritizes productivity, efficiency, and accuracy so staff can move through their work quickly while ensuring the best outcome for citizens and government.
Workspaces should be adapted to fit each service's context and user needs. The reference example is a starting point to expand on, not a rigid template.",
+ "status": "published",
+ "categories": [],
+ "tags": [
+ "workspace",
+ "worker",
+ "service",
+ "case-management",
+ "dashboard",
+ "pattern"
+ ],
+ "components": [
+ "work-side-menu",
+ "work-side-notification-panel",
+ "work-side-notification-item",
+ "table",
+ "badge",
+ "tabs",
+ "container",
+ "accordion",
+ "drawer",
+ "button",
+ "block"
+ ],
+ "scale": "product",
+ "userType": "worker",
+ "slug": "workspace"
}
]
\ No newline at end of file
diff --git a/docs/public/thumbnails/workspace-notification-panel.png b/docs/public/thumbnails/workspace-notification-panel.png
new file mode 100644
index 0000000000..b0bb9762d4
Binary files /dev/null and b/docs/public/thumbnails/workspace-notification-panel.png differ
diff --git a/docs/public/thumbnails/workspace-sticky-action-bar.png b/docs/public/thumbnails/workspace-sticky-action-bar.png
index 6e9e528067..3b1879875c 100644
Binary files a/docs/public/thumbnails/workspace-sticky-action-bar.png and b/docs/public/thumbnails/workspace-sticky-action-bar.png differ
diff --git a/docs/src/components/ConfigurationPreview.tsx b/docs/src/components/ConfigurationPreview.tsx
index 612ba5e6be..69d2fe979c 100644
--- a/docs/src/components/ConfigurationPreview.tsx
+++ b/docs/src/components/ConfigurationPreview.tsx
@@ -10,11 +10,11 @@
* Code snippet changes based on selected framework preference.
*/
-import { useState, useEffect, useRef, useCallback } from "react";
+import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
// Note: Using web component directly for v2 styling (React wrapper doesn't pass version prop)
import { CodeSnippet } from "./CodeSnippet";
import { useGitHubIssueCount } from "../hooks/useGitHubIssueCount";
-import type { ComponentConfigurations } from "../data/configurations/types";
+import type { ComponentConfigurations } from "@/data/configurations";
import DOMPurify from "dompurify";
// Allow GoA web component custom elements through DOMPurify.
@@ -65,21 +65,23 @@ export function ConfigurationPreview({
webComponentCode.js ? `` : "",
].join("");
+ const previewHtml = configurations.previewWrapper
+ ? configurations.previewWrapper.replace("{{slot}}", rawCode)
+ : rawCode;
+
// Extract script content before sanitization
- const scriptMatch = rawCode.match(/