Skip to main content

NL-Government and French-Government Icons Integration

Overview

The Thematiq app includes 1488 icons materialized from @conduction/nextcloud-vue's EUPL-compatible NL-government icon packs (RVO, OpenGemeenten, Gemeente Den Haag), plus 1038 icons materialized from @gouvfr/dsfr's French-government DSFR pack (Etalab-2.0) — 2526 icons total — plus 23 logos, making them available for use across all Nextcloud apps.

Theme-switchable iconography

The icon pack an app should serve travels with the active design system, driven by design-systems.json's optional icon_pack field: nldesign -> ["rvo", "open-gemeenten", "den-haag"], lasuite -> ["dsfr"]. Resolve the active pack via DesignSystemService::resolveActiveIconPacks() / resolveIconPath(), or read it from the public capability (capabilities.nldesign.iconPacks) — see openspec/specs/icon-packs/spec.md. This does not replace Nextcloud core's built-in icons; it only switches Thematiq's own bundled assets served through imagePath.

The proprietary City-of-Amsterdam icon set (@amsterdam/design-system-assets) is NOT bundled. Its LICENSE.md marks the set proprietary to the City of Amsterdam, restricted to contexts where Amsterdam is the main communicator — Thematiq shipping it to arbitrary Dutch-government instances was exactly the redistribution its notice forbids. It was removed; see CHANGELOG.md for the full list of removed filenames and their 77 one-release legacy-name aliases.

Availability and fallbacks

These icon and logo URLs only resolve while the thematiq app is installed and enabled on the instance. A consumer app that references imagePath('thematiq', 'icons/...') on an instance without thematiq will get a broken image. Consumers MUST either ship a fallback icon or declare a dependency on thematiq in their appinfo/info.xml.

Naming stability

Icon and logo filenames are a public API consumed by other apps. Within an installed source pack version, renaming or removing a bundled icon or logo is a breaking change: it MUST be recorded in the changelog naming both the old and new filename, and img/ICONS.md MUST be regenerated in the same change so the inventory regression test (tests/Unit/IconAssetsTest.php) keeps passing. Upgrading a source dependency that can change pack contents — @conduction/nextcloud-vue (the rvo/open-gemeenten/den-haag packs) or @gouvfr/dsfr (the dsfr pack) — MUST be an explicit, reviewed change whose diff of added/removed keys is listed in the changelog — never a silent regenerate.

Available Icons

View all available icons in the icon documentation or browse the files in:

  • NL-government icons: img/icons/{rvo,open-gemeenten,den-haag}/ (1488 SVG files across 3 sets)
  • DSFR (French-government) icons: img/icons/dsfr/ (1038 SVG files)
  • Legacy aliases: img/icons/*.svg (77 one-release compatibility files — see CHANGELOG.md, removed next minor release)
  • Logos: img/logos/ (23 SVG files, static checked-in huisstijl assets — not build output)

Usage in Nextcloud Apps

<?php
// In your template file
$iconUrl = \OC::$server->getURLGenerator()->imagePath('thematiq', 'icons/den-haag/dh-communication-message.svg');
?>
<img src="<?php p($iconUrl); ?>" alt="Notifications" class="nldesign-icon" />

Method 2: Background Image in CSS

.my-icon {
background-image: url('../../../thematiq/img/icons/den-haag/dh-functional-search.svg');
background-size: contain;
background-repeat: no-repeat;
width: 24px;
height: 24px;
}

Method 3: Inline SVG (For Dynamic Styling)

<?php
// Read and output SVG content directly
$iconPath = \OC::$SERVERROOT . '/apps/thematiq/img/icons/den-haag/dh-communication-message.svg';
if (file_exists($iconPath)) {
echo file_get_contents($iconPath);
}
?>

Vue-based consumers

Vue apps SHOULD import the packs from @conduction/nextcloud-vue directly rather than going through the PHP image-path contract:

import { rvoIcons } from '@conduction/nextcloud-vue/src/icons/rvo.js'
// <CnIconBrowser :url-icons="rvoIcons" … />

Icon Sets

SetDirectoryUpstreamLicenceCount
RVO / ROOSimg/icons/rvo/Rijksdienst voor Ondernemend NederlandCC0-1.01163
OpenGemeentenimg/icons/open-gemeenten/OpenGemeenten Iconenset ("Line" style)CC0-1.0256
Gemeente Den Haagimg/icons/den-haag/Gemeente Den Haag icon setEUPL-1.269
DSFRimg/icons/dsfr/Système de Design de l'État (@gouvfr/dsfr)Etalab-2.01038

Filenames are the pack entry keys (kebab-case slugs already carrying a short set prefix, e.g. rvo-zoek, dh-functional-search, og-zoeken) — confirm the exact filename in img/icons/{set}/ or img/ICONS.md before referencing it.

Legacy Amsterdam filename aliases (one release only)

For exactly this release, 77 of the 344 removed Amsterdam filenames resolve at their old top-level path (img/icons/{Name}.svg) to a byte-identical copy of a replacement icon from the sets above — e.g. Search.svg, Star.svg, House.svg, Mail.svg. See img/ICONS.md for the full alias table. These aliases are removed in the next minor release — do not build new integrations against them; migrate to the set-prefixed path.

Logos

The 23 logos in img/logos/ cover government and municipal organizations. A representative sample:

  • amsterdam.svg - City of Amsterdam logo
  • ggd-amsterdam.svg - GGD Amsterdam logo
  • stadsarchief.svg - Amsterdam City Archives
  • stadsbank-van-lening.svg - Stadsbank van Lening
  • museum_weesp.svg - Museum Weesp
  • vga-verzekeringen.svg - VGA Verzekeringen
  • rijkshuisstijl.svg, vng.svg, provincie-zuid-holland.svg, and other municipal logos (Utrecht, Rotterdam, Leiden, Nijmegen, Tilburg, Hoorn, Epe, and more)

Browse img/logos/ for the complete set. These are static, checked-in huisstijl assets tied to token-sets.json theming.logo entries — scripts/build-icons.js never creates, modifies, or deletes anything under img/logos/.

Styling Icons

Icons are designed to work with the NL Design System color tokens:

.nldesign-icon {
width: 24px;
height: 24px;
/* Apply NL Design colors */
filter: invert(var(--nldesign-icon-invert, 0));
}

