@statsbygg/layout 0.0.7 → 0.0.8

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.
@@ -0,0 +1,22 @@
1
+ .breadcrumbs {
2
+ --dsc-breadcrumbs-color: var(--ds-color-text-default);
3
+ padding: 2.5rem 0 0 0;
4
+ }
5
+
6
+ .link {
7
+ text-decoration: underline;
8
+ text-underline-offset: 2px;
9
+ color: var(--ds-color-text-default);
10
+ }
11
+
12
+ .link:hover
13
+ .link:visited{
14
+ color: var(--ds-color-text-default);
15
+ }
16
+
17
+ .currentLink {
18
+ text-decoration: none;
19
+ font-weight: 500;
20
+ pointer-events: none;
21
+ color: var(--ds-color-text-default);
22
+ }
@@ -0,0 +1,28 @@
1
+ .footer {
2
+ background-color: var(--ds-color-neutral-surface-subtle);
3
+ border-top: 1px solid var(--ds-color-neutral-border-subtle);
4
+ margin-top: auto;
5
+ }
6
+
7
+ .container {
8
+ max-width: 1440px;
9
+ margin: 0 auto;
10
+ padding: var(--ds-spacing-6) var(--ds-spacing-4);
11
+ }
12
+
13
+ .content {
14
+ display: flex;
15
+ justify-content: space-between;
16
+ align-items: center;
17
+ gap: var(--ds-spacing-4);
18
+ flex-wrap: wrap;
19
+ }
20
+
21
+ @media (max-width: 768px) {
22
+ .content {
23
+ flex-direction: column;
24
+ align-items: flex-start;
25
+ }
26
+
27
+
28
+ }
@@ -0,0 +1,70 @@
1
+ .header {
2
+ background-color: var(--ds-color-accent-surface-tinted);
3
+ border-bottom: 1px solid var(--ds-color-neutral-border-subtle);
4
+ position: sticky;
5
+ top: 0;
6
+ z-index: 100;
7
+ }
8
+
9
+ .headerContainer {
10
+ max-width: 90rem;
11
+ margin: 0 auto;
12
+ padding: 0 var(--ds-size-30);
13
+ }
14
+
15
+ .topBarContainer {
16
+ display: flex;
17
+ justify-content: space-between;
18
+ align-items: center;
19
+ padding: 1.25rem 0;
20
+ }
21
+
22
+ .logo {
23
+ margin: 0;
24
+ color: var(--ds-color-neutral-text-default);
25
+ white-space: nowrap;
26
+ display: flex;
27
+ align-items: center;
28
+ min-height: inherit;
29
+ }
30
+
31
+ .actionsContainer {
32
+ display: flex;
33
+ align-items: stretch;
34
+ gap: var(--ds-size-9);
35
+ min-height: inherit;
36
+ }
37
+
38
+ .searchInput {
39
+ min-width: 12.5rem;
40
+ display: flex;
41
+ align-items: center;
42
+ }
43
+
44
+ @media (max-width: 768px) {
45
+ .container {
46
+ padding: 0 var(--ds-spacing-4);
47
+ }
48
+
49
+ .topBar {
50
+ flex-wrap: wrap;
51
+ padding: var(--ds-spacing-4) 0;
52
+ }
53
+
54
+ .actions {
55
+ order: 3;
56
+ width: 100%;
57
+ flex-direction: column;
58
+ gap: var(--ds-spacing-3);
59
+ }
60
+
61
+ .searchInput {
62
+ width: 100%;
63
+ min-width: auto;
64
+ }
65
+
66
+ .menuButton {
67
+ width: 100%;
68
+ justify-content: center;
69
+ }
70
+ }
@@ -0,0 +1,41 @@
1
+ .userInfo {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--ds-spacing-1);
5
+ padding: var(--ds-spacing-2) var(--ds-spacing-3);
6
+ }
7
+
8
+ .userName {
9
+ font-size: var(--ds-font-size-sm);
10
+ font-weight: var(--ds-font-weight-medium);
11
+ color: var(--ds-color-neutral-text-default);
12
+ }
13
+
14
+ .userEmail {
15
+ font-size: var(--ds-font-size-xs);
16
+ color: var(--ds-color-neutral-text-subtle);
17
+ }
18
+
19
+ .menuButton {
20
+ background-color: var(--ds-color-neutral-base-default);
21
+ }
22
+
23
+ .devContainer {
24
+ display: flex;
25
+ gap: var(--ds-spacing-4);
26
+ padding: var(--ds-spacing-2);
27
+ }
28
+
29
+ .zoneSection {
30
+ flex: 1;
31
+ min-width: 12rem;
32
+ }
33
+
34
+ .zoneTitle {
35
+ font-weight: 600;
36
+ padding: var(--ds-spacing-2);
37
+ color: var(--ds-color-neutral-text-default);
38
+ border-bottom: 1px solid var(--ds-color-neutral-border-subtle);
39
+ margin-bottom: var(--ds-spacing-2);
40
+ text-transform: capitalize;
41
+ }
@@ -0,0 +1,9 @@
1
+ .root {
2
+ display: flex;
3
+ flex-direction: column;
4
+ min-height: 100vh;
5
+ }
6
+
7
+ .main {
8
+ flex: 1;
9
+ }
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
2
  "use client";
