✨ Add aksel.nav.no website with live component examples

Vite + React docs site that imports @navikt/ds-react, @navikt/ds-css and
@navikt/ds-tokens from the workspace and renders every component.
Heading level now accepts string literals to match JSX usage.
This commit is contained in:
Aksel Mini committed 2026-08-25 10:05:00 +02:00
1 parent adfcead7be
commit 9c8f55f5cf
10 files changed
+1242 -3

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="no">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aksel Mini — Komponenter</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+25
View File
@@ -0,0 +1,25 @@
{
"name": "website",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit -p tsconfig.json && vite build",
"preview": "vite preview"
},
"dependencies": {
"@navikt/ds-css": "workspace:*",
"@navikt/ds-react": "workspace:*",
"@navikt/ds-tokens": "workspace:*",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/react": "18.3.11",
"@types/react-dom": "18.3.1",
"@vitejs/plugin-react": "4.3.2",
"typescript": "5.5.4",
"vite": "5.4.8"
}
}
+110
View File
@@ -0,0 +1,110 @@
import { useState } from "react";
import {
Accordion,
Alert,
BodyShort,
Button,
Heading,
Modal,
TextField,
} from "@navikt/ds-react";
export function App() {
const [modalOpen, setModalOpen] = useState(false);
return (
<main className="page">
<header className="intro">
<Heading level="1" size="xlarge">
Aksel Mini
</Heading>
<BodyShort size="medium">
Et miniatyr-designsystem som speiler strukturen til Aksel. Hver komponent
under er rendret direkte fra @navikt/ds-react med stiler fra @navikt/ds-css.
</BodyShort>
</header>
<section className="example">
<Heading level="2" size="medium">
Button
</Heading>
<div className="example__preview">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="tertiary">Tertiary</Button>
<Button variant="danger">Danger</Button>
<Button size="small">Small</Button>
</div>
</section>
<section className="example">
<Heading level="2" size="medium">
Typography
</Heading>
<div className="example__preview example__preview--column">
<Heading level="3" size="small">
Heading small
</Heading>
<BodyShort size="medium">BodyShort medium — brukes til vanlig brødtekst.</BodyShort>
<BodyShort size="small">BodyShort small — brukes til hjelpetekst og metadata.</BodyShort>
</div>
</section>
<section className="example">
<Heading level="2" size="medium">
TextField
</Heading>
<div className="example__preview example__preview--column">
<TextField label="Navn" description="For- og etternavn" />
<TextField label="E-post" error="E-postadressen ser ikke gyldig ut" />
</div>
</section>
<section className="example">
<Heading level="2" size="medium">
Alert
</Heading>
<div className="example__preview example__preview--column">
<Alert variant="info">Søknaden din er mottatt.</Alert>
<Alert variant="success">Alt gikk bra.</Alert>
<Alert variant="warning">Fristen nærmer seg.</Alert>
<Alert variant="error">Noe gikk galt.</Alert>
</div>
</section>
<section className="example">
<Heading level="2" size="medium">
Accordion
</Heading>
<Accordion>
<Accordion.Item title="Hvordan søker jeg?">
<BodyShort>Du søker ved å fylle ut skjemaet digitalt.</BodyShort>
</Accordion.Item>
<Accordion.Item title="Hva koster det?" defaultOpen>
<BodyShort>Det er gratis å søke.</BodyShort>
</Accordion.Item>
</Accordion>
</section>
<section className="example">
<Heading level="2" size="medium">
Modal
</Heading>
<div className="example__preview">
<Button variant="secondary" onClick={() => setModalOpen(true)}>
Åpne modal
</Button>
</div>
<Modal open={modalOpen} onClose={() => setModalOpen(false)} label="Eksempelmodal">
<Heading level="3" size="small">
Bekreftelse
</Heading>
<BodyShort>Dette er en modal renderet via en portal.</BodyShort>
<Button variant="primary" onClick={() => setModalOpen(false)}>
Lukk
</Button>
</Modal>
</section>
</main>
);
}
+46
View File
@@ -0,0 +1,46 @@
:root {
color-scheme: light;
}
body {
margin: 0;
background-color: var(--a-bg-default);
color: var(--a-text-default);
font-family: var(--a-font-family);
}
.page {
max-width: 48rem;
margin: 0 auto;
padding: var(--a-spacing-8) var(--a-spacing-4);
display: flex;
flex-direction: column;
gap: var(--a-spacing-8);
}
.intro {
display: flex;
flex-direction: column;
gap: var(--a-spacing-2);
}
.example {
display: flex;
flex-direction: column;
gap: var(--a-spacing-4);
padding: var(--a-spacing-6);
border: 1px solid var(--a-border-subtle);
border-radius: var(--a-border-radius-large);
}
.example__preview {
display: flex;
flex-wrap: wrap;
gap: var(--a-spacing-3);
align-items: center;
}
.example__preview--column {
flex-direction: column;
align-items: stretch;
}
+12
View File
@@ -0,0 +1,12 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "@navikt/ds-tokens/dist/tokens.css";
import "@navikt/ds-css/dist/index.css";
import "./main.css";
import { App } from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"types": ["vite/client"]
},
"include": ["src", "vite.config.ts"]
}
+9
View File
@@ -0,0 +1,9 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
},
});
+3 -3
View File
@@ -10,13 +10,13 @@ export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
size?: "xlarge" | "large" | "medium" | "small" | "xsmall";
/**
* Semantic heading level (h1–h6).
* @default 1
* @default "1"
*/
level?: 1 | 2 | 3 | 4 | 5 | 6;
level?: "1" | "2" | "3" | "4" | "5" | "6";
}
export const Heading = forwardRef<HTMLHeadingElement, HeadingProps>(function Heading(
{ size = "medium", level = 1, className, ...rest },
{ size = "medium", level = "1", className, ...rest },
ref,
) {
return createElement(`h${level}`, {
+1013
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -1,3 +1,6 @@
packages:
- "packages/**"
- "aksel.nav.no/**"
allowBuilds:
esbuild: true