Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9013e0f
wip
ermenm Jan 20, 2026
7515bd3
feat: shared components
ermenm Jan 22, 2026
700aa50
chore: case insensitive stylesheet selector
ermenm Jan 22, 2026
a73fd9b
fix: relative file refs
ermenm Jan 22, 2026
9afe27c
fix: import clippy-code
ermenm Jan 22, 2026
f4cb227
chore: rename file
ermenm Jan 22, 2026
6a94c70
feat: foldering and structuring
ermenm Jan 22, 2026
d201cb6
chore: separate files for styles
ermenm Jan 22, 2026
87d9239
feat: initial version of search results page
ermenm Jan 23, 2026
5e9b708
chore: classname
ermenm Jan 27, 2026
50548af
WIP
ermenm Feb 3, 2026
1291b87
wip
ermenm Feb 3, 2026
b8b1b1b
wip
ermenm Feb 3, 2026
33ea001
wip
ermenm Feb 3, 2026
2a9552b
feat: Implement client-side search filtering and sorting directly wit…
ermenm Feb 3, 2026
572092c
chore: devtools
ermenm Feb 4, 2026
f71bd3d
refactor(search): relocate search components into feature directories…
ermenm Feb 4, 2026
3c7cbad
feat(layout): introduce TemplateLayout and integrate navigation with …
ermenm Feb 4, 2026
061fba7
feat(search): update constants to be organization-agnostic and improv…
ermenm Feb 4, 2026
e95eea4
chore(storybook): update search templates and preview configuration
ermenm Feb 4, 2026
88b74bb
chore: add number-badge dependency and update website configuration
ermenm Feb 4, 2026
c4aa45e
feat: Relocate the filter reset button to the SearchFilters component…
ermenm Feb 4, 2026
82e3c9c
chore: cleanup
ermenm Feb 4, 2026
cbdef0e
fix: lint
ermenm Feb 4, 2026
3561d53
chore: apply code formatting, update Stylelint patterns
ermenm Feb 4, 2026
bb205b3
refactor: Remove `prerender = false` export from the search results p…
ermenm Feb 4, 2026
12e00f7
chore: add vercel adapter and disable prerender for search-results page
ermenm Feb 5, 2026
54bf8cd
feat: enhancements
ermenm Feb 5, 2026
395abe3
fix: skip link
ermenm Feb 5, 2026
d0f0d0e
refactor: Adjust search form input group layout, remove generic icon-…
ermenm Feb 9, 2026
3d94b2a
chore: Remove the generated custom-elements.json file from clippy-com…
ermenm Feb 9, 2026
e0eea41
chore: remove custom elements json
ermenm Feb 9, 2026
7b52013
chore: remove package
ermenm Feb 9, 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
6 changes: 3 additions & 3 deletions .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"scss/percent-placeholder-pattern": "^(theme|utrecht)-[a-z0-9-]+$",
"scss/operator-no-newline-after": null,
"scss/at-extend-no-missing-placeholder": null,
"custom-property-pattern": "^_?(ams|basis|clippy|theme|denhaag|utrecht)-[a-z0-9-]+$",
"selector-class-pattern": "^(ams|basis|clippy|theme|denhaag|utrecht)-[a-z0-9_-]+$",
"keyframes-name-pattern": "^(ams|basis|clippy|theme|utrecht)-[a-z0-9-]+$",
"custom-property-pattern": "^_?(nl|ams|basis|clippy|theme|denhaag|utrecht)-[a-z0-9-]+$",
"selector-class-pattern": "^(nl|ams|basis|clippy|theme|denhaag|utrecht)-[a-z0-9_-]+$",
"keyframes-name-pattern": "^(nl|ams|basis|clippy|theme|utrecht)-[a-z0-9-]+$",
"at-rule-no-unknown": null,
"block-no-empty": [true],
"color-no-invalid-hex": [true],
Expand Down
2 changes: 1 addition & 1 deletion packages/clippy-storybook/config/decorators.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { THEMES } from './themes/theme-data';