/* For dark backgrounds */
.nldesign-icon--light {
filter: invert(1);
}

Examples

Button with Icon

<button class="button-vue--vue-primary">
<img src="<?php p(\OC::$server->getURLGenerator()->imagePath('thematiq', 'icons/rvo/rvo-plus.svg')); ?>"
alt="" class="button-icon" />
Toevoegen
</button>
<li>
<a href="/path">
<img src="<?php p(\OC::$server->getURLGenerator()->imagePath('thematiq', 'icons/den-haag/dh-objects-house.svg')); ?>"
alt="Home icon" />
Home
</a>
</li>

Status Indicator

<div class="status-indicator">
<img src="<?php p(\OC::$server->getURLGenerator()->imagePath('thematiq', 'icons/den-haag/dh-informational-checkcircle.svg')); ?>"
alt="Success" class="status-icon status-icon--success" />
<span>Voltooid</span>
</div>

Browser Compatibility

All icons are SVG format and support:

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • IE11+ (with appropriate polyfills)
  • Mobile browsers (iOS Safari, Chrome Mobile)

Accessibility

When using icons, always provide appropriate alt text or aria-labels:

<!-- Decorative icon (no alt needed) -->
<img src="<?php p($iconUrl); ?>" alt="" aria-hidden="true" />

<!-- Functional icon (provide alt text) -->
<img src="<?php p($iconUrl); ?>" alt="Search" />

<!-- Icon button (use aria-label) -->
<button aria-label="Close dialog">
<img src="<?php p($iconUrl); ?>" alt="" />
</button>

License

Icons are sourced from @conduction/nextcloud-vue and @gouvfr/dsfr:

The proprietary @amsterdam/design-system-assets package is not a dependency of this app and no shipped asset derives from it.

Resources

Building Icons

Icons are automatically built from @conduction/nextcloud-vue's and @gouvfr/dsfr's bundled icon packs. To rebuild:

npm run build:icons

This decodes the data-URI icon packs at node_modules/@conduction/nextcloud-vue/src/icons/{rvo,openGemeenten,denHaag}.js into standalone SVG files under img/icons/{set}/, copies every DSFR source SVG (@gouvfr/dsfr/dist/icons/**/*.svg, falling back to the pre-fetched .dsfr-src/icons/ scratch source when the package cannot be installed) into img/icons/dsfr/{basename}.svg, materializes the one-release legacy aliases from scripts/icon-aliases.json, and regenerates img/ICONS.md. It never touches img/logos/.

Theme-Switchable Icon Packs

Beyond the fixed imagePath('thematiq', 'icons/{set}/{key}.svg') contract above, the icon pack an app should serve can also travel with the active design system:

  • design-systems.json carries an optional icon_pack field per design system (string or ordered array): nldesign -> ["rvo", "open-gemeenten", "den-haag"], lasuite -> ["dsfr"]. A design system without the field serves no pack (Nextcloud stock icons).
  • DesignSystemService::resolveActiveIconPacks(tokenSetId) resolves the chain active token set -> its design_system -> that design system's icon_pack, honoring an appconfig icon_pack admin override (occ config:app:set thematiq icon_pack --value=dsfr) when it names a real pack directory.
  • DesignSystemService::resolveIconPath($name, $tokenSetId) returns the imagePath-relative path of $name in the first pack of the resolved list that contains it, or null.
  • The resolved list is advertised on the public capability: /ocs/v2.php/cloud/capabilities -> capabilities.nldesign.iconPacks.

See openspec/specs/icon-packs/spec.md for the full contract. Honest limitation: this only switches Thematiq's own bundled icon assets — it does not force-replace Nextcloud core's built-in icon set beyond what the active theme's CSS already restyles.