3
- var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
7
  var __export = (target, all) => {
10
8
  for (var name in all)
@@ -18,375 +16,15 @@ var __copyProps = (to, from, except, desc) => {
18
16
  }
19
17
  return to;
20
18
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/index.ts
32
20
  var index_exports = {};
33
21
  __export(index_exports, {
34
- RootLayout: () => RootLayout,
35
- useGlobalStore: () => useGlobalStore
22
+ RootLayout: () => import_RootLayout.RootLayout,
23
+ useGlobalStore: () => import_globalState.useGlobalStore
36
24
  });
37
25
  module.exports = __toCommonJS(index_exports);
38
-
39
- // src/components/RootLayout/RootLayout.tsx
40
- var import_react2 = require("react");
41
- var import_clsx4 = __toESM(require("clsx"));
42
-
43
- // src/components/GlobalHeader/GlobalHeader.tsx
44
- var import_react = require("react");
45
- var import_designsystemet_react3 = require("@digdir/designsystemet-react");
46
- var import_clsx2 = __toESM(require("clsx"));
47
-
48
- // src/components/Breadcrumbs/Breadcrumbs.tsx
49
- var import_navigation = require("next/navigation");
50
- var import_designsystemet_react = require("@digdir/designsystemet-react");
51
- var import_clsx = __toESM(require("clsx"));
52
-
53
- // src/components/Breadcrumbs/Breadcrumbs.module.css
54
- var Breadcrumbs_default = {
55
- breadcrumbs: "Breadcrumbs_breadcrumbs",
56
- link: "Breadcrumbs_link",
57
- currentLink: "Breadcrumbs_currentLink"
58
- };
59
-
60
- // src/routes.ts
61
- var ZONE_TREES_INPUT = {
62
- sbno: {
63
- segment: "",
64
- // primary root route, no breadcrumb
65
- label: "Hjem",
66
- children: [
67
- { segment: "nyheter", label: "Nyheter" }
68
- ]
69
- },
70
- lokaler: {
71
- segment: "lokaler",
72
- label: "Statens eide og leide lokaler",
73
- children: [
74
- {
75
- segment: "lokalbruk",
76
- label: "Lokalbruk"
77
- },
78
- { segment: "veiledning", label: "Veiledning" },
79
- { segment: "statlige-eiendommer", label: "Statlige eiendommer" },
80
- { segment: "ledig-for-fremleie", label: "Ledig for fremleie" },
81
- { segment: "statistikk", label: "Statistikk" }
82
- ]
83
- }
84
- };
85
- var ROUTES_INDEX = {};
86
- var PARENT_INDEX = /* @__PURE__ */ new Map();
87
- var ZONE_TREES = {};
88
- function isSegmentNode(n) {
89
- return n.segment !== void 0 && n.path === void 0;
90
- }
91
- function isPathNode(n) {
92
- return n.path !== void 0;
93
- }
94
- function joinPath(base, seg) {
95
- if (!base) return seg ? `/${seg}` : "/";
96
- return seg ? `${base.replace(/\/+$/, "")}/${seg.replace(/^\/+/, "")}` : base || "/";
97
- }
98
- function normalizeToAbsolute(node, base = "") {
99
- var _a;
100
- const path = isSegmentNode(node) ? joinPath(base, node.segment) : isPathNode(node) ? node.path === "" ? "/" : node.path : "/";
101
- const children = ((_a = node.children) != null ? _a : []).map((c) => normalizeToAbsolute(c, path));
102
- return { path, label: node.label, children: children.length ? children : void 0 };
103
- }
104
- (function buildAll() {
105
- Object.keys(ZONE_TREES_INPUT).forEach((zone) => {
106
- ZONE_TREES[zone] = normalizeToAbsolute(ZONE_TREES_INPUT[zone]);
107
- });
108
- function walk(zone, node, parentKey) {
109
- var _a;
110
- const def = { zone, path: node.path, label: node.label };
111
- const key = `${zone}:${node.path}`;
112
- ROUTES_INDEX[zone].push(def);
113
- PARENT_INDEX.set(key, parentKey);
114
- for (const child of (_a = node.children) != null ? _a : []) {
115
- walk(zone, child, key);
116
- }
117
- }
118
- Object.keys(ZONE_TREES).forEach((zone) => {
119
- ROUTES_INDEX[zone] = [];
120
- walk(zone, ZONE_TREES[zone], null);
121
- });
122
- })();
123
- function findBestMatch(zone, pathname) {
124
- var _a;
125
- const list = (_a = ROUTES_INDEX[zone]) != null ? _a : [];
126
- let best;
127
- for (const r of list) {
128
- if (pathname === r.path) {
129
- best = r;
130
- break;
131
- }
132
- if (pathname.startsWith(r.path.endsWith("/") ? r.path : r.path + "/")) {
133
- if (!best || r.path.length > best.path.length) best = r;
134
- }
135
- }
136
- return best != null ? best : list.find((r) => {
137
- var _a2;
138
- return r.path === ((_a2 = ZONE_TREES[zone]) == null ? void 0 : _a2.path);
139
- });
140
- }
141
- function getZoneMenuRoutes(zone) {
142
- var _a;
143
- const root = ZONE_TREES[zone];
144
- const children = (_a = root == null ? void 0 : root.children) != null ? _a : [];
145
- return children.map((c) => ({ zone, path: c.path, label: c.label }));
146
- }
147
- function getAllZones() {
148
- return Object.keys(ZONE_TREES);
149
- }
150
- function getZoneRoot(zone) {
151
- var _a;
152
- return ((_a = ZONE_TREES[zone]) == null ? void 0 : _a.path) || "/";
153
- }
154
- function labelFromSlug(slug) {
155
- try {
156
- const s = decodeURIComponent(slug).replace(/[-_]+/g, " ").trim();
157
- return s ? s.charAt(0).toUpperCase() + s.slice(1) : slug;
158
- } catch (e) {
159
- return slug;
160
- }
161
- }
162
- function getBreadcrumbs(zone, pathname) {
163
- var _a, _b;
164
- const normalizedPathname = pathname === "/" ? pathname : pathname.replace(/\/+$/, "");
165
- if (zone === "sbno" && normalizedPathname === "/") return [];
166
- const match = findBestMatch(zone, normalizedPathname);
167
- if (!match) return [];
168
- const chain = [];
169
- let key = `${zone}:${match.path}`;
170
- while (key) {
171
- const parentKey = PARENT_INDEX.get(key);
172
- const [z, p] = key.split(":");
173
- const def = ((_a = ROUTES_INDEX[z]) != null ? _a : []).find((r) => r.path === p);
174
- if (def) chain.unshift(def);
175
- key = parentKey != null ? parentKey : void 0;
176
- }
177
- const homeRoute = ((_b = ROUTES_INDEX.sbno) != null ? _b : []).find((r) => r.path === "/");
178
- if (homeRoute && !(chain.length === 1 && chain[0].zone === "sbno" && chain[0].path === "/") && (chain.length === 0 || chain[0].path !== homeRoute.path)) {
179
- chain.unshift(homeRoute);
180
- }
181
- const last = chain[chain.length - 1];
182
- if (last && normalizedPathname !== last.path && normalizedPathname.startsWith(last.path.endsWith("/") ? last.path : last.path + "/")) {
183
- const segments = normalizedPathname.split("/").filter(Boolean);
184
- const tail = segments[segments.length - 1];
185
- chain.push({ zone, path: normalizedPathname, label: labelFromSlug(tail) });
186
- }
187
- return chain.map((r) => ({ label: r.label, href: r.path }));
188
- }
189
- function transformHrefForZone(targetPath, currentZone, options) {
190
- const { isDev, prodUrl } = options;
191
- const targetZone = getZoneFromPathname(targetPath);
192
- const isCrossZone = targetZone !== currentZone;
193
- if (isCrossZone && isDev && prodUrl) {
194
- return `${prodUrl}${targetPath}`;
195
- }
196
- const currentZoneRoot = getZoneRoot(currentZone);
197
- if (!isCrossZone && isDev && currentZoneRoot !== "/") {
198
- return targetPath.replace(currentZoneRoot, "") || "/";
199
- }
200
- return targetPath;
201
- }
202
- function getZoneFromPathname(pathname) {
203
- if (pathname.startsWith("/lokaler")) return "lokaler";
204
- return "sbno";
205
- }
206
-
207
- // src/components/Breadcrumbs/Breadcrumbs.tsx
208
- var import_jsx_runtime = require("react/jsx-runtime");
209
- function SbBreadcrumbs({ className, zone }) {
210
- const pathname = (0, import_navigation.usePathname)();
211
- const isDev = process.env.NODE_ENV === "development";
212
- const prodUrl = "https://www.statsbygg.no";
213
- const zoneRoot = getZoneRoot(zone);
214
- const fullPath = isDev && zoneRoot !== "/" && !pathname.startsWith(zoneRoot) ? `${zoneRoot}${pathname}` : pathname;
215
- const breadcrumbs = getBreadcrumbs(zone, fullPath);
216
- if (breadcrumbs.length <= 1) {
217
- return null;
218
- }
219
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_designsystemet_react.Breadcrumbs, { "aria-label": "Du er her:", className: (0, import_clsx.default)(Breadcrumbs_default.breadcrumbs, className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_designsystemet_react.Breadcrumbs.List, { children: breadcrumbs.map((crumb, index) => {
220
- const isLast = index === breadcrumbs.length - 1;
221
- const href = transformHrefForZone(crumb.href, zone, { isDev, prodUrl });
222
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_designsystemet_react.Breadcrumbs.Item, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
223
- import_designsystemet_react.Breadcrumbs.Link,
224
- {
225
- href,
226
- "aria-current": isLast ? "page" : void 0,
227
- className: isLast ? Breadcrumbs_default.currentLink : Breadcrumbs_default.link,
228
- children: crumb.label
229
- }
230
- ) }, crumb.href);
231
- }) }) });
232
- }
233
-
234
- // src/components/MenuButton/MenuButton.tsx
235
- var import_link = __toESM(require("next/link"));
236
- var import_designsystemet_react2 = require("@digdir/designsystemet-react");
237
- var import_lucide_react = require("lucide-react");
238
-
239
- // src/components/MenuButton/MenuButton.module.css
240
- var MenuButton_default = {
241
- userInfo: "MenuButton_userInfo",
242
- userName: "MenuButton_userName",
243
- userEmail: "MenuButton_userEmail",
244
- menuButton: "MenuButton_menuButton",
245
- devContainer: "MenuButton_devContainer",
246
- zoneSection: "MenuButton_zoneSection",
247
- zoneTitle: "MenuButton_zoneTitle"
248
- };
249
-
250
- // src/components/MenuButton/MenuButton.tsx
251
- var import_jsx_runtime2 = require("react/jsx-runtime");
252
- function MenuButton({ zone }) {
253
- const isDev = process.env.NODE_ENV === "development";
254
- const prodUrl = "https://www.statsbygg.no";
255
- const allZones = getAllZones();
256
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_designsystemet_react2.Dropdown.TriggerContext, { children: [
257
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_designsystemet_react2.Dropdown.Trigger, { asChild: true, className: MenuButton_default.menuButton, children: [
258
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Menu, { size: 20, "aria-hidden": true }),
259
- "Meny"
260
- ] }),
261
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_designsystemet_react2.Dropdown, { children: isDev ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: MenuButton_default.devContainer, children: allZones.map((z) => {
262
- const routes = getZoneMenuRoutes(z);
263
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: MenuButton_default.zoneSection, children: [
264
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: MenuButton_default.zoneTitle, children: z }),
265
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_designsystemet_react2.Dropdown.List, { children: routes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_designsystemet_react2.Dropdown.Item, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_link.default, { href: transformHrefForZone(r.path, zone, { isDev, prodUrl }), children: r.label }) }, `${r.zone}:${r.path}`)) })
266
- ] }, z);
267
- }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_designsystemet_react2.Dropdown.List, { children: getZoneMenuRoutes(zone).map((r) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_designsystemet_react2.Dropdown.Item, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_link.default, { href: transformHrefForZone(r.path, zone, { isDev, prodUrl }), children: r.label }) }, `${r.zone}:${r.path}`)) }) })
268
- ] });
269
- }
270
-
271
- // src/components/GlobalHeader/GlobalHeader.module.css
272
- var GlobalHeader_default = {
273
- header: "GlobalHeader_header",
274
- headerContainer: "GlobalHeader_headerContainer",
275
- topBarContainer: "GlobalHeader_topBarContainer",
276
- logo: "GlobalHeader_logo",
277
- actionsContainer: "GlobalHeader_actionsContainer",
278
- searchInput: "GlobalHeader_searchInput",
279
- container: "GlobalHeader_container",
280
- topBar: "GlobalHeader_topBar",
281
- actions: "GlobalHeader_actions",
282
- menuButton: "GlobalHeader_menuButton"
283
- };
284
-
285
- // src/logo.svg
286
- var logo_default = "./logo-JRXKWS5H.svg";
287
-
288
- // src/components/GlobalHeader/GlobalHeader.tsx
289
- var import_jsx_runtime3 = require("react/jsx-runtime");
290
- function GlobalHeader({ className, zone }) {
291
- const [searchValue, setSearchValue] = (0, import_react.useState)("");
292
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("header", { className: (0, import_clsx2.default)(GlobalHeader_default.header, className), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: GlobalHeader_default.headerContainer, children: [
293
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: GlobalHeader_default.topBarContainer, children: [
294
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_designsystemet_react3.Link, { href: "https://www.statsbygg.no", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("img", { src: logo_default, alt: "Logo", className: GlobalHeader_default.logo }) }),
295
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: GlobalHeader_default.actionsContainer, children: [
296
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
297
- import_designsystemet_react3.Textfield,
298
- {
299
- value: searchValue,
300
- onChange: (e) => setSearchValue(e.target.value),
301
- placeholder: "S\xF8k...",
302
- className: GlobalHeader_default.searchInput,
303
- "aria-label": "S\xF8k"
304
- }
305
- ),
306
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuButton, { zone })
307
- ] })
308
- ] }),
309
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SbBreadcrumbs, { zone })
310
- ] }) });
311
- }
312
-
313
- // src/components/GlobalFooter/GlobalFooter.tsx
314
- var import_designsystemet_react4 = require("@digdir/designsystemet-react");
315
- var import_clsx3 = __toESM(require("clsx"));
316
-
317
- // src/components/GlobalFooter/GlobalFooter.module.css
318
- var GlobalFooter_default = {
319
- footer: "GlobalFooter_footer",
320
- container: "GlobalFooter_container",
321
- content: "GlobalFooter_content"
322
- };
323
-
324
- // src/components/GlobalFooter/GlobalFooter.tsx
325
- var import_jsx_runtime4 = require("react/jsx-runtime");
326
- function GlobalFooter({ className }) {
327
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("footer", { className: (0, import_clsx3.default)(GlobalFooter_default.footer, className), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: GlobalFooter_default.container, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: GlobalFooter_default.content, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_designsystemet_react4.Paragraph, { children: "Statsbygg Footer" }) }) }) });
328
- }
329
-
330
- // src/components/RootLayout/RootLayout.module.css
331
- var RootLayout_default = {
332
- root: "RootLayout_root",
333
- main: "RootLayout_main"
334
- };
335
-
336
- // src/store/globalState.ts
337
- var import_zustand = require("zustand");
338
- var import_middleware = require("zustand/middleware");
339
- var creator = (set, get) => ({
340
- user: null,
341
- theme: "light",
342
- locale: "no",
343
- setUser: (user) => set({ user }),
344
- setTheme: (theme) => {
345
- set({ theme });
346
- if (typeof document !== "undefined") {
347
- document.documentElement.setAttribute("data-color-scheme", theme);
348
- }
349
- },
350
- setLocale: (locale) => set({ locale }),
351
- initialize: () => {
352
- if (typeof document !== "undefined") {
353
- document.documentElement.setAttribute("data-color-scheme", get().theme);
354
- }
355
- }
356
- });
357
- var useGlobalStore = (0, import_zustand.create)()(
358
- (0, import_middleware.persist)(creator, {
359
- name: "statsbygg-global-state",
360
- storage: (0, import_middleware.createJSONStorage)(() => localStorage)
361
- })
362
- );
363
-
364
- // src/components/RootLayout/RootLayout.tsx
365
- var import_jsx_runtime5 = require("react/jsx-runtime");
366
- function RootLayout({
367
- children,
368
- zone,
369
- className
370
- }) {
371
- const initialize = useGlobalStore((state) => state.initialize);
372
- (0, import_react2.useEffect)(() => {
373
- try {
374
- const maybe = initialize();
375
- if (maybe && typeof maybe.then === "function") {
376
- maybe.catch((error) => {
377
- console.error("Failed to initialize global state:", error);
378
- });
379
- }
380
- } catch (error) {
381
- console.error("Failed to initialize global state:", error);
382
- }
383
- }, [initialize]);
384
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: (0, import_clsx4.default)(RootLayout_default.root, className), "data-zone": zone, children: [
385
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalHeader, { zone }),
386
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: RootLayout_default.main, children }),
387
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalFooter, {})
388
- ] });
389
- }
26
+ var import_RootLayout = require("./components/RootLayout");
27
+ var import_globalState = require("./store/globalState");
390
28
  // Annotate the CommonJS export names for ESM import in node:
