diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000..2edeafb
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+20
\ No newline at end of file
diff --git a/.storybook/DocsTemplate.mdx b/.storybook/DocsTemplate.mdx
new file mode 100644
index 0000000..0066ca2
--- /dev/null
+++ b/.storybook/DocsTemplate.mdx
@@ -0,0 +1,9 @@
+import { Meta, Title, Subtitle, Stories } from "@storybook/blocks";
+
+
+
+
+
+
+
+
diff --git a/.storybook/StoriesOnlyTemplate.mdx b/.storybook/StoriesOnlyTemplate.mdx
deleted file mode 100644
index f5eec8b..0000000
--- a/.storybook/StoriesOnlyTemplate.mdx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Meta, Title, Primary, Controls, Stories } from "@storybook/blocks";
-
-
-
-
-
-
diff --git a/.storybook/main.ts b/.storybook/main.ts
index 1ebc717..730dd9d 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -5,6 +5,9 @@ const config: StorybookConfig = {
framework: "@storybook/web-components-vite",
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
addons: ["@storybook/addon-essentials"],
+ docs: {
+ autodocs: true,
+ },
async viteFinal(config) {
const { mergeConfig } = await import("vite");
return mergeConfig(config, {
diff --git a/.storybook/preview.ts b/.storybook/preview.ts
index 541bbab..8db52e1 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.ts
@@ -1,15 +1,17 @@
import type { Preview } from "@storybook/web-components";
import "../src/scss/iati.scss";
+import DocsTemplate from "./DocsTemplate.mdx";
const preview: Preview = {
parameters: {
options: {
storySort: {
- order: ["Core", "Components"],
+ order: ["Get Started", "Core", "Components", "Layout"],
},
},
docs: {
+ page: DocsTemplate,
source: {
format: "dedent",
},
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 013d63b..f82015b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,4 +22,9 @@ BREAKING CHANGE: removes the '.subcomponent' class.
### What is a breaking change?
-A breaking change is any "incompatible API change". In the context of this design system, the API consists of CSS classes and SASS variables/functions/mixins etc. Any change which removes or renames a part of the API must be labelled a breaking change.
+A breaking change is any "incompatible API change". In the context of this design system, the API consists of CSS classes and SASS variables/functions/mixins etc.
+
+Breaking changes include the following:
+
+- Any change which removes or renames a part of the API must be labelled a breaking change.
+- Any change which would require a downstream consumer to change their HTML.
diff --git a/README.md b/README.md
index 31b4ef1..e0677fc 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,81 @@
# IATI Design System
-## Usage
+## What is the IATI Design System?
-### NPM
+The IATI Design System is a set of reusable styles and components which should be used in IATI web products, along with guidance on how to use them.
-```
-npm install iati-design-system
-```
+## How do I use the IATI Design System?
-### CDN
+### CDN (Recommended)
-```
-https://cdn.jsdelivr.net/npm/iati-design-system@[X.Y.Z]/dist/css/iati.css
+The recommended way to use the design system in an IATI product is by including the CSS from the CDN, using the url below, replacing `` with the version you would like to use:
+
+```code
+https://cdn.jsdelivr.net/npm/iati-design-system@/dist/css/iati.min.css
```
-## Development
+This project is versioned using [Semantic Versioning](https://semver.org/). Versions can be specified as a major, minor, or patch version e.g. `1`, `1.2`, or `1.2.3`. The latest version is shown on the [GitHub releases page](https://github.com/IATI/design-system/releases). We recommend fixing to a specific patch version so that upgrades can be checked explicitly before deployment, but as a minimum you should fix to a major version to prevent unexpected breaking changes.
-Start storybook:
+To include the CSS in a HTML project, add the following code inside the `` of your HTML pages:
+```html
+
```
-npm start
+
+Once this link is included, core styles will be applied, and all component and layout CSS classes will be available to apply to HTML elements, for example the `.iati-button` class:
+
+```html
+
```
-## Production build
+### NPM (Optional)
-Build CSS:
+It is also possible to include the design system in a [Sass](https://sass-lang.com/) project.
-```
-npm run build
+First install with npm:
+
+```code
+npm install iati-design-system
```
-Build storybook:
+Then import the package in your `.scss` file. The [Node.js Package Importer](https://sass-lang.com/documentation/at-rules/use/#node-js-package-importer) is required to use this syntax.
+```css
+@use "pkg:iati-design-system";
```
-npm run build:storybook
-```
+
+## How do I contribute to the IATI Design System?
+
+### Prerequisites
+
+#### Node v20
+
+IATI Design System requires Node v20. We recommend installing [Node Version Manager](https://github.com/nvm-sh/nvm) and running the command `nvm use` to use the Node version set in the `.nvmrc` file at the root of the project.
+
+### Running locally
+
+To run Storybook locally, take the following steps:
+
+1. Install dependencies: `npm install`
+2. Start Storybook: `npm start`
+
+You will see live updates in the browser when you update styles or stories.
+
+### Production build
+
+#### CSS
+
+To check the CSS production build, take the following steps:
+
+1. Build the CSS: `npm run build`
+2. View the CSS file: `./dist/css/iati.css`.
+
+#### Storybook
+
+The check the Storybook production build, take the following steps:
+
+1. Build the Storybook: `npm run build:storybook`
+2. Serve the Storybook: `npm run serve:storybook`
diff --git a/package.json b/package.json
index 2cdf49e..6275b64 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"start": "storybook dev -p 6006",
"build": "sass --pkg-importer=node --no-source-map --style=expanded src/scss:dist/css",
"build:storybook": "storybook build",
+ "serve:storybook": "npx http-server -o ./storybook-static",
"lint": "npm run lint:eslint && npm run lint:prettier",
"lint:eslint": "eslint",
"lint:prettier": "prettier . --check",
diff --git a/src/scss/base/_index.scss b/src/scss/base/_index.scss
index d70ed04..85802a3 100644
--- a/src/scss/base/_index.scss
+++ b/src/scss/base/_index.scss
@@ -1,2 +1,3 @@
@forward "normalize";
@forward "reset";
+@forward "mixins";
diff --git a/src/scss/base/_mixins.scss b/src/scss/base/_mixins.scss
new file mode 100644
index 0000000..3b0ce85
--- /dev/null
+++ b/src/scss/base/_mixins.scss
@@ -0,0 +1,25 @@
+@use "../tokens/color" as *;
+@use "../tokens/spacing" as *;
+
+@mixin page-width-container {
+ width: 100%;
+ max-width: $page-width-max;
+ margin-left: auto;
+ margin-right: auto;
+ padding: $padding-block;
+}
+
+@mixin columns {
+ display: flex;
+ flex-flow: row nowrap;
+ justify-content: space-between;
+ align-items: center;
+ column-gap: $padding-block;
+ row-gap: $padding-block;
+}
+
+@mixin unstyled-list {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
diff --git a/src/scss/base/_reset.scss b/src/scss/base/_reset.scss
index 08f0941..390d2eb 100644
--- a/src/scss/base/_reset.scss
+++ b/src/scss/base/_reset.scss
@@ -16,3 +16,18 @@ strong {
em {
font-style: italic;
}
+
+html {
+ height: 100%;
+}
+
+body {
+ height: 100%;
+ display: flex;
+ flex-flow: column;
+}
+
+a:has(i),
+a:has(img) {
+ text-decoration: none;
+}
diff --git a/src/scss/components/_index.scss b/src/scss/components/_index.scss
index 5ccec41..fbea8e9 100644
--- a/src/scss/components/_index.scss
+++ b/src/scss/components/_index.scss
@@ -1 +1,6 @@
+@forward "button/button";
@forward "callout/callout";
+@forward "card/card";
+@forward "icon/icon";
+@forward "search-bar/search-bar";
+@forward "table/table";
diff --git a/src/scss/components/button/_button.scss b/src/scss/components/button/_button.scss
new file mode 100644
index 0000000..f084647
--- /dev/null
+++ b/src/scss/components/button/_button.scss
@@ -0,0 +1,14 @@
+@use "../../tokens/color" as *;
+@use "../../tokens/spacing" as *;
+
+.iati-button {
+ background-color: $color-teal-90;
+ border: none;
+ color: white;
+ text-transform: uppercase;
+ padding: $padding-block;
+
+ &:hover {
+ background-color: $color-teal-80;
+ }
+}
diff --git a/src/scss/components/button/button.stories.ts b/src/scss/components/button/button.stories.ts
new file mode 100644
index 0000000..f2d362a
--- /dev/null
+++ b/src/scss/components/button/button.stories.ts
@@ -0,0 +1,14 @@
+import type { Meta, StoryObj } from "@storybook/web-components";
+
+import { html } from "lit";
+
+const meta: Meta = {
+ title: "Components/Button",
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Button: Story = {
+ render: () => html``,
+};
diff --git a/src/scss/components/callout/_callout.scss b/src/scss/components/callout/_callout.scss
index 0f60598..9948d42 100644
--- a/src/scss/components/callout/_callout.scss
+++ b/src/scss/components/callout/_callout.scss
@@ -1,4 +1,5 @@
@use "../../tokens/color" as *;
+@use "../../tokens/font" as *;
@use "../../tokens/spacing" as *;
.iati-callout {
@@ -39,6 +40,6 @@
&__title {
font-weight: bold;
font-size: 1.2rem;
- line-height: 2;
+ line-height: $line-height-body;
}
}
diff --git a/src/scss/components/callout/callout.stories.ts b/src/scss/components/callout/callout.stories.ts
index 429f418..abbb26e 100644
--- a/src/scss/components/callout/callout.stories.ts
+++ b/src/scss/components/callout/callout.stories.ts
@@ -1,16 +1,8 @@
import type { Meta, StoryObj } from "@storybook/web-components";
import { html } from "lit";
-import Template from "../../../../.storybook/StoriesOnlyTemplate.mdx";
-
const meta: Meta = {
title: "Components/Callout",
- tags: ["autodocs"],
- parameters: {
- docs: {
- page: Template,
- },
- },
};
export default meta;
diff --git a/src/scss/components/card/_card.scss b/src/scss/components/card/_card.scss
new file mode 100644
index 0000000..a93aa4e
--- /dev/null
+++ b/src/scss/components/card/_card.scss
@@ -0,0 +1,31 @@
+@use "../../tokens/color" as *;
+@use "../../tokens/spacing" as *;
+
+.iati-card {
+ box-shadow: 0 4px 5px $color-grey-20;
+ background-color: white;
+ border-top: $border-width solid $color-teal-90;
+ padding: $padding-block;
+
+ & :first-child {
+ margin-top: 0;
+ }
+
+ & :last-child {
+ margin-bottom: 0;
+ }
+
+ &__title {
+ margin: 0;
+ font-weight: bold;
+ font-size: 1.2rem;
+ }
+
+ &__subtitle {
+ color: $color-teal-90;
+ font-size: 0.8rem;
+ font-weight: bold;
+ margin: 0;
+ text-transform: uppercase;
+ }
+}
diff --git a/src/scss/components/card/card.stories.ts b/src/scss/components/card/card.stories.ts
new file mode 100644
index 0000000..7d3d2c3
--- /dev/null
+++ b/src/scss/components/card/card.stories.ts
@@ -0,0 +1,20 @@
+import type { Meta, StoryObj } from "@storybook/web-components";
+
+import { html } from "lit";
+
+const meta: Meta = {
+ title: "Components/Card",
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Card: Story = {
+ render: () => html`
+
diff --git a/src/start.mdx b/src/start.mdx
index 9ff0e1a..98d0887 100644
--- a/src/start.mdx
+++ b/src/start.mdx
@@ -1,36 +1,7 @@
-import { Meta, Title } from "@storybook/blocks";
+import { Markdown, Meta, Title } from "@storybook/blocks";
-
-
-
IATI Design System
-
-## Installation
-
-There are multiple ways to use the IATI Design System CSS in your product:
-
-### Option 1: CDN
-
-1. Add a link to the CSS in the `` section of your HTML page:
+import ReadMe from "../README.md?raw";
- ```html
-
-
-
- ```
-
-### Option 2: NPM
-
-1. Install the package with NPM:
-
- ```
- npm install iati-design-system
- ```
-
-2. The CSS can be imported from the following location:
+
- ```javascript
- import "iati-design-system/dist/css/iati.css";
- ```
+{ReadMe}