Skip to content

Commit 607defd

Browse files
committed
Merge branch 'main' into olejorgenbakken/issue4566
2 parents 39a5789 + 57854ff commit 607defd

File tree

52 files changed

+1232
-445
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1232
-445
lines changed

.storybook/main.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ const config: StorybookConfig = {
55
stories: ["../packages/jokul/**/*.stories.@(ts|tsx)"],
66
staticDirs: ["../storybook-public"],
77
addons: [
8-
"@storybook/addon-onboarding",
98
"@storybook/addon-essentials",
109
"@chromatic-com/storybook",
1110
"@storybook/addon-interactions",
1211
],
12+
features: {
13+
backgroundsStoryGlobals: true,
14+
},
1315
framework: {
1416
name: "@storybook/react-vite",
1517
options: {},

.storybook/preview-body.html

-3
This file was deleted.

.storybook/preview.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,42 @@ import React from "react";
44
import "../packages/jokul/src/components/card/styles/_index.scss";
55
import { PropDocs } from "./docs/props/PropDocs.js";
66
import "./global.scss";
7+
import { themeDecorator, themeGlobal, themes } from "./theme.js";
78

89
const preview: Preview = {
10+
globalTypes: {
11+
theme: themeGlobal,
12+
},
13+
initialGlobals: {
14+
theme: themes[0],
15+
backgrounds: { value: "page" },
16+
},
17+
decorators: [themeDecorator],
918
parameters: {
19+
backgrounds: {
20+
options: {
21+
page: {
22+
name: "Page",
23+
value: "var(--jkl-color-background-page)",
24+
},
25+
pageVariant: {
26+
name: "Page variant",
27+
value: "var(--jkl-color-background-page-variant)",
28+
},
29+
container: {
30+
name: "Container",
31+
value: "var(--jkl-color-background-container)",
32+
},
33+
containerLow: {
34+
name: "Container low",
35+
value: "var(--jkl-color-background-container-low)",
36+
},
37+
containerHigh: {
38+
name: "Container high",
39+
value: "var(--jkl-color-background-container-high)",
40+
},
41+
},
42+
},
1043
options: {
1144
storySort: (a, b) => {
1245
let compareBy = "name";

.storybook/theme.tsx

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ReactRenderer } from "@storybook/react";
2+
import React, { useEffect } from "react";
3+
import { DecoratorFunction } from "storybook/internal/types";
4+
5+
export const themes = [undefined, "light", "dark"] as const;
6+
7+
const applyTheme = (element: HTMLElement, theme: (typeof themes)[number]) => {
8+
element.classList.add("jkl");
9+
element.dataset["theme"] = theme;
10+
};
11+
12+
const clearTheme = (element: HTMLElement) => {
13+
delete element.dataset["theme"];
14+
};
15+
16+
export const themeGlobal = {
17+
description: "Fargetema for eksemplet",
18+
toolbar: {
19+
title: "Fargetema",
20+
icon: "paintbrush",
21+
items: [
22+
{ title: "Automatisk", value: themes[0], icon: "contrast" },
23+
{ title: "Lyst", value: themes[1], icon: "sun" },
24+
{ title: "Mørkt", value: themes[2], icon: "moon" },
25+
],
26+
dynamicTitle: true,
27+
},
28+
};
29+
30+
export const themeDecorator: DecoratorFunction<ReactRenderer, {}> = (
31+
Story,
32+
context,
33+
) => {
34+
useEffect(() => {
35+
const body = window.document.body;
36+
clearTheme(body);
37+
applyTheme(body, context.globals.theme);
38+
39+
return () => clearTheme(body);
40+
}, [context.globals.theme]);
41+
42+
return <Story />;
43+
};

ny-portal/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@portabletext/react": "^3.2.1",
3030
"@sanity/client": "^6.28.1",
3131
"@sanity/image-url": "^1.1.0",
32+
"@sanity/ui": "^2.14.3",
3233
"@sanity/vision": "^3.76.3",
3334
"@types/mdx": "^2.0.13",
3435
"clsx": "^2.1.1",

ny-portal/src/app/(frontend)/komponenter/[slug]/page.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import PortableTextRenderer from "@/components/portable-text";
2+
import { PropDocumentation } from "@/components/prop-documentation/PropDocumentation";
23
import { client } from "@/sanity/client";
34
import { componentPageBySlugQuery } from "@/sanity/queries/componentPage";
45

@@ -18,6 +19,10 @@ export default async function Page({
1819
{data?.lede && <PortableTextRenderer value={data.lede} />}
1920

2021
{data?.content && <PortableTextRenderer value={data.content} />}
22+
23+
{data?.component_folder && (
24+
<PropDocumentation component={data.component_folder} />
25+
)}
2126
</>
2227
);
2328
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import { NextResponse } from "next/server";
4+
import glob from "tiny-glob";
5+
6+
const packageRoot = path.resolve(
7+
process.cwd(),
8+
"..",
9+
"packages",
10+
"jokul",
11+
"src",
12+
"components",
13+
);
14+
15+
export async function GET() {
16+
try {
17+
const paths = (await glob("*", { cwd: packageRoot })).filter(
18+
(component) =>
19+
fs.statSync(path.resolve(packageRoot, component)).isDirectory(),
20+
);
21+
22+
const formattedOptions = paths.sort().map((component) => ({
23+
title: component,
24+
value: component,
25+
}));
26+
27+
return NextResponse.json(formattedOptions);
28+
} catch (error) {
29+
console.error("Error reading component folders:", error);
30+
return NextResponse.json(
31+
{ error: "Failed to read component folders" },
32+
{ status: 500 },
33+
);
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Select } from "@sanity/ui";
2+
import React, { useEffect, useState } from "react";
3+
import { set, unset } from "sanity";
4+
import type { StringInputProps } from "sanity";
5+
6+
type ComponentFolderOption = {
7+
title: string;
8+
value: string;
9+
};
10+
11+
export function ComponentFolderInput(props: StringInputProps) {
12+
const { value, onChange } = props;
13+
const [options, setOptions] = useState<ComponentFolderOption[]>([]);
14+
const [loading, setLoading] = useState<boolean>(true);
15+
16+
const handleChange = React.useCallback(
17+
(event: React.FormEvent<HTMLSelectElement> | undefined) => {
18+
const value = event?.currentTarget.value;
19+
20+
// If the selected option has a value,
21+
// it will be written to the document
22+
// otherwise the field will be cleared
23+
onChange(value ? set(value) : unset());
24+
},
25+
[onChange],
26+
);
27+
28+
useEffect(() => {
29+
async function fetchData() {
30+
try {
31+
const componentsResult = await fetch("/api/component-folders", {
32+
cache: "no-store",
33+
});
34+
35+
const components: ComponentFolderOption[] =
36+
await componentsResult.json();
37+
38+
const formattedOptions: ComponentFolderOption[] =
39+
components.map(({ title, value }) => ({
40+
title,
41+
value,
42+
}));
43+
44+
setOptions(formattedOptions);
45+
} catch (error) {
46+
console.error("Failed to fetch component folders:", error);
47+
} finally {
48+
setLoading(false);
49+
}
50+
}
51+
52+
fetchData();
53+
}, []);
54+
55+
return (
56+
<Select
57+
onChange={handleChange}
58+
disabled={loading || options.length === 0}
59+
value={value}
60+
>
61+
<option value="">-- Velg komponent --</option>
62+
{options.map((option) => (
63+
<option key={option.value} value={option.value}>
64+
{option.title}
65+
</option>
66+
))}
67+
</Select>
68+
);
69+
}

ny-portal/src/sanity/extract.json

+7
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,13 @@
10691069
}
10701070
},
10711071
"optional": true
1072+
},
1073+
"component_folder": {
1074+
"type": "objectAttribute",
1075+
"value": {
1076+
"type": "string"
1077+
},
1078+
"optional": true
10721079
}
10731080
}
10741081
},

ny-portal/src/sanity/schemas/componentPage.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { defineField, defineType } from "sanity";
2+
import { ComponentFolderInput } from "../components/ComponentFolderInput";
23

34
const MAX_LENGTH = 70;
45

@@ -36,5 +37,14 @@ export const componentPage = defineType({
3637
type: "array",
3738
of: [{ type: "block" }],
3839
}),
40+
defineField({
41+
name: "component_folder",
42+
title: "Komponentmappe",
43+
type: "string",
44+
components: {
45+
input: ComponentFolderInput,
46+
},
47+
validation: (Rule) => Rule.required(),
48+
}),
3949
],
4050
});

ny-portal/src/sanity/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ export type Jokul_componentPage = {
185185
_type: "block";
186186
_key: string;
187187
}>;
188+
component_folder?: string;
188189
};
189190

190191
export type Slug = {
@@ -276,6 +277,7 @@ export type ComponentPageBySlugQueryResult = {
276277
_type: "block";
277278
_key: string;
278279
}>;
280+
component_folder?: string;
279281
} | null;
280282

281283
// Query TypeMap

0 commit comments

Comments
 (0)