const stylesheetExists = (href: string): HTMLLinkElement | undefined =>
Array.from(document.querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]')).find((link) => link.href === href);
Array.from(document.querySelectorAll<HTMLLinkElement>('link[rel~="stylesheet"]')).find((link) => link.href === href);

const ensureThemeStylesheet = (root: HTMLElement, themeClassName: string) => {
const head = document.querySelector('head');
Expand Down
3 changes: 3 additions & 0 deletions packages/clippy-storybook/config/preview-head.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<script>
document.documentElement.classList.add('js-enabled');
</script>
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<style>
#storybook-root.theme-loading::before {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { SearchResults, type SearchResultsProps } from '@nl-design-system-community/theme-wizard-templates/react';
import * as React from 'react';
import '@utrecht/component-library-css';
import documentation from './docs/Results.md?raw';

const CombinedResults = SearchResults as React.ComponentType<SearchResultsProps>;

const meta = {
component: CombinedResults,
parameters: {
docs: {
description: {
component: documentation,
},
},
layout: 'fullscreen',
},
tags: ['autodocs'],
title: 'Templates/Zoeken/Resultaten',
} satisfies Meta<SearchResultsProps>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
name: 'Zoekresultaten',
args: {
currentPath: '/search-results',
initialQuery: 'afval',
},
};