391
29
  0 && (module.exports = {
392
30
  RootLayout,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/RootLayout/RootLayout.tsx","../src/components/GlobalHeader/GlobalHeader.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx","../src/components/Breadcrumbs/Breadcrumbs.module.css","../src/routes.ts","../src/components/MenuButton/MenuButton.tsx","../src/components/MenuButton/MenuButton.module.css","../src/components/GlobalHeader/GlobalHeader.module.css","../src/components/GlobalFooter/GlobalFooter.tsx","../src/components/GlobalFooter/GlobalFooter.module.css","../src/components/RootLayout/RootLayout.module.css","../src/store/globalState.ts"],"sourcesContent":["'use client';\n\nexport { RootLayout } from './components/RootLayout';\nexport type { RootLayoutProps } from './components/RootLayout';\n\nexport { useGlobalStore } from './store/globalState';\nexport type { GlobalState } from './store/globalState';\n","'use client';\n\nimport { useEffect } from 'react';\nimport clsx from 'clsx';\nimport { GlobalHeader } from '../GlobalHeader';\nimport { GlobalFooter } from '../GlobalFooter';\nimport type { RootLayoutProps } from './RootLayout.types';\nimport styles from './RootLayout.module.css';\nimport { useGlobalStore } from '@/store/globalState';\n\nexport function RootLayout({\n children,\n zone, \n className,\n}: RootLayoutProps) {\n const initialize = useGlobalStore((state) => state.initialize);\n\n useEffect(() => {\n try {\n const maybe = initialize();\n if (maybe && typeof (maybe as Promise<void>).then === 'function') {\n (maybe as Promise<void>).catch((error) => {\n console.error('Failed to initialize global state:', error);\n });\n }\n } catch (error) {\n console.error('Failed to initialize global state:', error);\n }\n }, [initialize]);\n\n\n return (\n <div className={clsx(styles.root, className)} data-zone={zone}>\n <GlobalHeader zone={zone}/>\n <main className={styles.main}>{children}</main>\n <GlobalFooter />\n </div>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { Link, Textfield } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport { Breadcrumbs } from '../Breadcrumbs';\nimport { MenuButton } from '../MenuButton';\nimport type { GlobalHeaderProps } from './GlobalHeader.types';\nimport styles from './GlobalHeader.module.css';\nimport logo from '../../logo.svg'; \n\nexport function GlobalHeader({ className, zone }: GlobalHeaderProps) {\n const [searchValue, setSearchValue] = useState('');\n\n return (\n <header className={clsx(styles.header, className)}>\n <div className={styles.headerContainer}>\n <div className={styles.topBarContainer}>\n <Link href=\"https://www.statsbygg.no\">\n <img src={logo} alt=\"Logo\" className={styles.logo} />\n </Link>\n <div className={styles.actionsContainer}>\n <Textfield\n value={searchValue}\n onChange={(e) => setSearchValue(e.target.value)}\n placeholder=\"Søk...\"\n className={styles.searchInput}\n aria-label=\"Søk\"\n />\n <MenuButton zone={zone}/>\n </div>\n </div>\n <Breadcrumbs zone={zone} />\n </div>\n </header>\n );\n}","'use client';\n\nimport { usePathname } from 'next/navigation';\nimport { Breadcrumbs } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport type { BreadcrumbsProps } from './Breadcrumbs.types';\nimport styles from './Breadcrumbs.module.css';\nimport { getBreadcrumbs, getZoneRoot, transformHrefForZone } from '@/routes';\n\nexport function SbBreadcrumbs({ className, zone }: BreadcrumbsProps) {\n const pathname = usePathname();\n const isDev = process.env.NODE_ENV === 'development';\n const prodUrl = 'https://www.statsbygg.no';\n const zoneRoot = getZoneRoot(zone);\n \n const fullPath = isDev && zoneRoot !== '/' && !pathname.startsWith(zoneRoot)\n ? `${zoneRoot}${pathname}`\n : pathname;\n \n const breadcrumbs = getBreadcrumbs(zone, fullPath);\n\n if (breadcrumbs.length <= 1) {\n return null;\n }\n\n\n return (\n <Breadcrumbs aria-label=\"Du er her:\" className={clsx(styles.breadcrumbs, className)}>\n <Breadcrumbs.List>\n {breadcrumbs.map((crumb, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const href = transformHrefForZone(crumb.href, zone, { isDev, prodUrl });\n \n return (\n <Breadcrumbs.Item key={crumb.href}>\n <Breadcrumbs.Link\n href={href}\n aria-current={isLast ? 'page' : undefined}\n className={isLast ? styles.currentLink : styles.link}\n >\n {crumb.label}\n </Breadcrumbs.Link>\n </Breadcrumbs.Item>\n );\n })}\n </Breadcrumbs.List>\n </Breadcrumbs>\n );\n}",".breadcrumbs {\n --dsc-breadcrumbs-color: var(--ds-color-text-default);\n padding: 2.5rem 0 0 0;\n}\n\n.link {\n text-decoration: underline;\n text-underline-offset: 2px;\n color: var(--ds-color-text-default);\n}\n\n.link:hover \n.link:visited{\n color: var(--ds-color-text-default);\n}\n\n.currentLink {\n text-decoration: none;\n font-weight: 500;\n pointer-events: none;\n color: var(--ds-color-text-default);\n}\n","export type RouteNodeInput =\n | { segment: string; label: string; children?: RouteNodeInput[] }\n | { path: string; label: string; children?: RouteNodeInput[] };\n\nexport type RouteNode = {\n path: string;\n label: string;\n children?: RouteNode[];\n};\n\nexport type RouteDefinition = {\n path: string;\n label: string;\n zone: string;\n};\n\nconst ZONE_TREES_INPUT: Record<string, RouteNodeInput> = {\n sbno: {\n segment: '',// primary root route, no breadcrumb\n label: 'Hjem',\n children: [\n { segment: 'nyheter', label: 'Nyheter' },\n ],\n },\n lokaler: {\n segment: 'lokaler',\n label: 'Statens eide og leide lokaler',\n children: [\n {\n segment: 'lokalbruk', label: 'Lokalbruk'\n },\n { segment: 'veiledning', label: 'Veiledning' },\n { segment: 'statlige-eiendommer', label: 'Statlige eiendommer' },\n { segment: 'ledig-for-fremleie', label: 'Ledig for fremleie' },\n { segment: 'statistikk', label: 'Statistikk' },\n ],\n },\n};\n\n\ntype Key = `${string}:${string}`; // `${zone}:${absolutePath}`\n\nconst ROUTES_INDEX: Record<string, RouteDefinition[]> = {};\nconst PARENT_INDEX = new Map<Key, Key | null>(); // child -> parent\nconst ZONE_TREES: Record<string, RouteNode> = {}; // normalized absolute trees\n\nfunction isSegmentNode(n: RouteNodeInput): n is Extract<RouteNodeInput, { segment: string }> {\n return (n as any).segment !== undefined && (n as any).path === undefined;\n}\nfunction isPathNode(n: RouteNodeInput): n is Extract<RouteNodeInput, { path: string }> {\n return (n as any).path !== undefined;\n}\n\nfunction joinPath(base: string, seg: string): string {\n if (!base) return seg ? `/${seg}` : '/';\n return seg ? `${base.replace(/\\/+$/, '')}/${seg.replace(/^\\/+/, '')}` : base || '/';\n}\n\nfunction normalizeToAbsolute(node: RouteNodeInput, base = ''): RouteNode {\n const path = isSegmentNode(node)\n ? joinPath(base, node.segment)\n : isPathNode(node)\n ? (node.path === '' ? '/' : node.path)\n : '/';\n\n const children = (node.children ?? []).map((c) => normalizeToAbsolute(c, path));\n return { path, label: (node as any).label, children: children.length ? children : undefined };\n}\n\n(function buildAll() {\n // Normalize each zone tree to absolute paths\n Object.keys(ZONE_TREES_INPUT).forEach((zone) => {\n ZONE_TREES[zone] = normalizeToAbsolute(ZONE_TREES_INPUT[zone]);\n });\n\n // Build flat indexes + parent relationships\n function walk(zone: string, node: RouteNode, parentKey: Key | null) {\n const def: RouteDefinition = { zone, path: node.path, label: node.label };\n const key: Key = `${zone}:${node.path}`;\n ROUTES_INDEX[zone].push(def);\n PARENT_INDEX.set(key, parentKey);\n for (const child of node.children ?? []) {\n walk(zone, child, key);\n }\n }\n\n (Object.keys(ZONE_TREES) as string[]).forEach((zone) => {\n ROUTES_INDEX[zone] = [];\n walk(zone, ZONE_TREES[zone], null);\n });\n})();\n\n\nfunction findBestMatch(zone: string, pathname: string): RouteDefinition | undefined {\n const list = ROUTES_INDEX[zone] ?? [];\n let best: RouteDefinition | undefined;\n\n for (const r of list) {\n if (pathname === r.path) {\n best = r; // exact wins\n break;\n }\n if (pathname.startsWith(r.path.endsWith('/') ? r.path : r.path + '/')) {\n if (!best || r.path.length > best.path.length) best = r;\n }\n }\n // fallback: zone root\n return best ?? list.find((r) => r.path === ZONE_TREES[zone]?.path);\n}\n\nexport function getZoneRoutes(zone: string): RouteDefinition[] {\n return ROUTES_INDEX[zone] ?? [];\n}\n\n// Top-level links for a zone’s menu (children of the zone root)\nexport function getZoneMenuRoutes(zone: string): RouteDefinition[] {\n const root = ZONE_TREES[zone];\n const children = root?.children ?? [];\n return children.map((c) => ({ zone, path: c.path, label: c.label }));\n}\n\nexport function getAllZones(): string[] {\n return Object.keys(ZONE_TREES);\n}\n\nexport function getZoneRoot(zone: string): string {\n return ZONE_TREES[zone]?.path || '/';\n}\n\n// prettify dynamic slug labels\nfunction labelFromSlug(slug: string): string {\n try {\n const s = decodeURIComponent(slug).replace(/[-_]+/g, ' ').trim();\n return s ? s.charAt(0).toUpperCase() + s.slice(1) : slug;\n } catch {\n return slug;\n }\n}\n\nexport function getBreadcrumbs(\n zone: string,\n pathname: string\n): Array<{ label: string; href: string }> {\n\n const normalizedPathname = pathname === '/' ? pathname : pathname.replace(/\\/+$/, '');\n\n // sbno root has no crumbs\n if (zone === 'sbno' && normalizedPathname === '/') return [];\n\n const match = findBestMatch(zone, normalizedPathname);\n if (!match) return [];\n\n const chain: RouteDefinition[] = [];\n let key: Key | undefined = `${zone}:${match.path}`;\n while (key) {\n const parentKey = PARENT_INDEX.get(key);\n const [z, p] = key.split(':') as [string, string];\n const def = (ROUTES_INDEX[z] ?? []).find((r) => r.path === p);\n if (def) chain.unshift(def);\n key = parentKey ?? undefined;\n }\n\n const homeRoute = (ROUTES_INDEX.sbno ?? []).find((r) => r.path === '/');\n if (\n homeRoute &&\n !(chain.length === 1 && chain[0].zone === 'sbno' && chain[0].path === '/') &&\n (chain.length === 0 || chain[0].path !== homeRoute.path)\n ) {\n chain.unshift(homeRoute);\n }\n\n // If the pathname is deeper than the best static match, add a dynamic tail\n const last = chain[chain.length - 1];\n if (last && normalizedPathname !== last.path && normalizedPathname.startsWith(last.path.endsWith('/') ? last.path : last.path + '/')) {\n const segments = normalizedPathname.split('/').filter(Boolean);\n const tail = segments[segments.length - 1];\n chain.push({ zone, path: normalizedPathname, label: labelFromSlug(tail) });\n }\n\n return chain.map((r) => ({ label: r.label, href: r.path }));\n}\n\nexport function transformHrefForZone(\n targetPath: string,\n currentZone: string,\n options: {\n isDev: boolean;\n prodUrl?: string;\n }\n): string {\n const { isDev, prodUrl } = options;\n\n const targetZone = getZoneFromPathname(targetPath);\n const isCrossZone = targetZone !== currentZone;\n\n if (isCrossZone && isDev && prodUrl) {\n return `${prodUrl}${targetPath}`;\n }\n\n const currentZoneRoot = getZoneRoot(currentZone);\n if (!isCrossZone && isDev && currentZoneRoot !== '/') {\n return targetPath.replace(currentZoneRoot, '') || '/';\n }\n\n return targetPath;\n}\n\nexport function getZoneFromPathname(pathname: string): string {\n if (pathname.startsWith('/lokaler')) return 'lokaler';\n return 'sbno';\n}","'use client';\n\nimport Link from 'next/link';\nimport { Dropdown } from '@digdir/designsystemet-react';\nimport { Menu } from 'lucide-react';\nimport { getZoneMenuRoutes, getAllZones, transformHrefForZone } from '@/routes';\nimport type { MenuButtonProps } from './MenuButton.types';\nimport styles from './MenuButton.module.css';\n\nexport function MenuButton({ zone }: MenuButtonProps) {\n const isDev = process.env.NODE_ENV === 'development';\n // TODO: Temporary here. Should come from env or something\n const prodUrl = 'https://www.statsbygg.no';\n const allZones = getAllZones();\n\n return (\n <Dropdown.TriggerContext>\n <Dropdown.Trigger asChild className={styles.menuButton}>\n <Menu size={20} aria-hidden />\n Meny\n </Dropdown.Trigger>\n <Dropdown>\n {isDev ? (\n <div className={styles.devContainer}>\n {allZones.map((z) => {\n const routes = getZoneMenuRoutes(z);\n return (\n <div key={z} className={styles.zoneSection}>\n <div className={styles.zoneTitle}>{z}</div>\n <Dropdown.List>\n {routes.map((r) => (\n <Dropdown.Item key={`${r.zone}:${r.path}`}>\n <Link href={transformHrefForZone(r.path, zone, { isDev, prodUrl })}>\n {r.label}\n </Link>\n </Dropdown.Item>\n ))}\n </Dropdown.List>\n </div>\n );\n })}\n </div>\n ) : (\n <Dropdown.List>\n {getZoneMenuRoutes(zone).map((r) => (\n <Dropdown.Item key={`${r.zone}:${r.path}`}>\n <Link href={transformHrefForZone(r.path, zone, { isDev, prodUrl })}>\n {r.label}\n </Link>\n </Dropdown.Item>\n ))}\n </Dropdown.List>\n )}\n </Dropdown>\n </Dropdown.TriggerContext>\n );\n}",".userInfo {\n display: flex;\n flex-direction: column;\n gap: var(--ds-spacing-1);\n padding: var(--ds-spacing-2) var(--ds-spacing-3);\n}\n\n.userName {\n font-size: var(--ds-font-size-sm);\n font-weight: var(--ds-font-weight-medium);\n color: var(--ds-color-neutral-text-default);\n}\n\n.userEmail {\n font-size: var(--ds-font-size-xs);\n color: var(--ds-color-neutral-text-subtle);\n}\n\n.menuButton {\n background-color: var(--ds-color-neutral-base-default);\n}\n\n.devContainer {\n display: flex;\n gap: var(--ds-spacing-4);\n padding: var(--ds-spacing-2);\n}\n\n.zoneSection {\n flex: 1;\n min-width: 12rem;\n}\n\n.zoneTitle {\n font-weight: 600;\n padding: var(--ds-spacing-2);\n color: var(--ds-color-neutral-text-default);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n margin-bottom: var(--ds-spacing-2);\n text-transform: capitalize;\n}\n",".header {\n background-color: var(--ds-color-accent-surface-tinted);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.headerContainer {\n max-width: 90rem;\n margin: 0 auto;\n padding: 0 var(--ds-size-30);\n}\n\n.topBarContainer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 0;\n}\n\n.logo {\n margin: 0;\n color: var(--ds-color-neutral-text-default);\n white-space: nowrap;\n display: flex;\n align-items: center;\n min-height: inherit;\n}\n\n.actionsContainer {\n display: flex;\n align-items: stretch;\n gap: var(--ds-size-9);\n min-height: inherit;\n}\n\n.searchInput {\n min-width: 12.5rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 768px) {\n .container {\n padding: 0 var(--ds-spacing-4);\n }\n\n .topBar {\n flex-wrap: wrap;\n padding: var(--ds-spacing-4) 0;\n }\n\n .actions {\n order: 3;\n width: 100%;\n flex-direction: column;\n gap: var(--ds-spacing-3);\n }\n\n .searchInput {\n width: 100%;\n min-width: auto;\n }\n\n .menuButton {\n width: 100%;\n justify-content: center;\n }\n}","'use client';\n\nimport { Paragraph } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport type { GlobalFooterProps } from './GlobalFooter.types';\nimport styles from './GlobalFooter.module.css';\n\nexport function GlobalFooter({ className }: GlobalFooterProps) {\n\n return (\n <footer className={clsx(styles.footer, className)}>\n <div className={styles.container}>\n <div className={styles.content}>\n <Paragraph>\n Statsbygg Footer\n </Paragraph>\n\n\n </div>\n </div>\n </footer>\n );\n}",".footer {\n background-color: var(--ds-color-neutral-surface-subtle);\n border-top: 1px solid var(--ds-color-neutral-border-subtle);\n margin-top: auto;\n}\n\n.container {\n max-width: 1440px;\n margin: 0 auto;\n padding: var(--ds-spacing-6) var(--ds-spacing-4);\n}\n\n.content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: var(--ds-spacing-4);\n flex-wrap: wrap;\n}\n\n@media (max-width: 768px) {\n .content {\n flex-direction: column;\n align-items: flex-start;\n }\n\n\n}",".root {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n}\n\n.main {\n flex: 1;\n}","import { create, StateCreator } from 'zustand';\nimport { persist, createJSONStorage } from 'zustand/middleware';\n\nexport type Theme = 'light' | 'dark' | 'system';\n\nexport type GlobalState = {\n user?: { id: string; name?: string } | null;\n theme: Theme;\n locale: string;\n setUser: (user: GlobalState['user']) => void;\n setTheme: (theme: Theme) => void;\n setLocale: (locale: string) => void;\n initialize: () => void | Promise<void>;\n};\n\nconst creator: StateCreator<GlobalState, [['zustand/persist', unknown]]> = (set, get) => ({\n user: null,\n theme: 'light',\n locale: 'no',\n setUser: (user) => set({ user }),\n setTheme: (theme) => {\n set({ theme });\n if (typeof document !== 'undefined') {\n document.documentElement.setAttribute('data-color-scheme', theme);\n }\n },\n setLocale: (locale) => set({ locale }),\n initialize: () => {\n if (typeof document !== 'undefined') {\n document.documentElement.setAttribute('data-color-scheme', get().theme);\n }\n },\n});\n\nexport const useGlobalStore = create<GlobalState>()(\n persist(creator, {\n name: 'statsbygg-global-state',\n storage: createJSONStorage(() => localStorage),\n })\n);\n"],"mappings":"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","names":["import_react","import_clsx","import_designsystemet_react","import_clsx","breadcrumbs","link","currentLink","_a","clsx","import_designsystemet_react","userInfo","userName","userEmail","menuButton","devContainer","zoneSection","zoneTitle","import_jsx_runtime","Link","header","headerContainer","topBarContainer","logo","actionsContainer","searchInput","container","topBar","actions","menuButton","import_jsx_runtime","clsx","import_designsystemet_react","import_clsx","footer","container","content","import_jsx_runtime","clsx","root","main","import_jsx_runtime","clsx"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["'use client';\n\nexport { RootLayout } from './components/RootLayout';\nexport type { RootLayoutProps } from './components/RootLayout';\n\nexport { useGlobalStore } from './store/globalState';\nexport type { GlobalState } from './store/globalState';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,wBAA2B;AAG3B,yBAA+B;","names":[]}
package/dist/index.mjs CHANGED
@@ -1,356 +1,6 @@
1
1
  "use client";
2
-
3
- // src/components/RootLayout/RootLayout.tsx
4
- import { useEffect } from "react";
5
- import clsx4 from "clsx";
6
-
7
- // src/components/GlobalHeader/GlobalHeader.tsx
8
- import { useState } from "react";
9
- import { Link as Link2, Textfield } from "@digdir/designsystemet-react";
10
- import clsx2 from "clsx";
11
-
12
- // src/components/Breadcrumbs/Breadcrumbs.tsx
13
- import { usePathname } from "next/navigation";
14
- import { Breadcrumbs } from "@digdir/designsystemet-react";
15
- import clsx from "clsx";
16
-
17
- // src/components/Breadcrumbs/Breadcrumbs.module.css
18
- var Breadcrumbs_default = {
19
- breadcrumbs: "Breadcrumbs_breadcrumbs",
20
- link: "Breadcrumbs_link",
21
- currentLink: "Breadcrumbs_currentLink"
22
- };
23
-
24
- // src/routes.ts
25
- var ZONE_TREES_INPUT = {
26
- sbno: {
27
- segment: "",
28
- // primary root route, no breadcrumb
29
- label: "Hjem",
30
- children: [
31
- { segment: "nyheter", label: "Nyheter" }
32
- ]
33
- },
34
- lokaler: {
35
- segment: "lokaler",
36
- label: "Statens eide og leide lokaler",
37
- children: [
38
- {
39
- segment: "lokalbruk",
40
- label: "Lokalbruk"
41
- },
42
- { segment: "veiledning", label: "Veiledning" },
43
- { segment: "statlige-eiendommer", label: "Statlige eiendommer" },
44
- { segment: "ledig-for-fremleie", label: "Ledig for fremleie" },
45
- { segment: "statistikk", label: "Statistikk" }
46
- ]
47
- }
48
- };
49
- var ROUTES_INDEX = {};
50
- var PARENT_INDEX = /* @__PURE__ */ new Map();
51
- var ZONE_TREES = {};
52
- function isSegmentNode(n) {
53
- return n.segment !== void 0 && n.path === void 0;
54
- }
55
- function isPathNode(n) {
56
- return n.path !== void 0;
57
- }
58
- function joinPath(base, seg) {
59
- if (!base) return seg ? `/${seg}` : "/";
60
- return seg ? `${base.replace(/\/+$/, "")}/${seg.replace(/^\/+/, "")}` : base || "/";
61
- }
62
- function normalizeToAbsolute(node, base = "") {
63
- var _a;
64
- const path = isSegmentNode(node) ? joinPath(base, node.segment) : isPathNode(node) ? node.path === "" ? "/" : node.path : "/";
65
- const children = ((_a = node.children) != null ? _a : []).map((c) => normalizeToAbsolute(c, path));
66
- return { path, label: node.label, children: children.length ? children : void 0 };
67
- }
68
- (function buildAll() {
69
- Object.keys(ZONE_TREES_INPUT).forEach((zone) => {
70
- ZONE_TREES[zone] = normalizeToAbsolute(ZONE_TREES_INPUT[zone]);
71
- });
72
- function walk(zone, node, parentKey) {
73
- var _a;
74
- const def = { zone, path: node.path, label: node.label };
75
- const key = `${zone}:${node.path}`;
76
- ROUTES_INDEX[zone].push(def);
77
- PARENT_INDEX.set(key, parentKey);
78
- for (const child of (_a = node.children) != null ? _a : []) {
79
- walk(zone, child, key);
80
- }
81
- }
82
- Object.keys(ZONE_TREES).forEach((zone) => {
83
- ROUTES_INDEX[zone] = [];
84
- walk(zone, ZONE_TREES[zone], null);
85
- });
86
- })();
87
- function findBestMatch(zone, pathname) {
88
- var _a;
89
- const list = (_a = ROUTES_INDEX[zone]) != null ? _a : [];
90
- let best;
91
- for (const r of list) {
92
- if (pathname === r.path) {
93
- best = r;
94
- break;
95
- }
96
- if (pathname.startsWith(r.path.endsWith("/") ? r.path : r.path + "/")) {
97
- if (!best || r.path.length > best.path.length) best = r;
98
- }
99
- }
100
- return best != null ? best : list.find((r) => {
101
- var _a2;
102
- return r.path === ((_a2 = ZONE_TREES[zone]) == null ? void 0 : _a2.path);
103
- });
104
- }
105
- function getZoneMenuRoutes(zone) {
106
- var _a;
107
- const root = ZONE_TREES[zone];
108
- const children = (_a = root == null ? void 0 : root.children) != null ? _a : [];
109
- return children.map((c) => ({ zone, path: c.path, label: c.label }));
110
- }
111
- function getAllZones() {
112
- return Object.keys(ZONE_TREES);
113
- }
114
- function getZoneRoot(zone) {
115
- var _a;
116
- return ((_a = ZONE_TREES[zone]) == null ? void 0 : _a.path) || "/";
117
- }
118
- function labelFromSlug(slug) {
119
- try {
120
- const s = decodeURIComponent(slug).replace(/[-_]+/g, " ").trim();
121
- return s ? s.charAt(0).toUpperCase() + s.slice(1) : slug;
122
- } catch (e) {
123
- return slug;
124
- }
125
- }
126
- function getBreadcrumbs(zone, pathname) {
127
- var _a, _b;
128
- const normalizedPathname = pathname === "/" ? pathname : pathname.replace(/\/+$/, "");
129
- if (zone === "sbno" && normalizedPathname === "/") return [];
130
- const match = findBestMatch(zone, normalizedPathname);
131
- if (!match) return [];
132
- const chain = [];
133
- let key = `${zone}:${match.path}`;
134
- while (key) {
135
- const parentKey = PARENT_INDEX.get(key);
136
- const [z, p] = key.split(":");
137
- const def = ((_a = ROUTES_INDEX[z]) != null ? _a : []).find((r) => r.path === p);
138
- if (def) chain.unshift(def);
139
- key = parentKey != null ? parentKey : void 0;
140
- }
141
- const homeRoute = ((_b = ROUTES_INDEX.sbno) != null ? _b : []).find((r) => r.path === "/");
142
- if (homeRoute && !(chain.length === 1 && chain[0].zone === "sbno" && chain[0].path === "/") && (chain.length === 0 || chain[0].path !== homeRoute.path)) {
143
- chain.unshift(homeRoute);
144
- }
145
- const last = chain[chain.length - 1];
146
- if (last && normalizedPathname !== last.path && normalizedPathname.startsWith(last.path.endsWith("/") ? last.path : last.path + "/")) {
147
- const segments = normalizedPathname.split("/").filter(Boolean);
148
- const tail = segments[segments.length - 1];
149
- chain.push({ zone, path: normalizedPathname, label: labelFromSlug(tail) });
150
- }
151
- return chain.map((r) => ({ label: r.label, href: r.path }));
152
- }
153
- function transformHrefForZone(targetPath, currentZone, options) {
154
- const { isDev, prodUrl } = options;
155
- const targetZone = getZoneFromPathname(targetPath);
156
- const isCrossZone = targetZone !== currentZone;
157
- if (isCrossZone && isDev && prodUrl) {
158
- return `${prodUrl}${targetPath}`;
159
- }
160
- const currentZoneRoot = getZoneRoot(currentZone);
161
- if (!isCrossZone && isDev && currentZoneRoot !== "/") {
162
- return targetPath.replace(currentZoneRoot, "") || "/";
163
- }
164
- return targetPath;
165
- }
166
- function getZoneFromPathname(pathname) {
167
- if (pathname.startsWith("/lokaler")) return "lokaler";
168
- return "sbno";
169
- }
170
-
171
- // src/components/Breadcrumbs/Breadcrumbs.tsx
172
- import { jsx } from "react/jsx-runtime";
173
- function SbBreadcrumbs({ className, zone }) {
174
- const pathname = usePathname();
175
- const isDev = process.env.NODE_ENV === "development";
176
- const prodUrl = "https://www.statsbygg.no";
177
- const zoneRoot = getZoneRoot(zone);
178
- const fullPath = isDev && zoneRoot !== "/" && !pathname.startsWith(zoneRoot) ? `${zoneRoot}${pathname}` : pathname;
179
- const breadcrumbs = getBreadcrumbs(zone, fullPath);
180
- if (breadcrumbs.length <= 1) {
181
- return null;
182
- }
183
- return /* @__PURE__ */ jsx(Breadcrumbs, { "aria-label": "Du er her:", className: clsx(Breadcrumbs_default.breadcrumbs, className), children: /* @__PURE__ */ jsx(Breadcrumbs.List, { children: breadcrumbs.map((crumb, index) => {
184
- const isLast = index === breadcrumbs.length - 1;
185
- const href = transformHrefForZone(crumb.href, zone, { isDev, prodUrl });
186
- return /* @__PURE__ */ jsx(Breadcrumbs.Item, { children: /* @__PURE__ */ jsx(
187
- Breadcrumbs.Link,
188
- {
189
- href,
190
- "aria-current": isLast ? "page" : void 0,
191
- className: isLast ? Breadcrumbs_default.currentLink : Breadcrumbs_default.link,
192
- children: crumb.label
193
- }
194
- ) }, crumb.href);
195
- }) }) });
196
- }
197
-
198
- // src/components/MenuButton/MenuButton.tsx
199
- import Link from "next/link";
200
- import { Dropdown } from "@digdir/designsystemet-react";
201
- import { Menu } from "lucide-react";
202
-
203
- // src/components/MenuButton/MenuButton.module.css
204
- var MenuButton_default = {
205
- userInfo: "MenuButton_userInfo",
206
- userName: "MenuButton_userName",
207
- userEmail: "MenuButton_userEmail",
208
- menuButton: "MenuButton_menuButton",
209
- devContainer: "MenuButton_devContainer",
210
- zoneSection: "MenuButton_zoneSection",
211
- zoneTitle: "MenuButton_zoneTitle"
212
- };
213
-
214
- // src/components/MenuButton/MenuButton.tsx
215
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
216
- function MenuButton({ zone }) {
217
- const isDev = process.env.NODE_ENV === "development";
218
- const prodUrl = "https://www.statsbygg.no";
219
- const allZones = getAllZones();
220
- return /* @__PURE__ */ jsxs(Dropdown.TriggerContext, { children: [
221
- /* @__PURE__ */ jsxs(Dropdown.Trigger, { asChild: true, className: MenuButton_default.menuButton, children: [
222
- /* @__PURE__ */ jsx2(Menu, { size: 20, "aria-hidden": true }),
223
- "Meny"
224
- ] }),
225
- /* @__PURE__ */ jsx2(Dropdown, { children: isDev ? /* @__PURE__ */ jsx2("div", { className: MenuButton_default.devContainer, children: allZones.map((z) => {
226
- const routes = getZoneMenuRoutes(z);
227
- return /* @__PURE__ */ jsxs("div", { className: MenuButton_default.zoneSection, children: [
228
- /* @__PURE__ */ jsx2("div", { className: MenuButton_default.zoneTitle, children: z }),
229
- /* @__PURE__ */ jsx2(Dropdown.List, { children: routes.map((r) => /* @__PURE__ */ jsx2(Dropdown.Item, { children: /* @__PURE__ */ jsx2(Link, { href: transformHrefForZone(r.path, zone, { isDev, prodUrl }), children: r.label }) }, `${r.zone}:${r.path}`)) })
230
- ] }, z);
231
- }) }) : /* @__PURE__ */ jsx2(Dropdown.List, { children: getZoneMenuRoutes(zone).map((r) => /* @__PURE__ */ jsx2(Dropdown.Item, { children: /* @__PURE__ */ jsx2(Link, { href: transformHrefForZone(r.path, zone, { isDev, prodUrl }), children: r.label }) }, `${r.zone}:${r.path}`)) }) })
232
- ] });
233
- }
234
-
235
- // src/components/GlobalHeader/GlobalHeader.module.css
236
- var GlobalHeader_default = {
237
- header: "GlobalHeader_header",
238
- headerContainer: "GlobalHeader_headerContainer",
239
- topBarContainer: "GlobalHeader_topBarContainer",
240
- logo: "GlobalHeader_logo",
241
- actionsContainer: "GlobalHeader_actionsContainer",
242
- searchInput: "GlobalHeader_searchInput",
243
- container: "GlobalHeader_container",
244
- topBar: "GlobalHeader_topBar",
245
- actions: "GlobalHeader_actions",
246
- menuButton: "GlobalHeader_menuButton"
247
- };
248
-
249
- // src/logo.svg
250
- var logo_default = "./logo-JRXKWS5H.svg";
251
-
252
- // src/components/GlobalHeader/GlobalHeader.tsx
253
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
254
- function GlobalHeader({ className, zone }) {
255
- const [searchValue, setSearchValue] = useState("");
256
- return /* @__PURE__ */ jsx3("header", { className: clsx2(GlobalHeader_default.header, className), children: /* @__PURE__ */ jsxs2("div", { className: GlobalHeader_default.headerContainer, children: [
257
- /* @__PURE__ */ jsxs2("div", { className: GlobalHeader_default.topBarContainer, children: [
258
- /* @__PURE__ */ jsx3(Link2, { href: "https://www.statsbygg.no", children: /* @__PURE__ */ jsx3("img", { src: logo_default, alt: "Logo", className: GlobalHeader_default.logo }) }),
259
- /* @__PURE__ */ jsxs2("div", { className: GlobalHeader_default.actionsContainer, children: [
260
- /* @__PURE__ */ jsx3(
261
- Textfield,
262
- {
263
- value: searchValue,
264
- onChange: (e) => setSearchValue(e.target.value),
265
- placeholder: "S\xF8k...",
266
- className: GlobalHeader_default.searchInput,
267
- "aria-label": "S\xF8k"
268
- }
269
- ),
270
- /* @__PURE__ */ jsx3(MenuButton, { zone })
271
- ] })
272
- ] }),
273
- /* @__PURE__ */ jsx3(SbBreadcrumbs, { zone })
274
- ] }) });
275
- }
276
-
277
- // src/components/GlobalFooter/GlobalFooter.tsx
278
- import { Paragraph } from "@digdir/designsystemet-react";
279
- import clsx3 from "clsx";
280
-
281
- // src/components/GlobalFooter/GlobalFooter.module.css
282
- var GlobalFooter_default = {
283
- footer: "GlobalFooter_footer",
284
- container: "GlobalFooter_container",
285
- content: "GlobalFooter_content"
286
- };
287
-
288
- // src/components/GlobalFooter/GlobalFooter.tsx
289
- import { jsx as jsx4 } from "react/jsx-runtime";
290
- function GlobalFooter({ className }) {
291
- return /* @__PURE__ */ jsx4("footer", { className: clsx3(GlobalFooter_default.footer, className), children: /* @__PURE__ */ jsx4("div", { className: GlobalFooter_default.container, children: /* @__PURE__ */ jsx4("div", { className: GlobalFooter_default.content, children: /* @__PURE__ */ jsx4(Paragraph, { children: "Statsbygg Footer" }) }) }) });
292
- }
293
-
294
- // src/components/RootLayout/RootLayout.module.css
295
- var RootLayout_default = {
296
- root: "RootLayout_root",
297
- main: "RootLayout_main"
298
- };
299
-
300
- // src/store/globalState.ts
301
- import { create } from "zustand";
302
- import { persist, createJSONStorage } from "zustand/middleware";
303
- var creator = (set, get) => ({
304
- user: null,
305
- theme: "light",
306
- locale: "no",
307
- setUser: (user) => set({ user }),
308
- setTheme: (theme) => {
309
- set({ theme });
310
- if (typeof document !== "undefined") {
311
- document.documentElement.setAttribute("data-color-scheme", theme);
312
- }
313
- },
314
- setLocale: (locale) => set({ locale }),
315
- initialize: () => {
316
- if (typeof document !== "undefined") {
317
- document.documentElement.setAttribute("data-color-scheme", get().theme);
318
- }
319
- }
320
- });
321
- var useGlobalStore = create()(
322
- persist(creator, {
323
- name: "statsbygg-global-state",
324
- storage: createJSONStorage(() => localStorage)
325
- })
326
- );
327
-
328
- // src/components/RootLayout/RootLayout.tsx
329
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
330
- function RootLayout({
331
- children,
332
- zone,
333
- className
334
- }) {
335
- const initialize = useGlobalStore((state) => state.initialize);
336
- useEffect(() => {
337
- try {
338
- const maybe = initialize();
339
- if (maybe && typeof maybe.then === "function") {
340
- maybe.catch((error) => {
341
- console.error("Failed to initialize global state:", error);
342
- });
343
- }
344
- } catch (error) {
345
- console.error("Failed to initialize global state:", error);
346
- }
347
- }, [initialize]);
348
- return /* @__PURE__ */ jsxs3("div", { className: clsx4(RootLayout_default.root, className), "data-zone": zone, children: [
349
- /* @__PURE__ */ jsx5(GlobalHeader, { zone }),
350
- /* @__PURE__ */ jsx5("main", { className: RootLayout_default.main, children }),
351
- /* @__PURE__ */ jsx5(GlobalFooter, {})
352
- ] });
353
- }
2
+ import { RootLayout } from "./components/RootLayout";
3
+ import { useGlobalStore } from "./store/globalState";
354
4
  export {
355
5
  RootLayout,
356
6
  useGlobalStore
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/RootLayout/RootLayout.tsx","../src/components/GlobalHeader/GlobalHeader.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx","../src/components/Breadcrumbs/Breadcrumbs.module.css","../src/routes.ts","../src/components/MenuButton/MenuButton.tsx","../src/components/MenuButton/MenuButton.module.css","../src/components/GlobalHeader/GlobalHeader.module.css","../src/components/GlobalFooter/GlobalFooter.tsx","../src/components/GlobalFooter/GlobalFooter.module.css","../src/components/RootLayout/RootLayout.module.css","../src/store/globalState.ts"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\nimport clsx from 'clsx';\nimport { GlobalHeader } from '../GlobalHeader';\nimport { GlobalFooter } from '../GlobalFooter';\nimport type { RootLayoutProps } from './RootLayout.types';\nimport styles from './RootLayout.module.css';\nimport { useGlobalStore } from '@/store/globalState';\n\nexport function RootLayout({\n children,\n zone, \n className,\n}: RootLayoutProps) {\n const initialize = useGlobalStore((state) => state.initialize);\n\n useEffect(() => {\n try {\n const maybe = initialize();\n if (maybe && typeof (maybe as Promise<void>).then === 'function') {\n (maybe as Promise<void>).catch((error) => {\n console.error('Failed to initialize global state:', error);\n });\n }\n } catch (error) {\n console.error('Failed to initialize global state:', error);\n }\n }, [initialize]);\n\n\n return (\n <div className={clsx(styles.root, className)} data-zone={zone}>\n <GlobalHeader zone={zone}/>\n <main className={styles.main}>{children}</main>\n <GlobalFooter />\n </div>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { Link, Textfield } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport { Breadcrumbs } from '../Breadcrumbs';\nimport { MenuButton } from '../MenuButton';\nimport type { GlobalHeaderProps } from './GlobalHeader.types';\nimport styles from './GlobalHeader.module.css';\nimport logo from '../../logo.svg'; \n\nexport function GlobalHeader({ className, zone }: GlobalHeaderProps) {\n const [searchValue, setSearchValue] = useState('');\n\n return (\n <header className={clsx(styles.header, className)}>\n <div className={styles.headerContainer}>\n <div className={styles.topBarContainer}>\n <Link href=\"https://www.statsbygg.no\">\n <img src={logo} alt=\"Logo\" className={styles.logo} />\n </Link>\n <div className={styles.actionsContainer}>\n <Textfield\n value={searchValue}\n onChange={(e) => setSearchValue(e.target.value)}\n placeholder=\"Søk...\"\n className={styles.searchInput}\n aria-label=\"Søk\"\n />\n <MenuButton zone={zone}/>\n </div>\n </div>\n <Breadcrumbs zone={zone} />\n </div>\n </header>\n );\n}","'use client';\n\nimport { usePathname } from 'next/navigation';\nimport { Breadcrumbs } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport type { BreadcrumbsProps } from './Breadcrumbs.types';\nimport styles from './Breadcrumbs.module.css';\nimport { getBreadcrumbs, getZoneRoot, transformHrefForZone } from '@/routes';\n\nexport function SbBreadcrumbs({ className, zone }: BreadcrumbsProps) {\n const pathname = usePathname();\n const isDev = process.env.NODE_ENV === 'development';\n const prodUrl = 'https://www.statsbygg.no';\n const zoneRoot = getZoneRoot(zone);\n \n const fullPath = isDev && zoneRoot !== '/' && !pathname.startsWith(zoneRoot)\n ? `${zoneRoot}${pathname}`\n : pathname;\n \n const breadcrumbs = getBreadcrumbs(zone, fullPath);\n\n if (breadcrumbs.length <= 1) {\n return null;\n }\n\n\n return (\n <Breadcrumbs aria-label=\"Du er her:\" className={clsx(styles.breadcrumbs, className)}>\n <Breadcrumbs.List>\n {breadcrumbs.map((crumb, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const href = transformHrefForZone(crumb.href, zone, { isDev, prodUrl });\n \n return (\n <Breadcrumbs.Item key={crumb.href}>\n <Breadcrumbs.Link\n href={href}\n aria-current={isLast ? 'page' : undefined}\n className={isLast ? styles.currentLink : styles.link}\n >\n {crumb.label}\n </Breadcrumbs.Link>\n </Breadcrumbs.Item>\n );\n })}\n </Breadcrumbs.List>\n </Breadcrumbs>\n );\n}",".breadcrumbs {\n --dsc-breadcrumbs-color: var(--ds-color-text-default);\n padding: 2.5rem 0 0 0;\n}\n\n.link {\n text-decoration: underline;\n text-underline-offset: 2px;\n color: var(--ds-color-text-default);\n}\n\n.link:hover \n.link:visited{\n color: var(--ds-color-text-default);\n}\n\n.currentLink {\n text-decoration: none;\n font-weight: 500;\n pointer-events: none;\n color: var(--ds-color-text-default);\n}\n","export type RouteNodeInput =\n | { segment: string; label: string; children?: RouteNodeInput[] }\n | { path: string; label: string; children?: RouteNodeInput[] };\n\nexport type RouteNode = {\n path: string;\n label: string;\n children?: RouteNode[];\n};\n\nexport type RouteDefinition = {\n path: string;\n label: string;\n zone: string;\n};\n\nconst ZONE_TREES_INPUT: Record<string, RouteNodeInput> = {\n sbno: {\n segment: '',// primary root route, no breadcrumb\n label: 'Hjem',\n children: [\n { segment: 'nyheter', label: 'Nyheter' },\n ],\n },\n lokaler: {\n segment: 'lokaler',\n label: 'Statens eide og leide lokaler',\n children: [\n {\n segment: 'lokalbruk', label: 'Lokalbruk'\n },\n { segment: 'veiledning', label: 'Veiledning' },\n { segment: 'statlige-eiendommer', label: 'Statlige eiendommer' },\n { segment: 'ledig-for-fremleie', label: 'Ledig for fremleie' },\n { segment: 'statistikk', label: 'Statistikk' },\n ],\n },\n};\n\n\ntype Key = `${string}:${string}`; // `${zone}:${absolutePath}`\n\nconst ROUTES_INDEX: Record<string, RouteDefinition[]> = {};\nconst PARENT_INDEX = new Map<Key, Key | null>(); // child -> parent\nconst ZONE_TREES: Record<string, RouteNode> = {}; // normalized absolute trees\n\nfunction isSegmentNode(n: RouteNodeInput): n is Extract<RouteNodeInput, { segment: string }> {\n return (n as any).segment !== undefined && (n as any).path === undefined;\n}\nfunction isPathNode(n: RouteNodeInput): n is Extract<RouteNodeInput, { path: string }> {\n return (n as any).path !== undefined;\n}\n\nfunction joinPath(base: string, seg: string): string {\n if (!base) return seg ? `/${seg}` : '/';\n return seg ? `${base.replace(/\\/+$/, '')}/${seg.replace(/^\\/+/, '')}` : base || '/';\n}\n\nfunction normalizeToAbsolute(node: RouteNodeInput, base = ''): RouteNode {\n const path = isSegmentNode(node)\n ? joinPath(base, node.segment)\n : isPathNode(node)\n ? (node.path === '' ? '/' : node.path)\n : '/';\n\n const children = (node.children ?? []).map((c) => normalizeToAbsolute(c, path));\n return { path, label: (node as any).label, children: children.length ? children : undefined };\n}\n\n(function buildAll() {\n // Normalize each zone tree to absolute paths\n Object.keys(ZONE_TREES_INPUT).forEach((zone) => {\n ZONE_TREES[zone] = normalizeToAbsolute(ZONE_TREES_INPUT[zone]);\n });\n\n // Build flat indexes + parent relationships\n function walk(zone: string, node: RouteNode, parentKey: Key | null) {\n const def: RouteDefinition = { zone, path: node.path, label: node.label };\n const key: Key = `${zone}:${node.path}`;\n ROUTES_INDEX[zone].push(def);\n PARENT_INDEX.set(key, parentKey);\n for (const child of node.children ?? []) {\n walk(zone, child, key);\n }\n }\n\n (Object.keys(ZONE_TREES) as string[]).forEach((zone) => {\n ROUTES_INDEX[zone] = [];\n walk(zone, ZONE_TREES[zone], null);\n });\n})();\n\n\nfunction findBestMatch(zone: string, pathname: string): RouteDefinition | undefined {\n const list = ROUTES_INDEX[zone] ?? [];\n let best: RouteDefinition | undefined;\n\n for (const r of list) {\n if (pathname === r.path) {\n best = r; // exact wins\n break;\n }\n if (pathname.startsWith(r.path.endsWith('/') ? r.path : r.path + '/')) {\n if (!best || r.path.length > best.path.length) best = r;\n }\n }\n // fallback: zone root\n return best ?? list.find((r) => r.path === ZONE_TREES[zone]?.path);\n}\n\nexport function getZoneRoutes(zone: string): RouteDefinition[] {\n return ROUTES_INDEX[zone] ?? [];\n}\n\n// Top-level links for a zone’s menu (children of the zone root)\nexport function getZoneMenuRoutes(zone: string): RouteDefinition[] {\n const root = ZONE_TREES[zone];\n const children = root?.children ?? [];\n return children.map((c) => ({ zone, path: c.path, label: c.label }));\n}\n\nexport function getAllZones(): string[] {\n return Object.keys(ZONE_TREES);\n}\n\nexport function getZoneRoot(zone: string): string {\n return ZONE_TREES[zone]?.path || '/';\n}\n\n// prettify dynamic slug labels\nfunction labelFromSlug(slug: string): string {\n try {\n const s = decodeURIComponent(slug).replace(/[-_]+/g, ' ').trim();\n return s ? s.charAt(0).toUpperCase() + s.slice(1) : slug;\n } catch {\n return slug;\n }\n}\n\nexport function getBreadcrumbs(\n zone: string,\n pathname: string\n): Array<{ label: string; href: string }> {\n\n const normalizedPathname = pathname === '/' ? pathname : pathname.replace(/\\/+$/, '');\n\n // sbno root has no crumbs\n if (zone === 'sbno' && normalizedPathname === '/') return [];\n\n const match = findBestMatch(zone, normalizedPathname);\n if (!match) return [];\n\n const chain: RouteDefinition[] = [];\n let key: Key | undefined = `${zone}:${match.path}`;\n while (key) {\n const parentKey = PARENT_INDEX.get(key);\n const [z, p] = key.split(':') as [string, string];\n const def = (ROUTES_INDEX[z] ?? []).find((r) => r.path === p);\n if (def) chain.unshift(def);\n key = parentKey ?? undefined;\n }\n\n const homeRoute = (ROUTES_INDEX.sbno ?? []).find((r) => r.path === '/');\n if (\n homeRoute &&\n !(chain.length === 1 && chain[0].zone === 'sbno' && chain[0].path === '/') &&\n (chain.length === 0 || chain[0].path !== homeRoute.path)\n ) {\n chain.unshift(homeRoute);\n }\n\n // If the pathname is deeper than the best static match, add a dynamic tail\n const last = chain[chain.length - 1];\n if (last && normalizedPathname !== last.path && normalizedPathname.startsWith(last.path.endsWith('/') ? last.path : last.path + '/')) {\n const segments = normalizedPathname.split('/').filter(Boolean);\n const tail = segments[segments.length - 1];\n chain.push({ zone, path: normalizedPathname, label: labelFromSlug(tail) });\n }\n\n return chain.map((r) => ({ label: r.label, href: r.path }));\n}\n\nexport function transformHrefForZone(\n targetPath: string,\n currentZone: string,\n options: {\n isDev: boolean;\n prodUrl?: string;\n }\n): string {\n const { isDev, prodUrl } = options;\n\n const targetZone = getZoneFromPathname(targetPath);\n const isCrossZone = targetZone !== currentZone;\n\n if (isCrossZone && isDev && prodUrl) {\n return `${prodUrl}${targetPath}`;\n }\n\n const currentZoneRoot = getZoneRoot(currentZone);\n if (!isCrossZone && isDev && currentZoneRoot !== '/') {\n return targetPath.replace(currentZoneRoot, '') || '/';\n }\n\n return targetPath;\n}\n\nexport function getZoneFromPathname(pathname: string): string {\n if (pathname.startsWith('/lokaler')) return 'lokaler';\n return 'sbno';\n}","'use client';\n\nimport Link from 'next/link';\nimport { Dropdown } from '@digdir/designsystemet-react';\nimport { Menu } from 'lucide-react';\nimport { getZoneMenuRoutes, getAllZones, transformHrefForZone } from '@/routes';\nimport type { MenuButtonProps } from './MenuButton.types';\nimport styles from './MenuButton.module.css';\n\nexport function MenuButton({ zone }: MenuButtonProps) {\n const isDev = process.env.NODE_ENV === 'development';\n // TODO: Temporary here. Should come from env or something\n const prodUrl = 'https://www.statsbygg.no';\n const allZones = getAllZones();\n\n return (\n <Dropdown.TriggerContext>\n <Dropdown.Trigger asChild className={styles.menuButton}>\n <Menu size={20} aria-hidden />\n Meny\n </Dropdown.Trigger>\n <Dropdown>\n {isDev ? (\n <div className={styles.devContainer}>\n {allZones.map((z) => {\n const routes = getZoneMenuRoutes(z);\n return (\n <div key={z} className={styles.zoneSection}>\n <div className={styles.zoneTitle}>{z}</div>\n <Dropdown.List>\n {routes.map((r) => (\n <Dropdown.Item key={`${r.zone}:${r.path}`}>\n <Link href={transformHrefForZone(r.path, zone, { isDev, prodUrl })}>\n {r.label}\n </Link>\n </Dropdown.Item>\n ))}\n </Dropdown.List>\n </div>\n );\n })}\n </div>\n ) : (\n <Dropdown.List>\n {getZoneMenuRoutes(zone).map((r) => (\n <Dropdown.Item key={`${r.zone}:${r.path}`}>\n <Link href={transformHrefForZone(r.path, zone, { isDev, prodUrl })}>\n {r.label}\n </Link>\n </Dropdown.Item>\n ))}\n </Dropdown.List>\n )}\n </Dropdown>\n </Dropdown.TriggerContext>\n );\n}",".userInfo {\n display: flex;\n flex-direction: column;\n gap: var(--ds-spacing-1);\n padding: var(--ds-spacing-2) var(--ds-spacing-3);\n}\n\n.userName {\n font-size: var(--ds-font-size-sm);\n font-weight: var(--ds-font-weight-medium);\n color: var(--ds-color-neutral-text-default);\n}\n\n.userEmail {\n font-size: var(--ds-font-size-xs);\n color: var(--ds-color-neutral-text-subtle);\n}\n\n.menuButton {\n background-color: var(--ds-color-neutral-base-default);\n}\n\n.devContainer {\n display: flex;\n gap: var(--ds-spacing-4);\n padding: var(--ds-spacing-2);\n}\n\n.zoneSection {\n flex: 1;\n min-width: 12rem;\n}\n\n.zoneTitle {\n font-weight: 600;\n padding: var(--ds-spacing-2);\n color: var(--ds-color-neutral-text-default);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n margin-bottom: var(--ds-spacing-2);\n text-transform: capitalize;\n}\n",".header {\n background-color: var(--ds-color-accent-surface-tinted);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.headerContainer {\n max-width: 90rem;\n margin: 0 auto;\n padding: 0 var(--ds-size-30);\n}\n\n.topBarContainer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 0;\n}\n\n.logo {\n margin: 0;\n color: var(--ds-color-neutral-text-default);\n white-space: nowrap;\n display: flex;\n align-items: center;\n min-height: inherit;\n}\n\n.actionsContainer {\n display: flex;\n align-items: stretch;\n gap: var(--ds-size-9);\n min-height: inherit;\n}\n\n.searchInput {\n min-width: 12.5rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 768px) {\n .container {\n padding: 0 var(--ds-spacing-4);\n }\n\n .topBar {\n flex-wrap: wrap;\n padding: var(--ds-spacing-4) 0;\n }\n\n .actions {\n order: 3;\n width: 100%;\n flex-direction: column;\n gap: var(--ds-spacing-3);\n }\n\n .searchInput {\n width: 100%;\n min-width: auto;\n }\n\n .menuButton {\n width: 100%;\n justify-content: center;\n }\n}","'use client';\n\nimport { Paragraph } from '@digdir/designsystemet-react';\nimport clsx from 'clsx';\nimport type { GlobalFooterProps } from './GlobalFooter.types';\nimport styles from './GlobalFooter.module.css';\n\nexport function GlobalFooter({ className }: GlobalFooterProps) {\n\n return (\n <footer className={clsx(styles.footer, className)}>\n <div className={styles.container}>\n <div className={styles.content}>\n <Paragraph>\n Statsbygg Footer\n </Paragraph>\n\n\n </div>\n </div>\n </footer>\n );\n}",".footer {\n background-color: var(--ds-color-neutral-surface-subtle);\n border-top: 1px solid var(--ds-color-neutral-border-subtle);\n margin-top: auto;\n}\n\n.container {\n max-width: 1440px;\n margin: 0 auto;\n padding: var(--ds-spacing-6) var(--ds-spacing-4);\n}\n\n.content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: var(--ds-spacing-4);\n flex-wrap: wrap;\n}\n\n@media (max-width: 768px) {\n .content {\n flex-direction: column;\n align-items: flex-start;\n }\n\n\n}",".root {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n}\n\n.main {\n flex: 1;\n}","import { create, StateCreator } from 'zustand';\nimport { persist, createJSONStorage } from 'zustand/middleware';\n\nexport type Theme = 'light' | 'dark' | 'system';\n\nexport type GlobalState = {\n user?: { id: string; name?: string } | null;\n theme: Theme;\n locale: string;\n setUser: (user: GlobalState['user']) => void;\n setTheme: (theme: Theme) => void;\n setLocale: (locale: string) => void;\n initialize: () => void | Promise<void>;\n};\n\nconst creator: StateCreator<GlobalState, [['zustand/persist', unknown]]> = (set, get) => ({\n user: null,\n theme: 'light',\n locale: 'no',\n setUser: (user) => set({ user }),\n setTheme: (theme) => {\n set({ theme });\n if (typeof document !== 'undefined') {\n document.documentElement.setAttribute('data-color-scheme', theme);\n }\n },\n setLocale: (locale) => set({ locale }),\n initialize: () => {\n if (typeof document !== 'undefined') {\n document.documentElement.setAttribute('data-color-scheme', get().theme);\n }\n },\n});\n\nexport const useGlobalStore = create<GlobalState>()(\n persist(creator, {\n name: 'statsbygg-global-state',\n storage: createJSONStorage(() => localStorage),\n })\n);\n"],"mappings":"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","names":["clsx","Link","clsx","breadcrumbs","link","currentLink","_a","userInfo","userName","userEmail","menuButton","devContainer","zoneSection","zoneTitle","jsx","header","headerContainer","topBarContainer","logo","actionsContainer","searchInput","container","topBar","actions","menuButton","jsx","jsxs","clsx","Link","clsx","footer","container","content","jsx","clsx","root","main","jsx","jsxs","clsx"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["'use client';\n\nexport { RootLayout } from './components/RootLayout';\nexport type { RootLayoutProps } from './components/RootLayout';\n\nexport { useGlobalStore } from './store/globalState';\nexport type { GlobalState } from './store/globalState';\n"],"mappings":";AAEA,SAAS,kBAAkB;AAG3B,SAAS,sBAAsB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsbygg/layout",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "publishConfig": { "access": "public" },
5
5
  "description": "Shared layout components for Statsbygg microfrontend architecture",
6
6
  "main": "./dist/index.js",
@@ -15,8 +15,8 @@
15
15
  }
16
16
  },
17
17
  "scripts": {
18
- "build": "tsup",
19
- "dev": "tsup --watch",
18
+ "build": "tsup && rsync -a --prune-empty-dirs --include='*/' --include='*.module.css' --exclude='*' src/ dist/",
19
+ "dev": "tsup --watch",
20
20
  "lint": "eslint src --ext .ts,.tsx",
21
21
  "type-check": "tsc --noEmit"
22
22
  },
package/dist/index.css DELETED
@@ -1,154 +0,0 @@
1
- /* src/components/Breadcrumbs/Breadcrumbs.module.css */
2
- .Breadcrumbs_breadcrumbs {
3
- --dsc-breadcrumbs-color: var(--ds-color-text-default);
4
- padding: 2.5rem 0 0 0;
5
- }
6
- .Breadcrumbs_link {
7
- text-decoration: underline;
8
- text-underline-offset: 2px;
9
- color: var(--ds-color-text-default);
10
- }
11
- .Breadcrumbs_link:hover .Breadcrumbs_link:visited {
12
- color: var(--ds-color-text-default);
13
- }
14
- .Breadcrumbs_currentLink {
15
- text-decoration: none;
16
- font-weight: 500;
17
- pointer-events: none;
18
- color: var(--ds-color-text-default);
19
- }
20
-
21
- /* src/components/MenuButton/MenuButton.module.css */
22
- .MenuButton_userInfo {
23
- display: flex;
24
- flex-direction: column;
25
- gap: var(--ds-spacing-1);
26
- padding: var(--ds-spacing-2) var(--ds-spacing-3);
27
- }
28
- .MenuButton_userName {
29
- font-size: var(--ds-font-size-sm);
30
- font-weight: var(--ds-font-weight-medium);
31
- color: var(--ds-color-neutral-text-default);
32
- }
33
- .MenuButton_userEmail {
34
- font-size: var(--ds-font-size-xs);
35
- color: var(--ds-color-neutral-text-subtle);
36
- }
37
- .MenuButton_menuButton {
38
- background-color: var(--ds-color-neutral-base-default);
39
- }
40
- .MenuButton_devContainer {
41
- display: flex;
42
- gap: var(--ds-spacing-4);
43
- padding: var(--ds-spacing-2);
44
- }
45
- .MenuButton_zoneSection {
46
- flex: 1;
47
- min-width: 12rem;
48
- }
49
- .MenuButton_zoneTitle {
50
- font-weight: 600;
51
- padding: var(--ds-spacing-2);
52
- color: var(--ds-color-neutral-text-default);
53
- border-bottom: 1px solid var(--ds-color-neutral-border-subtle);
54
- margin-bottom: var(--ds-spacing-2);
55
- text-transform: capitalize;
56
- }
57
-
58
- /* src/components/GlobalHeader/GlobalHeader.module.css */
59
- .GlobalHeader_header {
60
- background-color: var(--ds-color-accent-surface-tinted);
61
- border-bottom: 1px solid var(--ds-color-neutral-border-subtle);
62
- position: sticky;
63
- top: 0;
64
- z-index: 100;
65
- }
66
- .GlobalHeader_headerContainer {
67
- max-width: 90rem;
68
- margin: 0 auto;
69
- padding: 0 var(--ds-size-30);
70
- }
71
- .GlobalHeader_topBarContainer {
72
- display: flex;
73
- justify-content: space-between;
74
- align-items: center;
75
- padding: 1.25rem 0;
76
- }
77
- .GlobalHeader_logo {
78
- margin: 0;
79
- color: var(--ds-color-neutral-text-default);
80
- white-space: nowrap;
81
- display: flex;
82
- align-items: center;
83
- min-height: inherit;
84
- }
85
- .GlobalHeader_actionsContainer {
86
- display: flex;
87
- align-items: stretch;
88
- gap: var(--ds-size-9);
89
- min-height: inherit;
90
- }
91
- .GlobalHeader_searchInput {
92
- min-width: 12.5rem;
93
- display: flex;
94
- align-items: center;
95
- }
96
- @media (max-width: 768px) {
97
- .GlobalHeader_container {
98
- padding: 0 var(--ds-spacing-4);
99
- }
100
- .GlobalHeader_topBar {
101
- flex-wrap: wrap;
102
- padding: var(--ds-spacing-4) 0;
103
- }
104
- .GlobalHeader_actions {
105
- order: 3;
106
- width: 100%;
107
- flex-direction: column;
108
- gap: var(--ds-spacing-3);
109
- }
110
- .GlobalHeader_searchInput {
111
- width: 100%;
112
- min-width: auto;
113
- }
114
- .GlobalHeader_menuButton {
115
- width: 100%;
116
- justify-content: center;
117
- }
118
- }
119
-
120
- /* src/components/GlobalFooter/GlobalFooter.module.css */
121
- .GlobalFooter_footer {
122
- background-color: var(--ds-color-neutral-surface-subtle);
123
- border-top: 1px solid var(--ds-color-neutral-border-subtle);
124
- margin-top: auto;
125
- }
126
- .GlobalFooter_container {
127
- max-width: 1440px;
128
- margin: 0 auto;
129
- padding: var(--ds-spacing-6) var(--ds-spacing-4);
130
- }
131
- .GlobalFooter_content {
132
- display: flex;
133
- justify-content: space-between;
134
- align-items: center;
135
- gap: var(--ds-spacing-4);
136
- flex-wrap: wrap;
137
- }
138
- @media (max-width: 768px) {
139
- .GlobalFooter_content {
140
- flex-direction: column;
141
- align-items: flex-start;
142
- }
143
- }
144
-
145
- /* src/components/RootLayout/RootLayout.module.css */
146
- .RootLayout_root {
147
- display: flex;
148
- flex-direction: column;
149
- min-height: 100vh;
150
- }
151
- .RootLayout_main {
152
- flex: 1;
153
- }
154
- /*# sourceMappingURL=index.css.map */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Breadcrumbs/Breadcrumbs.module.css","../src/components/MenuButton/MenuButton.module.css","../src/components/GlobalHeader/GlobalHeader.module.css","../src/components/GlobalFooter/GlobalFooter.module.css","../src/components/RootLayout/RootLayout.module.css"],"sourcesContent":[".breadcrumbs {\n --dsc-breadcrumbs-color: var(--ds-color-text-default);\n padding: 2.5rem 0 0 0;\n}\n\n.link {\n text-decoration: underline;\n text-underline-offset: 2px;\n color: var(--ds-color-text-default);\n}\n\n.link:hover \n.link:visited{\n color: var(--ds-color-text-default);\n}\n\n.currentLink {\n text-decoration: none;\n font-weight: 500;\n pointer-events: none;\n color: var(--ds-color-text-default);\n}\n",".userInfo {\n display: flex;\n flex-direction: column;\n gap: var(--ds-spacing-1);\n padding: var(--ds-spacing-2) var(--ds-spacing-3);\n}\n\n.userName {\n font-size: var(--ds-font-size-sm);\n font-weight: var(--ds-font-weight-medium);\n color: var(--ds-color-neutral-text-default);\n}\n\n.userEmail {\n font-size: var(--ds-font-size-xs);\n color: var(--ds-color-neutral-text-subtle);\n}\n\n.menuButton {\n background-color: var(--ds-color-neutral-base-default);\n}\n\n.devContainer {\n display: flex;\n gap: var(--ds-spacing-4);\n padding: var(--ds-spacing-2);\n}\n\n.zoneSection {\n flex: 1;\n min-width: 12rem;\n}\n\n.zoneTitle {\n font-weight: 600;\n padding: var(--ds-spacing-2);\n color: var(--ds-color-neutral-text-default);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n margin-bottom: var(--ds-spacing-2);\n text-transform: capitalize;\n}\n",".header {\n background-color: var(--ds-color-accent-surface-tinted);\n border-bottom: 1px solid var(--ds-color-neutral-border-subtle);\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.headerContainer {\n max-width: 90rem;\n margin: 0 auto;\n padding: 0 var(--ds-size-30);\n}\n\n.topBarContainer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 0;\n}\n\n.logo {\n margin: 0;\n color: var(--ds-color-neutral-text-default);\n white-space: nowrap;\n display: flex;\n align-items: center;\n min-height: inherit;\n}\n\n.actionsContainer {\n display: flex;\n align-items: stretch;\n gap: var(--ds-size-9);\n min-height: inherit;\n}\n\n.searchInput {\n min-width: 12.5rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 768px) {\n .container {\n padding: 0 var(--ds-spacing-4);\n }\n\n .topBar {\n flex-wrap: wrap;\n padding: var(--ds-spacing-4) 0;\n }\n\n .actions {\n order: 3;\n width: 100%;\n flex-direction: column;\n gap: var(--ds-spacing-3);\n }\n\n .searchInput {\n width: 100%;\n min-width: auto;\n }\n\n .menuButton {\n width: 100%;\n justify-content: center;\n }\n}",".footer {\n background-color: var(--ds-color-neutral-surface-subtle);\n border-top: 1px solid var(--ds-color-neutral-border-subtle);\n margin-top: auto;\n}\n\n.container {\n max-width: 1440px;\n margin: 0 auto;\n padding: var(--ds-spacing-6) var(--ds-spacing-4);\n}\n\n.content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: var(--ds-spacing-4);\n flex-wrap: wrap;\n}\n\n@media (max-width: 768px) {\n .content {\n flex-direction: column;\n align-items: flex-start;\n }\n\n\n}",".root {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n}\n\n.main {\n flex: 1;\n}"],"mappings":";AAAA,CAACA;AACC,2BAAyB,IAAI;AAC7B,WAAS,OAAO,EAAE,EAAE;AACtB;AAEA,CAACC;AACC,mBAAiB;AACjB,yBAAuB;AACvB,SAAO,IAAI;AACb;AAEA,CANCA,gBAMI,OACL,CAPCA,gBAOI;AACH,SAAO,IAAI;AACb;AAEA,CAACC;AACC,mBAAiB;AACjB,eAAa;AACb,kBAAgB;AAChB,SAAO,IAAI;AACb;;;ACrBA,CAACC;AACC,WAAS;AACT,kBAAgB;AAChB,OAAK,IAAI;AACT,WAAS,IAAI,gBAAgB,IAAI;AACnC;AAEA,CAACC;AACC,aAAW,IAAI;AACf,eAAa,IAAI;AACjB,SAAO,IAAI;AACb;AAEA,CAACC;AACC,aAAW,IAAI;AACf,SAAO,IAAI;AACb;AAEA,CAACC;AACC,oBAAkB,IAAI;AACxB;AAEA,CAACC;AACC,WAAS;AACT,OAAK,IAAI;AACT,WAAS,IAAI;AACf;AAEA,CAACC;AACC,QAAM;AACN,aAAW;AACb;AAEA,CAACC;AACC,eAAa;AACb,WAAS,IAAI;AACb,SAAO,IAAI;AACX,iBAAe,IAAI,MAAM,IAAI;AAC7B,iBAAe,IAAI;AACnB,kBAAgB;AAClB;;;ACxCA,CAACC;AACC,oBAAkB,IAAI;AACtB,iBAAe,IAAI,MAAM,IAAI;AAC7B,YAAU;AACV,OAAK;AACL,WAAS;AACX;AAEA,CAACC;AACC,aAAW;AACX,UAAQ,EAAE;AACV,WAAS,EAAE,IAAI;AACjB;AAEA,CAACC;AACC,WAAS;AACT,mBAAiB;AACjB,eAAa;AACb,WAAS,QAAQ;AACnB;AAEA,CAACC;AACC,UAAQ;AACR,SAAO,IAAI;AACX,eAAa;AACb,WAAS;AACT,eAAa;AACb,cAAY;AACd;AAEA,CAACC;AACC,WAAS;AACT,eAAa;AACb,OAAK,IAAI;AACT,cAAY;AACd;AAEA,CAACC;AACC,aAAW;AACX,WAAS;AACT,eAAa;AACf;AAEA,OAAO,CAAC,SAAS,EAAE;AACjB,GAACC;AACC,aAAS,EAAE,IAAI;AACjB;AAEA,GAACC;AACC,eAAW;AACX,aAAS,IAAI,gBAAgB;AAC/B;AAEA,GAACC;AACC,WAAO;AACP,WAAO;AACP,oBAAgB;AAChB,SAAK,IAAI;AACX;AAEA,GAvBDH;AAwBG,WAAO;AACP,eAAW;AACb;AAEA,GAACI;AACC,WAAO;AACP,qBAAiB;AACnB;AACF;;;ACrEA,CAACC;AACC,oBAAkB,IAAI;AACtB,cAAY,IAAI,MAAM,IAAI;AAC1B,cAAY;AACd;AAEA,CAACC;AACC,aAAW;AACX,UAAQ,EAAE;AACV,WAAS,IAAI,gBAAgB,IAAI;AACnC;AAEA,CAACC;AACC,WAAS;AACT,mBAAiB;AACjB,eAAa;AACb,OAAK,IAAI;AACT,aAAW;AACb;AAEA,OAAO,CAAC,SAAS,EAAE;AACjB,GATDA;AAUG,oBAAgB;AAChB,iBAAa;AACf;AAGF;;;AC3BA,CAACC;AACC,WAAS;AACT,kBAAgB;AAChB,cAAY;AACd;AAEA,CAACC;AACC,QAAM;AACR;","names":["breadcrumbs","link","currentLink","userInfo","userName","userEmail","menuButton","devContainer","zoneSection","zoneTitle","header","headerContainer","topBarContainer","logo","actionsContainer","searchInput","container","topBar","actions","menuButton","footer","container","content","root","main"]}
@@ -1,29 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 75.1 14.9">
3
- <!-- Generator: Adobe Illustrator 29.8.2, SVG Export Plug-In . SVG Version: 2.1.1 Build 3) -->
4
- <defs>
5
- <style>
6
- .st0 {
7
- fill: #131819;
8
- }
9
- </style>
10
- </defs>
11
- <path class="st0" d="M16.6,11.4c-1.2-.5-1.8-1.1-1.8-2s.3-1.2.7-1.5c.5-.4,1.1-.5,1.8-.5s1.1.1,2.1.4v1.6h-.6c0-.4,0-.7-.2-1-.3-.4-.8-.5-1.2-.5-1,0-1.5.5-1.5,1.1s.3.8,1.5,1.4c1.4.6,2.4,1,2.4,2.3s-1.2,2.2-2.5,2.2-1,0-1.8-.3c-.4-.1-.5-.2-.5-.2v-2.1h.6c0,.8,0,2,1.7,2s1.6-.5,1.6-1.2-.3-.9-1.5-1.5l-.5-.2h-.3Z"/>
12
- <path class="st0" d="M41.6,11.4c-1.2-.5-1.8-1.1-1.8-2s.3-1.2.7-1.5c.5-.4,1.1-.5,1.8-.5s1.1.1,2.1.4v1.6h-.6c0-.4,0-.7-.2-1-.3-.4-.8-.5-1.2-.5-1,0-1.5.5-1.5,1.1s.3.8,1.5,1.4c1.4.6,2.4,1,2.4,2.3s-1.2,2.2-2.5,2.2-1,0-1.8-.3c-.4-.1-.5-.2-.5-.2v-2.1h.6c0,.8,0,2,1.7,2s1.6-.5,1.6-1.2-.3-.9-1.5-1.5l-.5-.2h-.3Z"/>
13
- <path class="st0" d="M22.7,8h-1.4c-.5.1-.6.6-.7,1.2h-.4v-1.8h6.2v1.8h-.4c0-.9-.3-1.1-.7-1.2h-1.4v5.6c0,.7.3.7.7.7h.4v.3h-3.2v-.3h.4c.4,0,.7,0,.7-.7v-5.6h-.2Z"/>
14
- <path class="st0" d="M35.3,8h-1.4c-.5.1-.6.6-.7,1.2h-.4v-1.8h6.2v1.8h-.4c0-.9-.3-1.1-.7-1.2h-1.4v5.6c0,.7.3.7.7.7h.4v.3h-3.2v-.3h.4c.4,0,.7,0,.7-.7v-5.6h-.2Z"/>
15
- <path class="st0" d="M30.6,12h-2.5l-.7,1.8v.3c0,.3.5.3.9.3v.3h-2.4v-.3c.5,0,.7,0,1-.7l2.6-6.1h.7l2.6,6.6c0,.1,0,.2.7.2v.3h-2.9v-.3c.8,0,1.1,0,.8-.7l-.6-1.7h-.2ZM30.5,11.5l-1.1-2.7-1.1,2.7s2.2,0,2.2,0Z"/>
16
- <path class="st0" d="M46.6,8.8c0-.7,0-.9-.5-.9h-.3v-.3h3.3c.5,0,.9,0,1.3.2.7.4.8,1.2.8,1.4,0,.4,0,.7-.4,1.1-.4.4-.8.6-1.1.7.3,0,.9.2,1.4.5.4.3.7.9.7,1.4s-.3,1.2-.8,1.5c-.5.4-1.2.3-1.5.3h-3.7v-.3c.7,0,.9,0,.9-.8v-4.8h-.1ZM47.7,10.7h1.7c.3-.1.7-.4.7-1.3s0-.9-.4-1.1c-.3-.3-.8-.3-.9-.3h-.8q-.2,0-.2.5v2.2h0ZM47.7,13.7c0,.3,0,.4.2.5.2,0,1,.1,1.2.1.3,0,.6,0,.9-.2.6-.4.6-1.1.6-1.2,0-.3,0-.7-.4-1.1s-.9-.7-2.5-.6v2.6h0Z"/>
17
- <path class="st0" d="M54.9,11.5l-2-3c-.3-.5-.4-.6-1.1-.6v-.3h3.1v.3h-.4c-.2,0-.4,0-.4.2s0,0,0,.2l1.7,2.7,1.4-2.1c.3-.4.4-.5.4-.8s0-.2-.8-.2v-.3h2.2v.3c-.4,0-.6,0-.8.4l-2.4,3.3v2.1c0,.2,0,.6.3.7h.7v.3h-3.3v-.3h.4c.4,0,.7,0,.7-.7v-2.2h.2Z"/>
18
- <path class="st0" d="M63.7,11.2h3v.3c-.7,0-.7.1-.7.6v2.1c-.3,0-.5.1-.7.2-1.1.3-1.6.4-2.3.4-2.5,0-3.9-1.7-3.9-3.9s.6-2.3,1.3-2.8c.8-.7,1.8-.8,2.5-.8s.9,0,1.7.2q.8.1,1.3.2v2h-.5c0-.4,0-.8-.5-1.2-.5-.4-1.2-.6-1.8-.6-1.8,0-2.7,1.3-2.7,2.9s.3,1.9.7,2.4c.7,1,1.7,1.1,2.3,1.1s.6,0,1-.1c.5-.2.5-.3.5-.8v-1.1c0-.6,0-.7-.8-.7h-.3v-.4h0Z"/>
19
- <path class="st0" d="M72.1,11.2h3v.3c-.7,0-.7.1-.7.6v2.1c-.3,0-.5.1-.7.2-1.1.3-1.6.4-2.3.4-2.5,0-3.9-1.7-3.9-3.9s.6-2.3,1.3-2.8c.8-.7,1.8-.8,2.5-.8s.9,0,1.7.2q.8.1,1.3.2v2h-.5c0-.4,0-.8-.5-1.2-.5-.4-1.2-.6-1.8-.6-1.8,0-2.7,1.3-2.7,2.9s.3,1.9.7,2.4c.7,1,1.7,1.1,2.3,1.1s.6,0,1-.1c.5-.2.5-.3.5-.8v-1.1c0-.6,0-.7-.8-.7h-.3v-.4h0Z"/>
20
- <g>
21
- <g>
22
- <polygon class="st0" points="0 9.9 .7 10.6 9.7 10.6 10.4 9.9 5.2 7.3 0 9.9"/>
23
- <rect class="st0" x=".7" y="11.4" width="9" height=".6"/>
24
- <rect class="st0" x=".7" y="12.7" width="9" height=".6"/>
25
- <rect class="st0" x=".7" y="14.1" width="9" height=".6"/>
26
- </g>
27
- <path class="st0" d="M8.1,3.1c-.3,0-.7,0-.9.2-.1-.1-.3-.2-.6-.2s-.8.2-.9.2h-.2s.5-.2.5-.8-.7-.8-.7-.8v-.9h.5v-.3h-.5v-.5h-.3v.5h-.5v.3h.5v.9s-.7,0-.7.8.5.8.5.8h-.2c-.1,0-.5-.2-.9-.2s-.5.1-.6.2c-.2-.1-.6-.2-.9-.2-.5,0-1.1.4-1,.9,0,.5.5,2.3.5,2.3h6.9s.4-1.8.5-2.3c0-.5-.5-.9-1-.9ZM3.2,5.2s-.2.5-.8.5-.9-.4-.9-.7h.1s.2.2.4.2.3-.1.3-.3-.1-.3-.2-.3c-.2,0-.3.2-.4.2,0,0-.2,0-.1-.1,0,0,.3-.2.3-.4s-.2-.3-.3-.3c0-.2.2-.6.8-.6s.8.1.8.1v.5s-.2,0-.2.3.2.4.2.4h0q0,.1-.1,0s-.2-.2-.3-.2-.2.1-.2.3.1.3.2.3.3-.2.3-.2h.1v.2h0ZM5,5.2s-.3.5-.8.5-.8-.5-.8-.5v-.2h.1s.2.2.3.2.2-.1.2-.3-.1-.3-.2-.3-.2.1-.3.2h-.1c0-.1.2-.3.2-.5s-.2-.3-.2-.3v-.4c0-.2.2-.2.4-.2s.9,0,1.1.1v.5s-.2,0-.2.3.2.4.2.4h0q0,.1-.1,0s-.2-.2-.3-.2-.2.1-.2.3.1.3.2.3.3-.2.3-.2h.1v.2h0ZM7,5.2s-.3.5-.8.5-.8-.5-.8-.5v-.2h.1s.2.2.3.2.2-.1.2-.3-.1-.3-.2-.3-.2.1-.3.2h-.1c0-.1.2-.3.2-.5s-.2-.3-.2-.3v-.5c.2,0,.9-.1,1.1-.1s.4,0,.4.2v.4s-.2,0-.2.3.2.4.2.4h0q0,.1-.1,0s-.2-.2-.3-.2-.2.1-.2.3.1.3.2.3.3-.2.3-.2h.1v.2h0ZM8.8,4.7s0,.1-.1.1c0,0-.2-.2-.4-.2s-.2.2-.2.3.2.3.3.3.3-.2.4-.2h.1c0,.3-.3.7-.9.7s-.8-.5-.8-.5v-.2h.1s.2.2.3.2.2-.1.2-.3-.1-.3-.2-.3-.2.1-.3.2h-.1c0-.1.2-.3.2-.5s-.2-.3-.2-.3v-.5s0-.1.8-.1.8.4.8.6c-.1,0-.3,0-.3.3s.2.3.3.4ZM8.3,4.5c-.1,0-.2.1-.2.3s.2.3.3.3"/>
28
- </g>
29
- </svg>