This Unplugin aims to get developers started quickly with developing frontend components and installs both icons and CSS for the WebBS design system.
Since the Unplugin only offers all the CSS, the markup needs to be built separately. This is intentional. Since frameworks such as Vue, Svelte, React, Twig, or Blade differ wildly in terms of template syntax, providing a standardised way of including components is next to impossible. We, therefore, settled on providing the CSS code and all assets necessary to create components but not the components themselves. The markup for the components can be found in Storybook.
The Unplugin provides all the necessary code to create a website with the look and feel of www.bs.ch. It's based on Tailwind. To get afull picture of the Digital Design System, please refer to the Storybook instance.
This package has several dependencies and peer dependencies.
npm i @kanton-basel-stadt/designsystem
Also, you need to install all peer dependencies for your framework:
For Vite, install
vite
For Webpack, install
webpack
css-loader
mini-css-extract-plugin
postcss-loader
style-loader
For Nuxt, install
@vue/compiler-sfc
@nuxt/kit
@nuxt/schema
For Rollup, install
rollup
rollup-plugin-postcss
For ESBuild, install
esbuild
To add proper type support for your framework of choice, you may also need to add TypeScript types to your tsconfig:
For example, to add types to React, you need to add the following to your tsconfig.json
:
{
"compilerOptions": {
"types": [
"@kanton-basel-stadt/designsystem/types/react"
]
}
}
There are types for Astro, Preact, Qwik, React, Svelte, Svelte3, Svelte4, Vue 2.7, Vue3+ and Web components.
Vite
import KantonBSDesignsystemPlugin from '@kanton-basel-stadt/designsystem/vite'
export default defineConfig({
plugins: [
KantonBSDesignsystemPlugin({ /* Options */ }),
],
server: {
fs: {
strict: false,
}
},
})
Example: Can be found in examples/vite-vanillla
.
Rollup
// rollup.config.js
import KantonBSDesignsystemPlugin from '@kanton-basel-stadt/designsystem/dist/rollup.cjs'
export default {
input: 'main.js',
output: { format: 'es', file: 'dist/bundle.js' },
plugins: [
KantonBSDesignsystemPlugin.default({
tailwindOptions: {
targetDir: `${process.cwd()}/dist` // Necessary for the output of font files to work
}
}),
],
}
Example: Can be found in examples/rollup
.
Webpack
// webpack.config.js
module.exports = {
/* ... */
plugins: [
require('@kanton-basel-stadt/designsystem/webpack').default({ /* Options */ })
],
}
Example: Can be found in examples/webpack5
.
Nuxt
// nuxt.config.js
export default defineNuxtConfig({
modules: [
['@kanton-basel-stadt/designsystem/nuxt', {
iconOptions: {
compiler: 'vue3',
}
}],
],
})
This module works for both Nuxt 2 and Nuxt Vite
Example: Can be found in examples/nuxt
.
Vue CLI
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
require('@kanton-basel-stadt/designsystem/webpack')({
iconOptions: {
compiler: 'vue3',
},
}),
],
},
}
esbuild
import Starter from '@kanton-basel-stadt/designsystem/esbuild'
// esbuild.config.js
import { build } from 'esbuild'
build({
plugins: [KantonBSDesignsystemPlugin()],
loader: {
// Necessary for the font files to work
'.woff': 'file',
'.woff2': 'file',
}
})
Example: Can be found in examples/esbuild
.
Astro
// astro.config.mjs
import KantonBSDesignsystemPlugin from '@kanton-basel-stadt/designsystem/astro'
// https://astro.build/config
export default defineConfig({
integrations: [
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'astro',
}
})
],
})
Example: Can be found in examples/astro
.
Vue3 + Vite
// vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import KantonBSDesignsystemPlugin from '@kanton-basel-stadt/designsystem/vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'vue3',
},
}),
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
fs: {
strict: false,
}
},
})
Example: Can be found in examples/vue-vite
.
The options of the plugin are as follows:
import type { Config as TailwindConfig } from 'tailwindcss'
import type { Options as UnpluginIconsOptions } from 'unplugin-icons'
export interface Options {
iconOptions?: UnpluginIconsOptions
tailwindOptions?: {
targetDir?: string
config?: Partial<TailwindConfig>
}
}
With iconOptions
being the options described in the unplugin-icons docs and
tailwindOptions
being used to configure some Tailwind behaviour. Please note that the targetDir
option only works for
ESBuild, Webpack and Rollup.
To overwrite parts of the Tailwind config, specify the keys in the plugin options.
For example, if your templates are located elsewhere than your build tool configuration, you may specify their path as follows:
// ...
KantonBSDesignsystemPlugin({
// ...
tailwindOptions: {
config: {
content: [
// Change path and file endings
'/path/to/your/template/folder/**/*.{html,js}',
],
}
}
})
In the above example, Tailwind will look for any HTML and JS file in /path/to/your/template/folder/
and its
subdirectories to find Tailwind classes to include in the built CSS.
You may also overwrite any other part of the config, such as the theme (to add things, such as additional colours, font sizes, etc.), the safelist (to guarantee certain classes to be present in the built CSS), to add plugins, etc.
The entire config is deep-merged with the standard config.
Please keep in mind, that any change to the theme should adhere to the design specifications. Use custom components
over theme changes, and, if the value is only used once or twice, use arbitrary value syntax (i.e. bg-[#ff0000]
).
This unplugin uses unplugin-icons as a nested plugin. All options of this plugin apply, but they are set to sensible defaults in order to work correctly with the supplied icon set.
Please keep in mind: In the examples specified above, the correct icon compilers are already configured.
Use the following code snippets to include the icon pen
. All other icons can be found in src/core/assets/symbols/
of this repository.
Please see Storybook for a detailed list of all icons.
The following examples are what is implemented in the current examples. Since unplugin-icons also offers support for
various frontend frameworks, the compiler
option may need to be different from the default configuration. For that,
please consult the official unplugin-icons documentation.
Astro
---
import IconSymbolPen from '@kanton-basel-stadt/designsystem/icons/symbol/pen'
---
<IconSymbolPen />
Example: Can be found in examples/astro
.
Nuxt/Vue
<script lang="ts" setup>
import IconSymbolPen from '@kanton-basel-stadt/designsystem/icons/symbol/pen'
</script>
<template>
<div>
<IconSymbolPen />
</div>
</template>
Example: Can be found in examples/nuxt
.
ESBuild, Webpack, Vite, Rollup
In your bundle file:
import '@kanton-basel-stadt/designsystem/icons/symbol/pen'
And then, in your HTML file:
<icon-symbol-pen />
Example: Can be found in examples/nuxt
.
To use icons with your framework of choice, you may need to specify a compiler. The unplugin defaults to web components, which work with most non-framework related build tools, such as standalone Webpack or standalone Vite. However, if you're using one of the following frameworks, you need to specify the compiler in the unplugin options with the following patterns:
Vue 3 / Vue 2.7+
Requires peer dependency @vue/compiler-sfc
.
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'vue3',
},
})
Vue 2 (only versions <2.7)
Requires peer dependency vue-template-compiler
.
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'vue2',
},
})
React
Requires peer dependencies @svgr/core
and its plugin @svgr/plugin-jsx
.
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'jsx',
jsx: 'react',
},
})
Preact
Requires peer dependencies @svgr/core
and its plugin @svgr/plugin-jsx
.
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'jsx',
jsx: 'preact',
},
})
Solid
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'solid'
},
})
Svelte
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'svelte'
},
})
Astro
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'astro'
},
})
qwik
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'qwik'
},
})
qwik + JSX
Requires peer dependencies @svgr/core
and its plugin @svgr/plugin-jsx
.
KantonBSDesignsystemPlugin({
iconOptions: {
compiler: 'jsx',
jsx: 'qwik',
},
})
Please consult the documentation of unplugin-icons for further information on types, etc.
This unplugin uses PostCSS and Tailwind, both preconfigured. So, any tree-shaking of any Tailwind classes will be handled.
To include the framework in your CSS, apply the top of your CSS:
@import '@kanton-basel-stadt/designsystem/assets/css/tailwind.css';
/* Apply custom CSS here */
Please keep in mind that any additional CSS should be kept within @layer components { /* ... */ }
, so Tailwind knows
what to do with it.
If you want to simply use Tailwind as is with no additional CSS, you can do so by applying the desired classes to your HTML elements. For that, please consult the official Tailwind documentation, Storybook and the Tailwind config of this repository. Please keep in mind that Storybook is currently not up to date with the latest implementations, especially when it comes to icons. They may need some adjustment.
To develop inside the DDS, it is recommended to use Node v20 and NPM.
To get started, install all dependencies. To test your changes manually, you can use various examples in the examples/
folder of the project that use the DDS. You need to install their dependencies as well. However, for your changes to
take effect, you need to build the DDS using npm run build
. Since the examples install the DDS via symlink, all changes
built are available immediately without the need for a release or an additional run of npm install
.
Before you do a release, make sure your changes...
- Work as intended (by testing in
examples/
) - Pass all existing and additional tests (by executing
npm run test
it is recommended to add tests to newly added code) - Adhere to the coding standards (by executing
npm run lint
andnpm run lint:fix
)
To create a new release (i.e. after you added changes) follow these steps:
- Make sure you have push rights to GitHub and access rights to the project on npmjs.
- Make sure you're logged in on npmjs using
npm login
. - Execute the following:
git commit -a -m "YOUR COMMIT MESSAGE HERE"
git push -u origin main
npm run lint:fix
npm run build
npm run release
Now, please tell users to update the package.
Please feel free to also submit pull requests and/or issues.
To execute unit tests, run the following command:
npm run test unit
The end-to-end tests set up actual build tools (Astro, esbuild, Nuxt, rollup, Vite and Webpack) with the unplugin, build them, serve their output and compare the result to a baseline screenshot to ensure the correct loading of icons, CSS, and font files.
To execute the tests, build the unplugin first:
npm run build
Then execute the following command:
npm run test e2e
Note: Please keep in mind that installation, building, starting the web server and the Chromium instance might take a while.
If any of the tests fail and want to see how the screenshot taken differs from the baseline, you can execute the tests with a flag to dump the diffs:
DUMP_DIFFS=1 npm run test e2e
This will generate PNGs named after the build tools (for example, diff_astro.png
) in the test/e2e/
folder. These are
ignored by Git. When you open these files, every red and yellow pixel is a pixel difference. If there are no red and yellow pixels,
then the baseline image and the screenshot taken overlap perfectly.
To check if your code adheres to the coding standards, you can execute ESLint by running:
npm run lint
And to automatically fix any automatically fixable errors, run:
npm run lint:fix
In the examples/
folder, you can find playgrounds for various different frameworks. They function much in the same way
the examples in the end-to-end tests do, with the exception that they may contain differing DOM and extra CSS.
To test the Unplugin's various parts and execute end-to-end tests for various build tools, you can execute the tests:
In order to run them, head to the desired example and install dependencies:
npm install
Note: Please keep in mind that the Unplugin is installed via symlink for ease of development, so each change you do,
once built with npm run build
executed in the unplugin project root, is directly reflected in the installed package in
the example.
If you need to add new icons, you can place them in the folder src/core/assets/symbols/
. Make sure any fill or stroke
attributes use currentColor
. Nothing else is needed, the icon will be available as a component upon the next execution
of npm run build
. The newly built src/core/configs/icons-index.ts
needs to be part of the release, otherwise the new
icons will not be available to users.
To execute the icon building separately, you can run the following command:
npm run build:generate-icons-index
If you'd like to contribute, please open an issue or merge request on GitHub. The core team can then help you get started.