@statsbygg/layout 0.1.23 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -44
- package/dist/Breadcrumbs.module.css +3 -8
- package/dist/GlobalFooter.module.css +5 -0
- package/dist/GlobalHeader.module.css +18 -26
- package/dist/RootLayout.module.css +1 -1
- package/dist/assets/images/statsbygg_logo.svg +0 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +147 -23854
- package/dist/index.js.map +1 -1
- package/dist/styles/base.css +103 -0
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ npm install @statsbygg/layout
|
|
|
25
25
|
## Peer Dependencies
|
|
26
26
|
|
|
27
27
|
This package requires:
|
|
28
|
+
|
|
28
29
|
- `next` >= 14.0.0
|
|
29
30
|
- `react` >= 18.0.0
|
|
30
31
|
- `react-dom` >= 18.0.0
|
|
@@ -71,22 +72,23 @@ The routing system uses **URL-Driven Logic**. You define a single `RouteNode` tr
|
|
|
71
72
|
- **Internal Links**: Any relative path (e.g., `/`, `/about`) is treated as internal to your application (relative to your `basePath`).
|
|
72
73
|
|
|
73
74
|
#### Scenario A: Standard Application
|
|
74
|
-
|
|
75
|
+
|
|
76
|
+
_This app sits directly under the main Statsbygg site._
|
|
75
77
|
|
|
76
78
|
```tsx
|
|
77
79
|
// app/layout.tsx
|
|
78
|
-
import { RootLayout, RouteNode } from
|
|
80
|
+
import { RootLayout, RouteNode } from "@statsbygg/layout";
|
|
79
81
|
|
|
80
82
|
const ROUTES: RouteNode = {
|
|
81
|
-
label:
|
|
82
|
-
path:
|
|
83
|
+
label: "Hjem",
|
|
84
|
+
path: "https://statsbygg.no", // External Parent
|
|
83
85
|
children: [
|
|
84
86
|
{
|
|
85
|
-
label:
|
|
86
|
-
path:
|
|
87
|
+
label: "My App",
|
|
88
|
+
path: "/", // App Root (relative to basePath)
|
|
87
89
|
children: [
|
|
88
|
-
{ label:
|
|
89
|
-
{ label:
|
|
90
|
+
{ label: "Page 1", path: "/page-1" },
|
|
91
|
+
{ label: "Page 2", path: "/page-2" },
|
|
90
92
|
],
|
|
91
93
|
},
|
|
92
94
|
],
|
|
@@ -101,59 +103,53 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
|
|
101
103
|
</html>
|
|
102
104
|
);
|
|
103
105
|
}
|
|
104
|
-
|
|
105
106
|
```
|
|
106
107
|
|
|
107
108
|
#### Scenario B: Deeply Nested Microfrontend
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
_This app sits deep within a hierarchy of other applications._
|
|
110
111
|
|
|
111
112
|
```tsx
|
|
112
113
|
// app/layout.tsx
|
|
113
114
|
const ROUTES: RouteNode = {
|
|
114
|
-
label:
|
|
115
|
-
path:
|
|
115
|
+
label: "Hjem",
|
|
116
|
+
path: "https://statsbygg.no",
|
|
116
117
|
children: [
|
|
117
118
|
{
|
|
118
|
-
label:
|
|
119
|
-
path:
|
|
119
|
+
label: "Parent Route",
|
|
120
|
+
path: "https://statsbygg.no/parent-route", // External Parent 2
|
|
120
121
|
children: [
|
|
121
122
|
{
|
|
122
|
-
label:
|
|
123
|
-
path:
|
|
124
|
-
children: [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
]
|
|
123
|
+
label: "Your App Name",
|
|
124
|
+
path: "/", // Your App Root
|
|
125
|
+
children: [{ label: "Your App Route", path: "/your-app-route" }],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
131
130
|
};
|
|
132
|
-
|
|
133
131
|
```
|
|
134
132
|
|
|
135
133
|
### 2. Handling Dynamic Routes
|
|
136
134
|
|
|
137
135
|
For pages with dynamic IDs (e.g., `/properties/[id]`), use the `useBreadcrumbs` hook.
|
|
138
136
|
|
|
139
|
-
**Note:** You only need to define the
|
|
137
|
+
**Note:** You only need to define the _dynamic_ portion of the path. The layout package automatically prepends the static parents (Home, App Root, etc.) defined in your `ROUTES` tree.
|
|
140
138
|
|
|
141
139
|
```tsx
|
|
142
140
|
// app/properties/[id]/page.tsx
|
|
143
|
-
|
|
144
|
-
import { useBreadcrumbs } from
|
|
141
|
+
"use client";
|
|
142
|
+
import { useBreadcrumbs } from "@statsbygg/layout";
|
|
145
143
|
|
|
146
144
|
export default function PropertyPage({ params, propertyName }) {
|
|
147
|
-
|
|
148
145
|
useBreadcrumbs([
|
|
149
|
-
{ label:
|
|
146
|
+
{ label: "Properties", href: "/properties" },
|
|
150
147
|
{ label: propertyName, href: `/properties/${params.id}` },
|
|
151
148
|
]);
|
|
152
149
|
|
|
153
150
|
return <div>...</div>;
|
|
154
151
|
}
|
|
155
152
|
// Resulting Breadcrumbs: Home > My App > Properties > [Property Name]
|
|
156
|
-
|
|
157
153
|
```
|
|
158
154
|
|
|
159
155
|
### Using the Global Store
|
|
@@ -161,17 +157,17 @@ export default function PropertyPage({ params, propertyName }) {
|
|
|
161
157
|
The package exports a zustand store for managing global state:
|
|
162
158
|
|
|
163
159
|
```tsx
|
|
164
|
-
import { useGlobalStore } from
|
|
160
|
+
import { useGlobalStore } from "@statsbygg/layout";
|
|
165
161
|
|
|
166
162
|
function MyComponent() {
|
|
167
163
|
const { user, theme, setUser, setTheme } = useGlobalStore();
|
|
168
164
|
|
|
169
165
|
function handleLogin() {
|
|
170
|
-
setUser({ name:
|
|
166
|
+
setUser({ name: "John Doe", email: "john@statsbygg.no" });
|
|
171
167
|
}
|
|
172
168
|
|
|
173
169
|
function toggleTheme() {
|
|
174
|
-
setTheme(theme ===
|
|
170
|
+
setTheme(theme === "light" ? "dark" : "light");
|
|
175
171
|
}
|
|
176
172
|
|
|
177
173
|
return (
|
|
@@ -183,6 +179,7 @@ function MyComponent() {
|
|
|
183
179
|
);
|
|
184
180
|
}
|
|
185
181
|
```
|
|
182
|
+
|
|
186
183
|
## API Reference
|
|
187
184
|
|
|
188
185
|
### RootLayout
|
|
@@ -204,16 +201,15 @@ Zustand store hook for global state management.
|
|
|
204
201
|
```tsx
|
|
205
202
|
interface GlobalState {
|
|
206
203
|
user: { name: string; email: string } | null;
|
|
207
|
-
theme:
|
|
208
|
-
locale:
|
|
204
|
+
theme: "light" | "dark";
|
|
205
|
+
locale: "no" | "en";
|
|
209
206
|
setUser: (user: { name: string; email: string } | null) => void;
|
|
210
|
-
setTheme: (theme:
|
|
211
|
-
setLocale: (locale:
|
|
207
|
+
setTheme: (theme: "light" | "dark") => void;
|
|
208
|
+
setLocale: (locale: "no" | "en") => void;
|
|
212
209
|
initialize: () => Promise<void>;
|
|
213
210
|
}
|
|
214
211
|
```
|
|
215
212
|
|
|
216
|
-
|
|
217
213
|
## Breadcrumbs Behavior
|
|
218
214
|
|
|
219
215
|
The Breadcrumbs component uses Designsystemet's responsive behavior:
|
|
@@ -241,6 +237,7 @@ This package uses [DigDir Designsystemet](https://designsystemet.no) components:
|
|
|
241
237
|
- `Paragraph`
|
|
242
238
|
|
|
243
239
|
All styling uses Designsystemet design tokens:
|
|
240
|
+
|
|
244
241
|
- `--ds-spacing-*` for spacing
|
|
245
242
|
- `--ds-color-*` for colors
|
|
246
243
|
- `--ds-font-size-*` for typography
|
|
@@ -249,24 +246,25 @@ All styling uses Designsystemet design tokens:
|
|
|
249
246
|
|
|
250
247
|
```bash
|
|
251
248
|
# Install dependencies
|
|
252
|
-
|
|
249
|
+
pnpm install
|
|
253
250
|
|
|
254
251
|
# Build the package
|
|
255
|
-
|
|
252
|
+
pnpm build
|
|
256
253
|
|
|
257
254
|
# Watch mode for development
|
|
258
|
-
|
|
255
|
+
pnpm dev
|
|
259
256
|
|
|
260
257
|
# Type checking
|
|
261
|
-
|
|
258
|
+
pnpm type-check
|
|
262
259
|
|
|
263
260
|
# Linting
|
|
264
|
-
|
|
261
|
+
pnpm lint
|
|
265
262
|
```
|
|
266
263
|
|
|
267
264
|
## Dependencies
|
|
268
265
|
|
|
269
266
|
This package includes:
|
|
267
|
+
|
|
270
268
|
- `@digdir/designsystemet-react` 1.12.1
|
|
271
269
|
- `@statsbygg/design-tokens` ^0.2.0
|
|
272
270
|
- `clsx` ^2.0.0
|
|
@@ -274,4 +272,4 @@ This package includes:
|
|
|
274
272
|
|
|
275
273
|
## License
|
|
276
274
|
|
|
277
|
-
Internal use only - Statsbygg
|
|
275
|
+
Internal use only - Statsbygg
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.wrapper {
|
|
2
2
|
width: 100%;
|
|
3
|
-
background-color: var(--ds-color-background-tinted);
|
|
3
|
+
background-color: var(--layout-background, var(--ds-color-background-tinted));
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.inner {
|
|
@@ -9,10 +9,6 @@
|
|
|
9
9
|
margin: 0 auto;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
.whiteBackground {
|
|
13
|
-
background-color: white;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
.breadcrumbs {
|
|
17
13
|
--dsc-breadcrumbs-color: var(--ds-color-text-default);
|
|
18
14
|
}
|
|
@@ -64,8 +60,7 @@
|
|
|
64
60
|
color: var(--ds-color-text-default);
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
.link:hover
|
|
68
|
-
.link:visited{
|
|
63
|
+
.link:hover .link:visited {
|
|
69
64
|
color: var(--ds-color-text-default);
|
|
70
65
|
}
|
|
71
66
|
|
|
@@ -85,4 +80,4 @@
|
|
|
85
80
|
.inner {
|
|
86
81
|
padding: var(--ds-size-6) var(--ds-size-4) 0;
|
|
87
82
|
}
|
|
88
|
-
}
|
|
83
|
+
}
|
|
@@ -4,27 +4,21 @@
|
|
|
4
4
|
background-color: var(--ds-color-background-tinted);
|
|
5
5
|
top: 0;
|
|
6
6
|
z-index: 100;
|
|
7
|
-
|
|
7
|
+
background-color: var(--layout-background, var(--ds-color-background-tinted));
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
.header,
|
|
10
|
+
.header,
|
|
11
|
+
.headerWrapper {
|
|
11
12
|
min-height: 128px;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
.whiteBackground,
|
|
15
|
-
.whiteBackground .topBarFixedWrapper,
|
|
16
|
-
.whiteBackground .headerContainer {
|
|
17
|
-
background-color: white;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
15
|
.topBarFixedWrapper {
|
|
21
16
|
position: relative;
|
|
22
17
|
left: 0;
|
|
23
18
|
right: 0;
|
|
24
|
-
background: var(--ds-color-background-tinted);
|
|
19
|
+
background: var(--layout-background, var(--ds-color-background-tinted));
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
|
|
28
22
|
.topBarFixed {
|
|
29
23
|
position: fixed;
|
|
30
24
|
top: 0;
|
|
@@ -32,7 +26,7 @@
|
|
|
32
26
|
|
|
33
27
|
.topBarContainer {
|
|
34
28
|
max-height: 10rem;
|
|
35
|
-
max-width: 90rem;
|
|
29
|
+
max-width: 90rem;
|
|
36
30
|
margin: 0 auto;
|
|
37
31
|
padding: 0 var(--ds-size-30);
|
|
38
32
|
}
|
|
@@ -58,7 +52,7 @@
|
|
|
58
52
|
left: 0;
|
|
59
53
|
right: 0;
|
|
60
54
|
top: 0;
|
|
61
|
-
background-color: var(--ds-color-background-tinted);
|
|
55
|
+
background-color: var(--layout-background, var(--ds-color-background-tinted));
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
.topBarInner {
|
|
@@ -95,8 +89,8 @@
|
|
|
95
89
|
}
|
|
96
90
|
|
|
97
91
|
@media (max-width: 1024px) {
|
|
98
|
-
|
|
99
|
-
.
|
|
92
|
+
.header,
|
|
93
|
+
.headerWrapper {
|
|
100
94
|
min-height: 112px;
|
|
101
95
|
}
|
|
102
96
|
|
|
@@ -110,8 +104,8 @@
|
|
|
110
104
|
}
|
|
111
105
|
|
|
112
106
|
@media (max-width: 768px) {
|
|
113
|
-
|
|
114
|
-
.
|
|
107
|
+
.header,
|
|
108
|
+
.headerWrapper {
|
|
115
109
|
min-height: 96px;
|
|
116
110
|
}
|
|
117
111
|
|
|
@@ -138,14 +132,14 @@
|
|
|
138
132
|
display: none;
|
|
139
133
|
}
|
|
140
134
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
135
|
+
.logo {
|
|
136
|
+
inline-size: 8rem;
|
|
137
|
+
}
|
|
144
138
|
}
|
|
145
139
|
|
|
146
140
|
@media (max-width: 600px) {
|
|
147
|
-
|
|
148
|
-
.
|
|
141
|
+
.header,
|
|
142
|
+
.headerWrapper {
|
|
149
143
|
min-height: 80px;
|
|
150
144
|
}
|
|
151
145
|
|
|
@@ -156,12 +150,11 @@
|
|
|
156
150
|
.topBarContainer {
|
|
157
151
|
padding: 0 var(--ds-size-6);
|
|
158
152
|
}
|
|
159
|
-
|
|
160
153
|
}
|
|
161
154
|
|
|
162
155
|
@media (max-width: 360px) {
|
|
163
|
-
|
|
164
|
-
.
|
|
156
|
+
.header,
|
|
157
|
+
.headerWrapper {
|
|
165
158
|
min-height: 74px;
|
|
166
159
|
}
|
|
167
160
|
|
|
@@ -172,5 +165,4 @@
|
|
|
172
165
|
.topBarInner {
|
|
173
166
|
padding: var(--ds-size-4) 0;
|
|
174
167
|
}
|
|
175
|
-
|
|
176
|
-
}
|
|
168
|
+
}
|
|
File without changes
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,9 @@ type GlobalHeaderProps = {
|
|
|
7
7
|
className?: string;
|
|
8
8
|
appBasePath?: string;
|
|
9
9
|
pathname?: string;
|
|
10
|
-
isWhiteBackground?: boolean;
|
|
11
10
|
};
|
|
12
11
|
|
|
13
|
-
declare function GlobalHeader({ className, appBasePath
|
|
12
|
+
declare function GlobalHeader({ className, appBasePath }: GlobalHeaderProps): react_jsx_runtime.JSX.Element;
|
|
14
13
|
|
|
15
14
|
type RouteNode = {
|
|
16
15
|
path: string;
|
|
@@ -28,15 +27,20 @@ type AncestorChain = {
|
|
|
28
27
|
declare function findAppRootWithAncestors(node: RouteNode, ancestors?: RouteNode[]): AncestorChain;
|
|
29
28
|
declare function getBreadcrumbs(routes: RouteNode, pathname: string): BreadcrumbItem[];
|
|
30
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Available background color schemes for the layout.
|
|
32
|
+
* These map to CSS custom properties in RootLayout.module.css
|
|
33
|
+
*/
|
|
34
|
+
type LayoutBackground = "default" | "white" | "alternative";
|
|
31
35
|
type RootLayoutProps = {
|
|
32
36
|
children: React.ReactNode;
|
|
33
37
|
routes: RouteNode;
|
|
34
38
|
appBasePath?: string;
|
|
35
39
|
className?: string;
|
|
36
|
-
|
|
40
|
+
background?: LayoutBackground;
|
|
37
41
|
};
|
|
38
42
|
|
|
39
|
-
declare function RootLayout({ children, routes, appBasePath, className,
|
|
43
|
+
declare function RootLayout({ children, routes, appBasePath, className, background, }: RootLayoutProps): react_jsx_runtime.JSX.Element;
|
|
40
44
|
|
|
41
45
|
interface GlobalFooterProps {
|
|
42
46
|
className?: string;
|
|
@@ -93,10 +97,9 @@ type BreadcrumbsProps = {
|
|
|
93
97
|
routes: RouteNode;
|
|
94
98
|
appBasePath?: string;
|
|
95
99
|
pathname?: string;
|
|
96
|
-
isWhiteBackground?: boolean;
|
|
97
100
|
};
|
|
98
101
|
|
|
99
|
-
declare function SbBreadcrumbs({ className, routes, appBasePath, pathname: propPathname,
|
|
102
|
+
declare function SbBreadcrumbs({ className, routes, appBasePath, pathname: propPathname, }: BreadcrumbsProps): react_jsx_runtime.JSX.Element | null;
|
|
100
103
|
|
|
101
104
|
type SmartLinkProps = {
|
|
102
105
|
href: string;
|