diff --git a/examples/result-summary-component/.gitignore b/examples/result-summary-component/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/examples/result-summary-component/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/result-summary-component/.npmrc b/examples/result-summary-component/.npmrc
new file mode 100644
index 00000000..6b5f38e8
--- /dev/null
+++ b/examples/result-summary-component/.npmrc
@@ -0,0 +1,2 @@
+save-exact = true
+package-lock = false
diff --git a/examples/result-summary-component/README.md b/examples/result-summary-component/README.md
new file mode 100644
index 00000000..a3b1ad73
--- /dev/null
+++ b/examples/result-summary-component/README.md
@@ -0,0 +1,23 @@
+# Frontend Mentor Result Summary Component
+
+Here is the implementation in [Bau.js](https://github.com/grucloud/bau) of the [Frontend Mentor Result Summary Component code challenge](https://www.frontendmentor.io/challenges/results-summary-component-CE_K6s0maV)
+
+## Workflow
+
+Install the dependencies:
+
+```sh
+npm install
+```
+
+Start a development server:
+
+```sh
+npm run dev
+```
+
+Build a production version:
+
+```sh
+npm run build
+```
diff --git a/examples/result-summary-component/index.html b/examples/result-summary-component/index.html
new file mode 100644
index 00000000..6fbe9613
--- /dev/null
+++ b/examples/result-summary-component/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ Result Summary Component | FrontendMentor
+
+
+
+
+
+
diff --git a/examples/result-summary-component/package.json b/examples/result-summary-component/package.json
new file mode 100644
index 00000000..a16914dc
--- /dev/null
+++ b/examples/result-summary-component/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "frontendmentor-result-summary-component",
+ "private": true,
+ "version": "0.85.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "typescript": "^5.0.2",
+ "vite": "^5.2.11"
+ },
+ "dependencies": {
+ "@grucloud/bau": "^0.85.0",
+ "@grucloud/bau-css": "^0.85.0",
+ "@grucloud/bau-ui": "^0.85.0"
+ }
+}
diff --git a/examples/result-summary-component/public/assets/images/favicon-32x32.png b/examples/result-summary-component/public/assets/images/favicon-32x32.png
new file mode 100644
index 00000000..1e2df7f0
Binary files /dev/null and b/examples/result-summary-component/public/assets/images/favicon-32x32.png differ
diff --git a/examples/result-summary-component/public/assets/images/icon-memory.svg b/examples/result-summary-component/public/assets/images/icon-memory.svg
new file mode 100644
index 00000000..8e110660
--- /dev/null
+++ b/examples/result-summary-component/public/assets/images/icon-memory.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/result-summary-component/public/assets/images/icon-reaction.svg b/examples/result-summary-component/public/assets/images/icon-reaction.svg
new file mode 100644
index 00000000..4317d212
--- /dev/null
+++ b/examples/result-summary-component/public/assets/images/icon-reaction.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/result-summary-component/public/assets/images/icon-verbal.svg b/examples/result-summary-component/public/assets/images/icon-verbal.svg
new file mode 100644
index 00000000..c975df5d
--- /dev/null
+++ b/examples/result-summary-component/public/assets/images/icon-verbal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/result-summary-component/public/assets/images/icon-visual.svg b/examples/result-summary-component/public/assets/images/icon-visual.svg
new file mode 100644
index 00000000..b1d2a564
--- /dev/null
+++ b/examples/result-summary-component/public/assets/images/icon-visual.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/result-summary-component/src/data.json b/examples/result-summary-component/src/data.json
new file mode 100644
index 00000000..257b468d
--- /dev/null
+++ b/examples/result-summary-component/src/data.json
@@ -0,0 +1,22 @@
+[
+ {
+ "category": "Reaction",
+ "score": 80,
+ "icon": "./assets/images/icon-reaction.svg"
+ },
+ {
+ "category": "Memory",
+ "score": 92,
+ "icon": "./assets/images/icon-memory.svg"
+ },
+ {
+ "category": "Verbal",
+ "score": 61,
+ "icon": "./assets/images/icon-verbal.svg"
+ },
+ {
+ "category": "Visual",
+ "score": 72,
+ "icon": "./assets/images/icon-visual.svg"
+ }
+]
diff --git a/examples/result-summary-component/src/main.ts b/examples/result-summary-component/src/main.ts
new file mode 100644
index 00000000..e621ffb2
--- /dev/null
+++ b/examples/result-summary-component/src/main.ts
@@ -0,0 +1,20 @@
+import { createContext, type Context } from "@grucloud/bau-ui/context";
+import resultSummary from "./resultSummary";
+
+import "./style.css";
+
+const context = createContext();
+
+const app = (context: Context) => {
+ const { bau } = context;
+ const { main } = bau.tags;
+
+ const ResultSummary = resultSummary(context);
+
+ return function () {
+ return main(ResultSummary());
+ };
+};
+
+const App = app(context);
+document.getElementById("app")?.replaceChildren(App());
diff --git a/examples/result-summary-component/src/resultSummary.ts b/examples/result-summary-component/src/resultSummary.ts
new file mode 100644
index 00000000..d3bdb282
--- /dev/null
+++ b/examples/result-summary-component/src/resultSummary.ts
@@ -0,0 +1,195 @@
+import { type Context } from "@grucloud/bau-ui/context";
+import data from "./data.json";
+
+const score = 76;
+
+export default function (context: Context) {
+ const { bau, css } = context;
+ const { h1, h2, div, p, article, section, button, ul, li, span, img } =
+ bau.tags;
+ const className = css`
+ max-width: 500px;
+ margin: auto;
+ display: grid;
+ grid-template-columns: minmax(auto, 350px) minmax(auto, 350px);
+ grid-template-rows: 1fr;
+
+ @media (max-width: 500px) {
+ grid-template-columns: 1fr;
+
+ border-radius: 0;
+ }
+ border-radius: 0.6rem;
+ box-shadow: 0 0.5rem 2rem 0 rgba(0, 0, 0, 0.1);
+ section {
+ display: flex;
+ flex-direction: column;
+ padding: 1rem;
+ gap: 0.7rem;
+ &.result {
+ align-items: center;
+ border-radius: 0.6rem;
+ @media (max-width: 600px) {
+ flex-direction: column;
+ border-radius: 0 0 0.6rem 0.6rem;
+ }
+ background: linear-gradient(
+ var(--Light-slate-blue),
+ var(--Light-royal-blue)
+ );
+
+ min-width: 250px;
+
+ h1 {
+ color: var(--color);
+ }
+ h2 {
+ color: var(--white);
+ }
+ p {
+ color: var(--color);
+ text-align: center;
+ padding: 0 1rem;
+ }
+ .score-container {
+ color: var(--white);
+ background: linear-gradient(var(--Violet-blue), var(--Persian-blue));
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border-radius: 50%;
+ aspect-ratio: 1;
+ padding: 1.5rem;
+ .score {
+ color: var(--white);
+ font-size: 3rem;
+ font-weight: bold;
+ line-height: 3rem;
+ }
+ .score-total {
+ font-size: 0.7rem;
+ color: var(--color);
+ }
+ }
+ }
+ &.summary {
+ min-width: 250px;
+ button {
+ width: 100%;
+ font-weight: 500;
+ font-size: 1rem;
+ padding: 0.6rem 0;
+ color: white;
+ border-radius: 1rem;
+ background-color: var(--btn-bg);
+ border: none;
+ outline: none;
+ cursor: pointer;
+ &:hover {
+ background: linear-gradient(
+ var(--Light-slate-blue),
+ var(--Light-royal-blue)
+ );
+ }
+ }
+ }
+ ul {
+ padding: 0;
+ flex-grow: 1;
+ li {
+ list-style: none;
+ padding: 0.7rem 0.5rem;
+ margin: 0.5rem 0rem;
+ border-radius: 0.3rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ &:nth-child(1) {
+ color: hsl(0, 100%, 67%);
+ background: hsla(0, 100%, 67%, 0.05);
+ }
+ &:nth-child(2) {
+ color: hsl(39, 100%, 56%);
+ background: hsla(39, 100%, 56%, 0.05);
+ }
+ &:nth-child(3) {
+ color: hsl(166, 100%, 37%);
+ background: hsla(166, 100%, 37%, 0.05);
+ }
+ &:nth-child(4) {
+ color: hsl(234, 85%, 45%);
+ background: hsla(234, 85%, 45%, 0.05);
+ }
+ .category {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ }
+ .category {
+ font-weight: 700;
+ }
+ .score {
+ color: hsl(224, 30%, 27%);
+ font-weight: 700;
+ padding-right: 0.3rem;
+ }
+ .score-total {
+ color: hsla(224, 30%, 27%, 0.5);
+ }
+ }
+ }
+ }
+ `;
+
+ const scoreState = bau.state(score);
+
+ var count = 0;
+ var interval = setInterval(() => {
+ count++;
+ scoreState.val = count;
+ if (count >= score) {
+ clearInterval(interval);
+ }
+ }, 5);
+
+ return function resultSummary() {
+ return article(
+ { class: className },
+ section(
+ { class: "result" },
+ h1("Result"),
+
+ div(
+ { class: "score-container" },
+ div({ class: "score" }, scoreState),
+ div({ class: "score-total" }, "of 100")
+ ),
+ h2("Great"),
+ p(
+ "You scored higher than 65% of the people who have taken these tests."
+ )
+ ),
+ section(
+ { class: "summary" },
+ h1("Summary"),
+ ul(
+ data.map(({ category, score, icon }) =>
+ li(
+ div(
+ { class: "category" },
+ img({ src: icon }),
+ span({ class: "category" }, category)
+ ),
+ div(
+ span({ class: "score" }, score),
+ span({ class: "score-total" }, "/100")
+ )
+ )
+ )
+ ),
+ button("Continue")
+ )
+ );
+ };
+}
diff --git a/examples/result-summary-component/src/style.css b/examples/result-summary-component/src/style.css
new file mode 100644
index 00000000..b3241a20
--- /dev/null
+++ b/examples/result-summary-component/src/style.css
@@ -0,0 +1,28 @@
+@import url("https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@500;700;800&display=swap");
+
+* {
+ margin: 0;
+ box-sizing: border-box;
+}
+
+:root {
+ --Light-slate-blue: hsl(252, 100%, 67%);
+ --Light-royal-blue: hsl(241, 81%, 54%);
+ --Violet-blue: hsla(256, 72%, 46%, 1);
+ --Persian-blue: hsla(241, 72%, 46%, 0);
+ --white: hsl(0, 0%, 100%);
+ --Pale-blue: hsl(221, 100%, 96%);
+ --color: hsl(241, 100%, 89%);
+ --btn-bg: hsl(224, 30%, 27%);
+}
+
+body {
+ font-family: "Hanken Grotesk", sans-serif;
+ min-height: 100vh;
+ display: grid;
+ place-items: center;
+
+ @media (max-width: 600px) {
+ place-items: flex-start;
+ }
+}
diff --git a/examples/result-summary-component/src/vite-env.d.ts b/examples/result-summary-component/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/examples/result-summary-component/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/result-summary-component/tsconfig.json b/examples/result-summary-component/tsconfig.json
new file mode 100644
index 00000000..75abdef2
--- /dev/null
+++ b/examples/result-summary-component/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/examples/result-summary-component/vite.config.js b/examples/result-summary-component/vite.config.js
new file mode 100644
index 00000000..41713bec
--- /dev/null
+++ b/examples/result-summary-component/vite.config.js
@@ -0,0 +1,9 @@
+import { defineConfig } from "vite";
+
+export default defineConfig(({ command, mode, ssrBuild }) => {
+ return {
+ server: {
+ open: true,
+ },
+ };
+});