diff --git a/bau-css/package.json b/bau-css/package.json
index 688b52f7..28cb8457 100644
--- a/bau-css/package.json
+++ b/bau-css/package.json
@@ -25,7 +25,7 @@
"build": "vite build",
"preview": "vite preview",
"bundle-visualizer": "vite-bundle-visualizer",
- "test": "vitest"
+ "test": "vitest run"
},
"devDependencies": {
"happy-dom": "15.7.4",
diff --git a/bau-router/package.json b/bau-router/package.json
index 5555fa33..7827211b 100644
--- a/bau-router/package.json
+++ b/bau-router/package.json
@@ -19,7 +19,7 @@
"build": "vite build",
"preview": "vite preview",
"bundle-visualizer": "vite-bundle-visualizer",
- "test": "vitest"
+ "test": "vitest run"
},
"dependencies": {
"@grucloud/bau": "^0.97.0"
diff --git a/bau/package.json b/bau/package.json
index 10c43a5b..925f77fe 100644
--- a/bau/package.json
+++ b/bau/package.json
@@ -24,7 +24,7 @@
"dev": "vite",
"build": "vite build",
"bundle-visualizer": "vite-bundle-visualizer",
- "test": "vitest"
+ "test": "vitest run"
},
"devDependencies": {
"@vitest/browser": "2.1.1",
diff --git a/examples/README.md b/examples/README.md
index a8ad17a6..a8199b19 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -22,6 +22,7 @@ Below is a list of projects implemented using _Bau_.
| IP Address Tracker | [live](https://grucloud.github.io/bau/frontendmentor/ip-address-tracker/) | [code](./ip-address-tracker) |
| Job Listing With Filtering | [live](https://grucloud.github.io/bau/frontendmentor/job-listings-with-filtering/) | [code](./job-listings-with-filtering) |
| Launch Countdown Timer | [live](https://grucloud.github.io/bau/frontendmentor/launch-countdown-timer/) | [code](./launch-countdown-timer) |
+| News Homepage | [live](https://grucloud.github.io/bau/frontendmentor/news-homepage/) | [code](./news-homepage) |
| Newsletter Signup Form | [live](https://grucloud.github.io/bau/frontendmentor/newsletter-signup-form/) | [code](./newsletter-signup-form) |
| Mortgage Repayment Calculator | [live](https://grucloud.github.io/bau/frontendmentor/mortgage-repayment-calculator/) | [code](./mortgage-repayment-calculator) |
| Multi Step Form | [live](https://grucloud.github.io/bau/frontendmentor/multi-step-form/) | [code](./multi-step-form) |
diff --git a/examples/calculator/package.json b/examples/calculator/package.json
index 21c3dcbe..03c0ec0e 100644
--- a/examples/calculator/package.json
+++ b/examples/calculator/package.json
@@ -8,7 +8,7 @@
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
- "test": "vitest",
+ "test": "vitest run",
"deploy": "gh-pages -d ../../dist"
},
"devDependencies": {
diff --git a/examples/news-homepage/.gitignore b/examples/news-homepage/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/examples/news-homepage/.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/news-homepage/.npmrc b/examples/news-homepage/.npmrc
new file mode 100644
index 00000000..6b5f38e8
--- /dev/null
+++ b/examples/news-homepage/.npmrc
@@ -0,0 +1,2 @@
+save-exact = true
+package-lock = false
diff --git a/examples/news-homepage/README.md b/examples/news-homepage/README.md
new file mode 100644
index 00000000..113736fe
--- /dev/null
+++ b/examples/news-homepage/README.md
@@ -0,0 +1,23 @@
+# Frontend Mentor News Homepage
+
+Here is the implementation in [Bau.js](https://github.com/grucloud/bau) of the [Frontend Mentor News Homepage code challenge](https://www.frontendmentor.io/challenges/news-homepage-H6SWTa1MFl)
+
+## 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/news-homepage/index.html b/examples/news-homepage/index.html
new file mode 100644
index 00000000..13a528f4
--- /dev/null
+++ b/examples/news-homepage/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ News Homepage | FrontendMentor
+
+
+
+
+
+
+
diff --git a/examples/news-homepage/package.json b/examples/news-homepage/package.json
new file mode 100644
index 00000000..0dcb5852
--- /dev/null
+++ b/examples/news-homepage/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "frontendmentor-news-homepage",
+ "homepage": "https://grucloud.github.io/bau/frontendmentor/news-homepage/",
+ "private": true,
+ "version": "0.97.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "deploy": "gh-pages -d ../../dist"
+ },
+ "devDependencies": {
+ "gh-pages": "6.1.1",
+ "typescript": "^5.0.2",
+ "vite": "^5.2.11"
+ },
+ "dependencies": {
+ "@grucloud/bau": "^0.97.0",
+ "@grucloud/bau-css": "^0.97.0",
+ "@grucloud/bau-ui": "^0.97.0"
+ }
+}
diff --git a/examples/news-homepage/public/assets/images/favicon-32x32.png b/examples/news-homepage/public/assets/images/favicon-32x32.png
new file mode 100644
index 00000000..1e2df7f0
Binary files /dev/null and b/examples/news-homepage/public/assets/images/favicon-32x32.png differ
diff --git a/examples/news-homepage/public/assets/images/icon-menu-close.svg b/examples/news-homepage/public/assets/images/icon-menu-close.svg
new file mode 100644
index 00000000..3800b8a6
--- /dev/null
+++ b/examples/news-homepage/public/assets/images/icon-menu-close.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/news-homepage/public/assets/images/icon-menu.svg b/examples/news-homepage/public/assets/images/icon-menu.svg
new file mode 100644
index 00000000..b62648f3
--- /dev/null
+++ b/examples/news-homepage/public/assets/images/icon-menu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/news-homepage/public/assets/images/image-gaming-growth.jpg b/examples/news-homepage/public/assets/images/image-gaming-growth.jpg
new file mode 100644
index 00000000..1acb97f9
Binary files /dev/null and b/examples/news-homepage/public/assets/images/image-gaming-growth.jpg differ
diff --git a/examples/news-homepage/public/assets/images/image-retro-pcs.jpg b/examples/news-homepage/public/assets/images/image-retro-pcs.jpg
new file mode 100644
index 00000000..a4f7fc40
Binary files /dev/null and b/examples/news-homepage/public/assets/images/image-retro-pcs.jpg differ
diff --git a/examples/news-homepage/public/assets/images/image-top-laptops.jpg b/examples/news-homepage/public/assets/images/image-top-laptops.jpg
new file mode 100644
index 00000000..f323c3e1
Binary files /dev/null and b/examples/news-homepage/public/assets/images/image-top-laptops.jpg differ
diff --git a/examples/news-homepage/public/assets/images/image-web-3-desktop.jpg b/examples/news-homepage/public/assets/images/image-web-3-desktop.jpg
new file mode 100644
index 00000000..03f1bba5
Binary files /dev/null and b/examples/news-homepage/public/assets/images/image-web-3-desktop.jpg differ
diff --git a/examples/news-homepage/public/assets/images/image-web-3-mobile.jpg b/examples/news-homepage/public/assets/images/image-web-3-mobile.jpg
new file mode 100644
index 00000000..240f589d
Binary files /dev/null and b/examples/news-homepage/public/assets/images/image-web-3-mobile.jpg differ
diff --git a/examples/news-homepage/public/assets/images/logo.svg b/examples/news-homepage/public/assets/images/logo.svg
new file mode 100644
index 00000000..4f93e978
--- /dev/null
+++ b/examples/news-homepage/public/assets/images/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/news-homepage/src/main.ts b/examples/news-homepage/src/main.ts
new file mode 100644
index 00000000..c3709c58
--- /dev/null
+++ b/examples/news-homepage/src/main.ts
@@ -0,0 +1,18 @@
+import { createContext, type Context } from "@grucloud/bau-ui/context";
+import newsHomepage from "./newsHomepage";
+import "./style.css";
+
+const context = createContext();
+
+const app = (context: Context) => {
+ const { bau } = context;
+ const { main } = bau.tags;
+ const NewsHomepage = newsHomepage(context);
+
+ return function () {
+ return main(NewsHomepage());
+ };
+};
+
+const App = app(context);
+document.getElementById("app")?.replaceChildren(App());
diff --git a/examples/news-homepage/src/newsHomepage.ts b/examples/news-homepage/src/newsHomepage.ts
new file mode 100644
index 00000000..a84943ce
--- /dev/null
+++ b/examples/news-homepage/src/newsHomepage.ts
@@ -0,0 +1,53 @@
+import { type Context } from "@grucloud/bau-ui/context";
+
+const HEADERS = ["Home", "New", "Popular", "Trending", "Categories"];
+
+export default function (context: Context) {
+ const { bau, css } = context;
+ const { article, nav, ul, li, header, h1, a } = bau.tags;
+
+ const className = css`
+ display: grid;
+ gap: 0.5rem;
+ margin-inline: auto;
+ padding: 1rem;
+ max-width: 800px;
+ > header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ h1 {
+ font-size: 2rem;
+ font-weight: 800;
+ }
+ }
+ `;
+
+ const Nav = () =>
+ nav(
+ {
+ class: css`
+ > ul {
+ list-style: none;
+ display: inline-flex;
+ gap: 0.7rem;
+ > li {
+ font-size: 0.8rem;
+ > a {
+ text-decoration: none;
+ color: var(--color-gray-500);
+ &:hover {
+ color: var(--soft-orange);
+ }
+ }
+ }
+ }
+ `,
+ },
+ ul(HEADERS.map((h) => li(a({ href: `${h}` }, h))))
+ );
+
+ return () => {
+ return article({ class: className }, header(h1("W."), Nav()));
+ };
+}
diff --git a/examples/news-homepage/src/style.css b/examples/news-homepage/src/style.css
new file mode 100644
index 00000000..19ae4c98
--- /dev/null
+++ b/examples/news-homepage/src/style.css
@@ -0,0 +1,38 @@
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400..800&display=swap");
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+:root {
+ --soft-orange: hsl(35, 77%, 62%);
+ --soft-red: hsl(5, 85%, 63%);
+
+ --off-white: hsl(36, 100%, 99%);
+ --grayish-blue: hsl(233, 8%, 79%);
+ --dark-grayish-blue: hsl(236, 13%, 42%);
+ --very-dark-blue: hsl(240, 100%, 5%);
+
+ --color-primary-h: 259;
+ --color-primary-base-s: 100%;
+ --color-primary-l: 65%;
+
+ --color-neutral-h: 245;
+ --color-neutral-base-s: 18%;
+ --color-neutral-l: 26%;
+
+ --color-danger-h: 358;
+ --color-danger-base-s: 79%;
+ --color-danger-l: 66%;
+
+ --font-color-primary: white;
+ --background-color: white;
+}
+
+body {
+ font: 400 15px/1.5 "Inter", sans-serif;
+ min-height: 100vh;
+ display: grid;
+}
diff --git a/examples/news-homepage/src/vite-env.d.ts b/examples/news-homepage/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/examples/news-homepage/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/news-homepage/tsconfig.json b/examples/news-homepage/tsconfig.json
new file mode 100644
index 00000000..75abdef2
--- /dev/null
+++ b/examples/news-homepage/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/news-homepage/vite.config.js b/examples/news-homepage/vite.config.js
new file mode 100644
index 00000000..bccf99d6
--- /dev/null
+++ b/examples/news-homepage/vite.config.js
@@ -0,0 +1,11 @@
+import { defineConfig } from "vite";
+
+export default defineConfig(({ command, mode, ssrBuild }) => {
+ return {
+ base: "/bau/frontendmentor/news-homepage/",
+ build: { outDir: "../../dist/frontendmentor/news-homepage" },
+ server: {
+ open: true,
+ },
+ };
+});