@altinn/altinn-components 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci-cd-main.yml +5 -2
- package/.github/workflows/workflow-deploy-storybook.yml +35 -0
- package/.storybook/StoryDecorator.tsx +10 -8
- package/CHANGELOG.md +14 -0
- package/README.md +20 -2
- package/lib/components/Attachment/AttachmentLink.stories.ts +0 -2
- package/lib/components/Avatar/avatar.stories.tsx +1 -0
- package/lib/components/Button/IconButton.tsx +21 -0
- package/lib/components/Button/buttonBase.module.css +17 -2
- package/lib/components/Button/iconButton.module.css +14 -0
- package/lib/components/Button/index.ts +1 -0
- package/lib/components/Dialog/Dialog.stories.ts +0 -2
- package/lib/components/Dialog/DialogAttachments.stories.ts +0 -2
- package/lib/components/Dialog/DialogHeader.stories.ts +0 -2
- package/lib/components/Dialog/DialogListItem.tsx +3 -0
- package/lib/components/Dialog/DialogMetadata.stories.ts +0 -2
- package/lib/components/Dialog/DialogNav.stories.ts +0 -2
- package/lib/components/Dialog/DialogSeenBy.stories.tsx +5 -7
- package/lib/components/Dialog/DialogTitle.stories.ts +0 -2
- package/lib/components/Dialog/dialogListItemBase.module.css +1 -1
- package/lib/components/Dropdown/Backdrop.tsx +11 -0
- package/lib/components/Dropdown/DrawerBase.tsx +17 -0
- package/lib/components/Dropdown/DropdownBase.tsx +17 -0
- package/lib/components/Dropdown/backdrop.module.css +8 -0
- package/lib/components/Dropdown/drawerBase.module.css +8 -0
- package/lib/components/Dropdown/dropdownBase.module.css +18 -0
- package/lib/components/Dropdown/index.ts +3 -0
- package/lib/components/Footer/Footer.stories.ts +37 -0
- package/lib/components/Footer/Footer.tsx +21 -0
- package/lib/components/Footer/FooterAddress.tsx +12 -0
- package/lib/components/Footer/FooterBase.tsx +16 -0
- package/lib/components/Footer/FooterLogo.tsx +17 -0
- package/lib/components/Footer/FooterMenu.tsx +43 -0
- package/lib/components/Footer/footerAddress.module.css +8 -0
- package/lib/components/Footer/footerBase.module.css +28 -0
- package/lib/components/Footer/footerLogo.module.css +12 -0
- package/lib/components/Footer/footerMenu.module.css +30 -0
- package/lib/components/Footer/index.ts +1 -0
- package/lib/components/{Header → GlobalMenu}/GlobalMenu.stories.tsx +1 -13
- package/lib/components/{Header → GlobalMenu}/GlobalMenu.tsx +14 -23
- package/lib/components/GlobalMenu/index.tsx +1 -0
- package/lib/components/Header/Header.stories.ts +61 -33
- package/lib/components/Header/Header.tsx +43 -17
- package/lib/components/Header/HeaderBase.tsx +10 -3
- package/lib/components/Header/HeaderButton.stories.ts +16 -0
- package/lib/components/Header/HeaderButton.tsx +12 -0
- package/lib/components/Header/HeaderMenu.tsx +17 -0
- package/lib/components/Header/header.module.css +51 -13
- package/lib/components/Header/headerBase.module.css +8 -0
- package/lib/components/Header/headerButton.module.css +1 -0
- package/lib/components/Header/headerMenu.module.css +3 -0
- package/lib/components/Header/index.tsx +0 -1
- package/lib/components/Layout/Layout.stories.tsx +264 -0
- package/lib/components/Layout/Layout.tsx +11 -7
- package/lib/components/Layout/LayoutBase.tsx +1 -1
- package/lib/components/Layout/LayoutBody.tsx +1 -1
- package/lib/components/Layout/LayoutContent.tsx +1 -1
- package/lib/components/Layout/LayoutSidebar.tsx +11 -4
- package/lib/components/Layout/layoutBase.module.css +23 -0
- package/lib/components/Layout/layoutBody.module.css +14 -0
- package/lib/components/Layout/layoutContent.module.css +8 -0
- package/lib/components/Layout/layoutSidebar.module.css +19 -0
- package/lib/components/LayoutAction/ActionFooter.stories.tsx +70 -0
- package/lib/components/LayoutAction/ActionFooter.tsx +15 -0
- package/lib/components/LayoutAction/ActionHeader.stories.ts +20 -0
- package/lib/components/LayoutAction/ActionHeader.tsx +19 -0
- package/lib/components/LayoutAction/ActionMenu.stories.tsx +39 -0
- package/lib/components/LayoutAction/ActionMenu.tsx +22 -0
- package/lib/components/LayoutAction/actionFooter.module.css +28 -0
- package/lib/components/LayoutAction/actionHeader.module.css +55 -0
- package/lib/components/LayoutAction/actionMenu.module.css +25 -0
- package/lib/components/LayoutAction/index.ts +3 -0
- package/lib/components/Menu/MenuBase.tsx +4 -2
- package/lib/components/Menu/MenuItemBase.tsx +5 -3
- package/lib/components/RootProvider/RootProvider.tsx +19 -0
- package/lib/components/RootProvider/index.ts +1 -0
- package/lib/components/Snackbar/Snackbar.stories.tsx +21 -0
- package/lib/components/Snackbar/Snackbar.tsx +32 -0
- package/lib/components/Snackbar/SnackbarBase.tsx +39 -0
- package/lib/components/Snackbar/SnackbarLabel.tsx +10 -0
- package/lib/components/Snackbar/SnackbarMedia.tsx +14 -0
- package/lib/components/Snackbar/index.ts +4 -0
- package/lib/components/Snackbar/snackbarBase.module.css +55 -0
- package/lib/components/Snackbar/snackbarLabel.module.css +6 -0
- package/lib/components/Snackbar/snackbarMedia.module.css +10 -0
- package/lib/components/Toolbar/ToolbarAdd.stories.ts +0 -2
- package/lib/components/Toolbar/ToolbarFilter.stories.ts +0 -2
- package/lib/components/index.ts +5 -0
- package/package.json +1 -1
- package/lib/components/Layout/Layout.stories.ts +0 -124
- package/lib/components/Layout/layout.module.css +0 -63
- /package/lib/components/Header/{globalMenu.module.css → mobileMenu.module.css} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
name: CI/CD Main
|
|
1
2
|
on:
|
|
2
3
|
push:
|
|
3
4
|
branches:
|
|
@@ -6,10 +7,12 @@ on:
|
|
|
6
7
|
permissions:
|
|
7
8
|
contents: write
|
|
8
9
|
pull-requests: write
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
11
12
|
|
|
12
13
|
jobs:
|
|
14
|
+
deploy-documentation:
|
|
15
|
+
uses: ./.github/workflows/workflow-deploy-storybook.yml
|
|
13
16
|
release-please:
|
|
14
17
|
runs-on: ubuntu-latest
|
|
15
18
|
steps:
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Deploy Storybook to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pages: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: "pages"
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
deploy:
|
|
18
|
+
environment:
|
|
19
|
+
name: github-pages
|
|
20
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
- name: Setup PNPM
|
|
26
|
+
uses: pnpm/action-setup@v2
|
|
27
|
+
- run: pnpm install --frozen-lockfile
|
|
28
|
+
- run: pnpm build-storybook
|
|
29
|
+
- name: Upload artifact
|
|
30
|
+
uses: actions/upload-pages-artifact@v3
|
|
31
|
+
with:
|
|
32
|
+
path: "./storybook-static"
|
|
33
|
+
- name: Deploy to GitHub Pages
|
|
34
|
+
id: deployment
|
|
35
|
+
uses: actions/deploy-pages@v4
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ReactNode} from "react";
|
|
2
2
|
import styles from "./storyDecorator.module.css";
|
|
3
|
+
import {RootProvider} from "../lib/components/RootProvider/";
|
|
3
4
|
|
|
4
5
|
interface StoryDecoratorProps {
|
|
5
6
|
tags: string[];
|
|
@@ -16,12 +17,13 @@ export const StoryDecorator = ({
|
|
|
16
17
|
const state = isStable ? "stable" : "experimental";
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
<RootProvider>
|
|
21
|
+
<div className={styles.preview} data-theme={theme}>
|
|
22
|
+
<div className={styles.component}>{children}</div>
|
|
23
|
+
<span className={styles.tag} data-tag={state}>
|
|
24
|
+
{state}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
</RootProvider>
|
|
26
28
|
);
|
|
27
29
|
};
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0](https://github.com/Altinn/altinn-components/compare/v0.3.0...v0.4.0) (2024-11-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add footer component ([#40](https://github.com/Altinn/altinn-components/issues/40)) ([bdf5c0c](https://github.com/Altinn/altinn-components/commit/bdf5c0cd68c374ac5fe83536033074289f379abe))
|
|
9
|
+
|
|
10
|
+
## [0.3.0](https://github.com/Altinn/altinn-components/compare/v0.2.2...v0.3.0) (2024-11-08)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add snackbar and bulk operation action components ([#38](https://github.com/Altinn/altinn-components/issues/38)) ([a39178d](https://github.com/Altinn/altinn-components/commit/a39178d060819e6943b1d1a5632832529b8f4165))
|
|
16
|
+
|
|
3
17
|
## [0.2.2](https://github.com/Altinn/altinn-components/compare/v0.2.1...v0.2.2) (2024-11-06)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -17,7 +17,25 @@ pnpm add @altinn/components
|
|
|
17
17
|
```
|
|
18
18
|
Tested with Node.js 20.x <
|
|
19
19
|
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
React `>=18`in your project.
|
|
23
|
+
|
|
20
24
|
## Usage
|
|
25
|
+
Wrap your application in RootProvider to enable shared context across all components. Here’s a basic setup:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { RootProvider } from '@altinn/components';
|
|
29
|
+
|
|
30
|
+
function App() {
|
|
31
|
+
return (
|
|
32
|
+
<RootProvider>
|
|
33
|
+
{ /* Your application here */ }
|
|
34
|
+
</RootProvider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
21
39
|
To use the components in your application, you need to import the components you want to use from the package. For example:
|
|
22
40
|
|
|
23
41
|
```tsx
|
|
@@ -26,9 +44,9 @@ import { Avatar, type AvatarVariant } from '@altinn/components';
|
|
|
26
44
|
```
|
|
27
45
|
and import the css file in your application once:
|
|
28
46
|
```ts
|
|
29
|
-
import '@altinn/components/
|
|
47
|
+
import '@altinn/altinn-components/lib/css/global.css';
|
|
30
48
|
```
|
|
31
49
|
for correct `font-family` and minimal collection of resets.
|
|
32
50
|
|
|
33
51
|
## Documentation
|
|
34
|
-
The documentation for the components can be found in the
|
|
52
|
+
The documentation for the components can be found in the [Storybook](https://altinn.github.io/altinn-components)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import { ButtonBase, type ButtonColor, type ButtonSize, type ButtonVariant } from '../Button';
|
|
3
|
+
import { Icon, type IconName } from '../Icon';
|
|
4
|
+
import styles from './iconButton.module.css';
|
|
5
|
+
|
|
6
|
+
interface IconButtonProps {
|
|
7
|
+
icon: IconName;
|
|
8
|
+
color?: ButtonColor;
|
|
9
|
+
size?: ButtonSize;
|
|
10
|
+
variant?: ButtonVariant;
|
|
11
|
+
className?: string;
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const IconButton = ({ className, variant, color, size, icon, onClick }: IconButtonProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<ButtonBase variant={variant} color={color} size={size} className={cx(styles.button, className)} onClick={onClick}>
|
|
18
|
+
<Icon name={icon} className={styles.icon} />
|
|
19
|
+
</ButtonBase>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
@@ -56,14 +56,12 @@
|
|
|
56
56
|
/* outline */
|
|
57
57
|
|
|
58
58
|
.button[data-variant="outline"] {
|
|
59
|
-
border-color: var(--theme-base-hover);
|
|
60
59
|
border-style: solid;
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
/* dotted */
|
|
64
63
|
|
|
65
64
|
.button[data-variant="dotted"] {
|
|
66
|
-
border-color: var(--theme-base-hover);
|
|
67
65
|
border-style: dotted;
|
|
68
66
|
}
|
|
69
67
|
|
|
@@ -78,6 +76,23 @@
|
|
|
78
76
|
color: var(--theme-text-default);
|
|
79
77
|
}
|
|
80
78
|
|
|
79
|
+
/* primary color */
|
|
80
|
+
|
|
81
|
+
.button[data-color="primary"] {
|
|
82
|
+
border-color: var(--theme-base-default);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.button[data-color="primary"]:hover {
|
|
86
|
+
border-color: var(--theme-base-hover);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.button[data-color="primary"][data-variant="solid"],
|
|
90
|
+
.button[data-color="primary"][data-variant="solid"] {
|
|
91
|
+
border-color: var(--theme-base-default);
|
|
92
|
+
background-color: var(--theme-base-default);
|
|
93
|
+
color: white;
|
|
94
|
+
}
|
|
95
|
+
|
|
81
96
|
/* secondary color */
|
|
82
97
|
|
|
83
98
|
.button[data-color="secondary"] {
|
|
@@ -53,6 +53,8 @@ export type DialogListItemProps = {
|
|
|
53
53
|
touchedBy?: DialogTouchedByActor[];
|
|
54
54
|
/** Number of attachments */
|
|
55
55
|
attachmentsCount?: number;
|
|
56
|
+
/** OnClick handler */
|
|
57
|
+
onClick?: () => void;
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
/**
|
|
@@ -82,6 +84,7 @@ export const DialogListItem = ({
|
|
|
82
84
|
attachmentsCount,
|
|
83
85
|
title,
|
|
84
86
|
summary,
|
|
87
|
+
onClick,
|
|
85
88
|
...rest
|
|
86
89
|
}: DialogListItemProps) => {
|
|
87
90
|
return (
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { fn } from '@storybook/test';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
|
|
5
2
|
import { DialogSeenBy } from './DialogSeenBy';
|
|
6
3
|
|
|
7
4
|
const meta = {
|
|
@@ -12,6 +9,7 @@ const meta = {
|
|
|
12
9
|
args: {
|
|
13
10
|
seenByEndUser: true,
|
|
14
11
|
seenByOthersCount: 2,
|
|
12
|
+
label: '',
|
|
15
13
|
},
|
|
16
14
|
} satisfies Meta<typeof DialogSeenBy>;
|
|
17
15
|
|
|
@@ -39,17 +37,17 @@ export const seenByEndUserAndOthers: Story = {
|
|
|
39
37
|
},
|
|
40
38
|
};
|
|
41
39
|
|
|
42
|
-
export const ExampleLabel = ({
|
|
43
|
-
|
|
40
|
+
export const ExampleLabel = ({
|
|
41
|
+
seenByEndUser,
|
|
42
|
+
seenByOthersCount,
|
|
43
|
+
}: { seenByEndUser: boolean; seenByOthersCount: number }) => {
|
|
44
44
|
const seenByLabel = [];
|
|
45
45
|
|
|
46
46
|
if (seenByEndUser) {
|
|
47
|
-
seen = true;
|
|
48
47
|
seenByLabel.push('deg');
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
if (seenByOthersCount) {
|
|
52
|
-
seen = true;
|
|
53
51
|
seenByLabel.push(seenByOthersCount);
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import styles from './backdrop.module.css';
|
|
3
|
+
|
|
4
|
+
export interface BackdropProps {
|
|
5
|
+
expanded?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Backdrop = ({ expanded = false, className }: BackdropProps) => {
|
|
10
|
+
return <div className={cx(styles.backdrop, className)} aria-expanded={expanded} />;
|
|
11
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import styles from './drawerBase.module.css';
|
|
4
|
+
|
|
5
|
+
export interface DrawerBaseProps {
|
|
6
|
+
expanded?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DrawerBase = ({ expanded = false, className, children }: DrawerBaseProps) => {
|
|
12
|
+
return (
|
|
13
|
+
<div className={cx(styles.drawer, className)} aria-expanded={expanded}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import styles from './dropdownBase.module.css';
|
|
4
|
+
|
|
5
|
+
export interface DropdownBaseProps {
|
|
6
|
+
expanded?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const DropdownBase = ({ expanded = false, className, children }: DropdownBaseProps) => {
|
|
12
|
+
return (
|
|
13
|
+
<div className={cx(styles.dropdown, className)} aria-expanded={expanded}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.dropdown {
|
|
2
|
+
display: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.dropdown[aria-expanded="true"] {
|
|
6
|
+
display: block;
|
|
7
|
+
position: absolute;
|
|
8
|
+
right: 0;
|
|
9
|
+
z-index: 2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.dropdown {
|
|
13
|
+
margin-top: 0.5rem;
|
|
14
|
+
padding: 0 0.5rem;
|
|
15
|
+
background-color: var(--neutral-background-default);
|
|
16
|
+
border-radius: 2px;
|
|
17
|
+
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Footer } from './Footer';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Footer/Footer',
|
|
6
|
+
component: Footer,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {},
|
|
9
|
+
args: {
|
|
10
|
+
address: 'Postboks 1382 Vika, 0114 Oslo.',
|
|
11
|
+
menu: {
|
|
12
|
+
items: [
|
|
13
|
+
{
|
|
14
|
+
id: '1',
|
|
15
|
+
title: 'Om Altinn',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: '2',
|
|
19
|
+
title: 'Driftsmeldinger',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: '3',
|
|
23
|
+
title: 'Personvern',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: '4',
|
|
27
|
+
title: 'Tilgjengelighet',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
} satisfies Meta<typeof Footer>;
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof meta>;
|
|
36
|
+
|
|
37
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FooterAddress } from './FooterAddress';
|
|
2
|
+
import { FooterBase } from './FooterBase';
|
|
3
|
+
import { FooterLogo } from './FooterLogo';
|
|
4
|
+
import { FooterMenu, type FooterMenuProps } from './FooterMenu';
|
|
5
|
+
|
|
6
|
+
export interface FooterProps {
|
|
7
|
+
address: string;
|
|
8
|
+
menu: FooterMenuProps;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Footer = ({ address, menu }: FooterProps) => {
|
|
12
|
+
return (
|
|
13
|
+
<FooterBase>
|
|
14
|
+
<FooterAddress>
|
|
15
|
+
<FooterLogo />
|
|
16
|
+
{address}
|
|
17
|
+
</FooterAddress>
|
|
18
|
+
<FooterMenu {...menu} />
|
|
19
|
+
</FooterBase>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import styles from './footerAddress.module.css';
|
|
4
|
+
|
|
5
|
+
export interface FooterAddressProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const FooterAddress = ({ className, children }: FooterAddressProps) => {
|
|
11
|
+
return <address className={cx(styles.address, className)}>{children}</address>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import styles from './footerBase.module.css';
|
|
4
|
+
|
|
5
|
+
export interface FooterBaseProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const FooterBase = ({ className, children }: FooterBaseProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<footer className={cx(styles.footer, className)}>
|
|
13
|
+
<div className={styles.grid}>{children} </div>
|
|
14
|
+
</footer>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import { DigdirLogomark } from '../Header/DigdirLogomark.tsx';
|
|
3
|
+
import styles from './footerLogo.module.css';
|
|
4
|
+
|
|
5
|
+
export interface FooterLogoProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const FooterLogo = ({ className, title = 'Digdir' }: FooterLogoProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<div className={cx(styles.logo, className)}>
|
|
13
|
+
<DigdirLogomark className={styles.symbol} />
|
|
14
|
+
<span>{title}</span>
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ElementType } from 'react';
|
|
3
|
+
import { MenuBase } from '../Menu/';
|
|
4
|
+
import styles from './footerMenu.module.css';
|
|
5
|
+
|
|
6
|
+
export interface FooterMenuProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
items: FooterLinkProps[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FooterLinkProps {
|
|
12
|
+
as?: ElementType;
|
|
13
|
+
id?: string;
|
|
14
|
+
href?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const FooterLink = ({ as, className, title, ...rest }: FooterLinkProps) => {
|
|
20
|
+
const Component = as || 'a';
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Component className={cx(styles.link, className)} {...rest}>
|
|
24
|
+
{title}
|
|
25
|
+
</Component>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const FooterMenu = ({ className, items = [] }: FooterMenuProps) => {
|
|
30
|
+
return (
|
|
31
|
+
<MenuBase className={cx(styles.menu, className)}>
|
|
32
|
+
<ul className={styles.list}>
|
|
33
|
+
{items.map((item) => {
|
|
34
|
+
return (
|
|
35
|
+
<li key={item.id}>
|
|
36
|
+
<FooterLink {...item} />
|
|
37
|
+
</li>
|
|
38
|
+
);
|
|
39
|
+
})}
|
|
40
|
+
</ul>
|
|
41
|
+
</MenuBase>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.footer {
|
|
2
|
+
border-top: 1px solid;
|
|
3
|
+
border-color: var(--theme-border-subtle);
|
|
4
|
+
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
row-gap: 1rem;
|
|
8
|
+
|
|
9
|
+
padding: 1rem 0;
|
|
10
|
+
margin: 2rem 1rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.grid {
|
|
14
|
+
width: 100%;
|
|
15
|
+
max-width: 80rem;
|
|
16
|
+
margin: 0 auto;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
justify-content: space-between;
|
|
20
|
+
row-gap: 1rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@media (min-width: 1024px) {
|
|
24
|
+
.grid {
|
|
25
|
+
padding: 0 1rem;
|
|
26
|
+
flex-direction: row;
|
|
27
|
+
}
|
|
28
|
+
}
|