export const NoResults: Story = {
name: 'Geen resultaten',
args: {
currentPath: '/search-results',
initialQuery: 'onbekendwoord',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Search, type SearchProps } from '@nl-design-system-community/theme-wizard-templates/react';
import * as React from 'react';
import '@utrecht/component-library-css';
import documentation from './docs/Search.md?raw';

const CombinedSearch = Search as React.ComponentType<SearchProps>;

const meta = {
component: CombinedSearch,
parameters: {
docs: {
description: {
component: documentation,
},
},
layout: 'fullscreen',
},
tags: ['autodocs'],
title: 'Templates/Zoeken/Start',
} satisfies Meta<SearchProps>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
name: 'Zoeken',
args: {
currentPath: '/search',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Placeholder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Placeholder
2 changes: 1 addition & 1 deletion packages/design-tokens-schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
"devDependencies": {
"@nl-design-system-community/ma-design-tokens": "2.5.0",
"@nl-design-system-unstable/start-design-tokens": "2.4.1",
"@nl-design-system-unstable/start-design-tokens": "3.0.0",
"@nl-design-system-unstable/voorbeeld-design-tokens": "7.4.0",
"@types/dlv": "1.1.5",
"@vitest/coverage-v8": "4.0.16",
Expand Down
2 changes: 1 addition & 1 deletion packages/theme-wizard-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"@nl-design-system-community/css-scraper": "workspace:*",
"@nl-design-system-community/design-tokens-schema": "workspace:*",
"@nl-design-system-community/ma-design-tokens": "3.0.0",
"@nl-design-system-unstable/start-design-tokens": "2.4.1",
"@nl-design-system-unstable/start-design-tokens": "3.0.0",
"@utrecht/button-css": "3.0.1",
"@utrecht/form-field-css": "2.0.1",
"@utrecht/form-field-error-message-css": "2.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ export default css`

/* Hide all app descendants, except those that are needed to show the preview content */
.wizard-layout *:not(
:has(.wizard-layout__main), /* any parent of main */
.wizard-layout__main, /* main itself */
.wizard-layout__main * /* any child of main */
:has(.wizard-layout__main),
.wizard-layout__main,
.wizard-layout__main *
) {
display: none;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/theme-wizard-templates/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import react from '@astrojs/react';
import vercel from '@astrojs/vercel';
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
adapter: vercel(),
devToolbar: {
enabled: false,
},
Expand Down
5 changes: 4 additions & 1 deletion packages/theme-wizard-templates/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@amsterdam/design-system-css": "2.1.0",
"@amsterdam/design-system-react": "2.2.0",
"@astrojs/react": "4.4.2",
"@astrojs/vercel": "9.0.2",
"@gemeente-denhaag/action": "4.1.3",
"@gemeente-denhaag/card": "5.0.6",
"@gemeente-denhaag/side-navigation": "4.0.3",
Expand All @@ -46,6 +47,7 @@
"@nl-design-system-candidate/heading-react": "1.1.6",
"@nl-design-system-candidate/link-css": "2.0.3",
"@nl-design-system-candidate/link-react": "1.1.7",
"@nl-design-system-candidate/number-badge-react": "1.3.2",
"@nl-design-system-candidate/paragraph-css": "2.1.3",
"@nl-design-system-candidate/paragraph-react": "2.2.1",
"@nl-design-system-candidate/skip-link-css": "1.0.5",
Expand All @@ -54,7 +56,7 @@
"@nl-design-system-community/design-tokens-schema": "workspace:*",
"@nl-design-system-community/ma-design-tokens": "3.0.0",
"@nl-design-system-community/theme-wizard-app": "workspace:*",
"@nl-design-system-unstable/start-design-tokens": "2.4.1",
"@nl-design-system-unstable/start-design-tokens": "3.0.0",
"@tabler/icons-react": "3.36.1",
"@utrecht/component-library-css": "8.2.1",
"@utrecht/component-library-react": "12.0.0",
Expand All @@ -65,6 +67,7 @@
"@utrecht/web-component-library-react": "3.0.12",
"@utrecht/web-component-library-stencil": "3.7.0",
"clsx": "2.1.1",
"css": "link:@nl-design-system-candidate/number-badge-react/css",
"lit": "3.3.2",
"react": "19.2.3",
"react-dom": "19.2.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
defineCustomElements();
});

import '@nl-design-system-community/clippy-components/clippy-button';
import '@nl-design-system-community/clippy-components/clippy-code';
import '@nl-design-system-community/clippy-components/clippy-heading';
import '../components';
</script>
171 changes: 102 additions & 69 deletions packages/theme-wizard-templates/src/components/DevTools.astro
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
---
// Check if we're in standalone mode (defined in astro.config.mjs)
const isStandalone = typeof __STANDALONE_PACKAGE__ !== 'undefined' && __STANDALONE_PACKAGE__ === true;
---

{isStandalone && (
<div class="clippy-dev-tools">
<a href="/">Back to home</a>
<utrecht-button id="clear-localstorage" type="button">Clear localStorage</utrecht-button>
<details class="clippy-dev-tools__details" hidden>
<summary>cookies</summary>
<pre id="localstorage-content" class="clippy-dev-tools__content"></pre>
</details>
<div class="clippy-dev-tools" tabindex={-1} aria-hidden="true">
<a href="/">Back to home</a>
<utrecht-button id="clear-localstorage" type="button">Clear localStorage</utrecht-button>
<div class="clippy-dev-tools__toggle">
<label>
<input type="checkbox" id="search-reload-toggle" />
Search with page reload
</label>
</div>
)}
<details class="clippy-dev-tools__details" hidden>
<summary>cookies</summary>
<pre id="localstorage-content" class="clippy-dev-tools__content"></pre>
</details>
</div>

<style>
.clippy-dev-tools {
Expand All @@ -33,6 +32,12 @@ const isStandalone = typeof __STANDALONE_PACKAGE__ !== 'undefined' && __STANDALO
z-index: 9999;
}

@media (width <= 768px) {
.clippy-dev-tools {
display: none;
}
}

.clippy-dev-tools a,
.clippy-dev-tools button {
font-family: var(--basis-text-font-family-default);
Expand Down Expand Up @@ -79,67 +84,95 @@ const isStandalone = typeof __STANDALONE_PACKAGE__ !== 'undefined' && __STANDALO
padding-inline: var(--basis-space-inline-sm);
white-space: pre-wrap;
}

.clippy-dev-tools__toggle {
align-items: center;
display: flex;
font-family: var(--basis-text-font-family-default);
font-size: var(--basis-text-font-size-sm);
gap: var(--basis-space-inline-sm);
}

.clippy-dev-tools__toggle label {
align-items: center;
cursor: pointer;
display: flex;
gap: 0.5rem;
}
</style>

{isStandalone && (
<script>
const STORAGE_KEY = 'cookie-consent-preferences';

// Function to read and display localStorage content
function updateLocalStorageDisplay() {
const detailsElement = document.querySelector('.clippy-dev-tools__details');
const contentElement = document.getElementById('localstorage-content');

if (!detailsElement || !contentElement) return;
<script>
const STORAGE_KEY = 'cookie-consent-preferences';

try {
const storedData = localStorage.getItem(STORAGE_KEY);
if (storedData) {
// Show details if there's data
detailsElement.removeAttribute('hidden');

// Try to parse and pretty-print JSON
try {
const parsed = JSON.parse(storedData);
contentElement.textContent = JSON.stringify(parsed, null, 2);
} catch {
// If not valid JSON, just show the raw value
contentElement.textContent = storedData;
}
} else {
// Hide details if there's no data
detailsElement.setAttribute('hidden', '');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
contentElement.textContent = `Fout bij lezen van localStorage: ${errorMessage}`;
}
}
// Function to read and display localStorage content
function updateLocalStorageDisplay() {
const detailsElement = document.querySelector('.clippy-dev-tools__details');
const contentElement = document.getElementById('localstorage-content');

// Update display on page load
updateLocalStorageDisplay();
if (!detailsElement || !contentElement) return;

// Update display when details is opened
const detailsElement = document.querySelector('.clippy-dev-tools__details') as HTMLDetailsElement | null;
if (detailsElement) {
detailsElement.addEventListener('toggle', () => {
if (detailsElement?.open) {
updateLocalStorageDisplay();
}
});
}
try {
const storedData = localStorage.getItem(STORAGE_KEY);
if (storedData) {
// Show details if there's data
detailsElement.removeAttribute('hidden');

// Clear localStorage button
const clearButton = document.getElementById('clear-localstorage');
if (clearButton) {
clearButton.addEventListener('click', () => {
// Try to parse and pretty-print JSON
try {
localStorage.removeItem(STORAGE_KEY);
window.location.reload();
} catch (error) {
console.error('Fout bij verwijderen van localStorage:', error);
const parsed = JSON.parse(storedData);
contentElement.textContent = JSON.stringify(parsed, null, 2);
} catch {
// If not valid JSON, just show the raw value
contentElement.textContent = storedData;
}
});
} else {
// Hide details if there's no data
detailsElement.setAttribute('hidden', '');
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
contentElement.textContent = `Fout bij lezen van localStorage: ${errorMessage}`;
}
</script>
)}
}

// Update display on page load
updateLocalStorageDisplay();

// Update display when details is opened
const detailsElement = document.querySelector('.clippy-dev-tools__details') as HTMLDetailsElement | null;
if (detailsElement) {
detailsElement.addEventListener('toggle', () => {
if (detailsElement?.open) {
updateLocalStorageDisplay();
}
});
}

// Clear localStorage button
const clearButton = document.getElementById('clear-localstorage');
if (clearButton) {
clearButton.addEventListener('click', () => {
try {
localStorage.removeItem(STORAGE_KEY);
localStorage.removeItem('clippy-search-use-reload');
window.location.reload();
} catch (error) {
console.error('Fout bij verwijderen van localStorage:', error);
}
});
}

// Search reload toggle
const RELOAD_KEY = 'clippy-search-use-reload';
const reloadToggle = document.getElementById('search-reload-toggle') as HTMLInputElement | null;

if (reloadToggle) {
// Initialize from localStorage
const useReload = localStorage.getItem(RELOAD_KEY) === 'true';
reloadToggle.checked = useReload;

reloadToggle.addEventListener('change', () => {
localStorage.setItem(RELOAD_KEY, String(reloadToggle.checked));
});
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Icon } from '@utrecht/component-library-react';
import React from 'react';
import type { NewsItem } from './types';
import { Column, Row } from '../Layout';
import '../shared/card-styles.css';
import './styles.css';

export interface NewsCardsProps {
cards: NewsItem[];
Expand Down
Loading
Loading