@altinn/altinn-components 0.3.0 → 0.4.1
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/.storybook/main.ts +1 -1
- package/CHANGELOG.md +14 -0
- package/lib/components/Dialog/DialogListItem.tsx +0 -1
- package/lib/components/Dialog/DialogNav.tsx +1 -1
- package/lib/components/Dialog/dialogNav.module.css +12 -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/Header.tsx +0 -5
- package/lib/components/History/HistoryAttachments.tsx +22 -0
- package/lib/components/History/HistoryItem.stories.ts +27 -18
- package/lib/components/History/HistoryItem.tsx +7 -15
- package/lib/components/History/HistoryList.stories.ts +34 -22
- package/lib/components/Layout/Layout.stories.tsx +30 -2
- package/lib/components/Layout/Layout.tsx +4 -2
- package/lib/components/Layout/LayoutBase.tsx +1 -1
- package/lib/components/Layout/index.tsx +1 -0
- package/lib/components/Layout/layoutBase.module.css +2 -14
- package/lib/components/Layout/layoutContent.module.css +6 -1
- package/lib/components/Layout/layoutSidebar.module.css +1 -0
- package/lib/components/LayoutAction/ActionFooter.stories.tsx +1 -1
- package/lib/components/LayoutAction/ActionHeader.tsx +1 -1
- package/lib/components/LayoutAction/ActionMenu.stories.tsx +1 -0
- package/lib/components/LayoutAction/ActionMenu.tsx +5 -2
- package/lib/components/LayoutAction/actionMenu.module.css +8 -6
- package/lib/components/Menu/{MenuItem.stories.ts → MenuItem.stories.tsx} +32 -0
- package/lib/components/Menu/MenuItemBase.tsx +1 -1
- package/lib/components/Menu/{menuItem.module.css → __menuItem.module.css} +0 -6
- package/lib/components/Menu/menuItemBase.module.css +12 -18
- package/lib/components/Menu/menuItemMedia.module.css +2 -0
- package/lib/components/index.ts +1 -0
- package/lib/css/global.css +1 -0
- package/lib/css/theme-global-dark.css +19 -0
- package/package.json +1 -1
package/.storybook/main.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StorybookConfig } from "@storybook/react-vite";
|
|
2
2
|
|
|
3
3
|
const config: StorybookConfig = {
|
|
4
|
-
stories: ["../lib/components/**/*.stories.@(ts|tsx)"],
|
|
4
|
+
stories: ["../lib/components/**/*.stories.@(ts|tsx)", "../lib/stories/**/*.stories.@(ts|tsx)"],
|
|
5
5
|
addons: [
|
|
6
6
|
"@storybook/addon-onboarding",
|
|
7
7
|
"@storybook/addon-links",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.1](https://github.com/Altinn/altinn-components/compare/v0.4.0...v0.4.1) (2024-11-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* css changes to dialog ([#43](https://github.com/Altinn/altinn-components/issues/43)) ([79e3287](https://github.com/Altinn/altinn-components/commit/79e3287dc2efbce8ba7a9c0b94f955514289c0d3))
|
|
9
|
+
|
|
10
|
+
## [0.4.0](https://github.com/Altinn/altinn-components/compare/v0.3.0...v0.4.0) (2024-11-08)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add footer component ([#40](https://github.com/Altinn/altinn-components/issues/40)) ([bdf5c0c](https://github.com/Altinn/altinn-components/commit/bdf5c0cd68c374ac5fe83536033074289f379abe))
|
|
16
|
+
|
|
3
17
|
## [0.3.0](https://github.com/Altinn/altinn-components/compare/v0.2.2...v0.3.0) (2024-11-08)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -6,7 +6,7 @@ import { ContextMenu, type ContextMenuProps } from '../ContextMenu/ContextMenu.t
|
|
|
6
6
|
import { MetaTimestamp } from '../Meta';
|
|
7
7
|
import { DialogStatus, type DialogStatusProps } from './DialogStatus';
|
|
8
8
|
import { DialogTouchedBy, type DialogTouchedByActor } from './DialogTouchedBy';
|
|
9
|
-
import styles from './
|
|
9
|
+
import styles from './dialogNav.module.css';
|
|
10
10
|
|
|
11
11
|
export interface DialogBackButtonProps {
|
|
12
12
|
as?: ElementType;
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.menu {
|
|
2
|
+
position: relative;
|
|
3
|
+
font-size: .875rem;
|
|
4
|
+
line-height: 1.5;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.list {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
row-gap: 1rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@media (min-width: 1024px) {
|
|
14
|
+
.list {
|
|
15
|
+
flex-direction: row;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: start;
|
|
18
|
+
column-gap: .5rem;
|
|
19
|
+
width: auto;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.list .item:hover {
|
|
24
|
+
background-color: var(--global-base-hover);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.link {
|
|
28
|
+
color: inherit;
|
|
29
|
+
text-decoration: underline;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Footer';
|
|
@@ -12,11 +12,6 @@ import styles from './header.module.css';
|
|
|
12
12
|
|
|
13
13
|
export type HeaderExpandedType = 'search' | 'menu' | null;
|
|
14
14
|
|
|
15
|
-
export interface HeaderAccountProps {
|
|
16
|
-
type?: string;
|
|
17
|
-
name?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
15
|
export interface HeaderProps {
|
|
21
16
|
menu: GlobalMenuProps;
|
|
22
17
|
search?: HeaderSearchProps;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type AttachmentLinkProps, AttachmentList } from '../Attachment';
|
|
2
|
+
import { MetaItem } from '../Meta';
|
|
3
|
+
|
|
4
|
+
export interface HistoryAttachmentsProps {
|
|
5
|
+
title?: string;
|
|
6
|
+
items?: AttachmentLinkProps[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const HistoryAttachments = ({ title = 'Attachments', items }: HistoryAttachmentsProps) => {
|
|
10
|
+
if (!items?.length) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<section>
|
|
16
|
+
<MetaItem as="h2" size="xs">
|
|
17
|
+
{title}
|
|
18
|
+
</MetaItem>
|
|
19
|
+
<AttachmentList size="lg" items={items} />
|
|
20
|
+
</section>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -9,7 +9,8 @@ const meta = {
|
|
|
9
9
|
tags: ['autodocs'],
|
|
10
10
|
parameters: {},
|
|
11
11
|
args: {
|
|
12
|
-
createdAt: '
|
|
12
|
+
createdAt: '2024-09-22 13:34',
|
|
13
|
+
createdAtLabel: '22. september 2024 kl 13.34',
|
|
13
14
|
createdBy: {
|
|
14
15
|
name: 'Eirik Horneland',
|
|
15
16
|
},
|
|
@@ -26,22 +27,30 @@ export const Default: Story = {
|
|
|
26
27
|
|
|
27
28
|
export const Attachments: Story = {
|
|
28
29
|
args: {
|
|
29
|
-
attachments:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
attachments: {
|
|
31
|
+
title: '6 vedlegg',
|
|
32
|
+
items: [
|
|
33
|
+
{
|
|
34
|
+
href: '#',
|
|
35
|
+
label: '1-0 Castro.pdf',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
href: '#',
|
|
39
|
+
label: '2-0 Kornvig.pdf',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
href: '#',
|
|
43
|
+
label: '3-0 Kartum.pdf',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
href: '#',
|
|
47
|
+
label: '3-1 Zinkernagel.pdf',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
href: '#',
|
|
51
|
+
label: '4-1 Castro.pdf',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
46
55
|
},
|
|
47
56
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type AttachmentLinkProps, AttachmentList } from '../Attachment';
|
|
2
1
|
import { Avatar } from '../Avatar/';
|
|
3
|
-
import { MetaBase,
|
|
2
|
+
import { MetaBase, MetaTimestamp } from '../Meta/';
|
|
4
3
|
import { Typography } from '../Typography';
|
|
4
|
+
import { HistoryAttachments, type HistoryAttachmentsProps } from './HistoryAttachments';
|
|
5
5
|
import { HistoryBorder } from './HistoryBorder';
|
|
6
6
|
import styles from './historyItem.module.css';
|
|
7
7
|
|
|
@@ -14,8 +14,9 @@ export interface CreatedByProps {
|
|
|
14
14
|
export interface HistoryItemProps {
|
|
15
15
|
createdBy?: CreatedByProps;
|
|
16
16
|
createdAt?: string;
|
|
17
|
+
createdAtLabel?: string;
|
|
17
18
|
summary?: string;
|
|
18
|
-
attachments?:
|
|
19
|
+
attachments?: HistoryAttachmentsProps;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const HistoryItem = ({
|
|
@@ -23,11 +24,10 @@ export const HistoryItem = ({
|
|
|
23
24
|
type: 'person',
|
|
24
25
|
},
|
|
25
26
|
createdAt,
|
|
27
|
+
createdAtLabel,
|
|
26
28
|
summary,
|
|
27
29
|
attachments,
|
|
28
30
|
}: HistoryItemProps) => {
|
|
29
|
-
const title = attachments?.length + ' vedlegg';
|
|
30
|
-
|
|
31
31
|
return (
|
|
32
32
|
<section className={styles.item}>
|
|
33
33
|
<header className={styles.header}>
|
|
@@ -42,20 +42,12 @@ export const HistoryItem = ({
|
|
|
42
42
|
<article className={styles.body}>
|
|
43
43
|
<MetaBase>
|
|
44
44
|
<MetaTimestamp datetime={createdAt} size="xs">
|
|
45
|
-
{createdBy?.name
|
|
46
|
-
{createdAt}
|
|
45
|
+
{[createdBy?.name, createdAtLabel].join(', ')}
|
|
47
46
|
</MetaTimestamp>
|
|
48
47
|
</MetaBase>
|
|
49
48
|
<Typography size="lg">
|
|
50
49
|
<p>{summary}</p>
|
|
51
|
-
{attachments
|
|
52
|
-
<section>
|
|
53
|
-
<MetaItem size="xs">{title}</MetaItem>
|
|
54
|
-
<AttachmentList items={attachments} />
|
|
55
|
-
</section>
|
|
56
|
-
) : (
|
|
57
|
-
''
|
|
58
|
-
)}
|
|
50
|
+
{attachments && <HistoryAttachments {...attachments} />}
|
|
59
51
|
</Typography>
|
|
60
52
|
</article>
|
|
61
53
|
</HistoryBorder>
|
|
@@ -16,23 +16,31 @@ const meta = {
|
|
|
16
16
|
name: 'Eirik Horneland',
|
|
17
17
|
},
|
|
18
18
|
summary: 'Brann slo Glimt 4-1 på Stadion.',
|
|
19
|
-
attachments:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
attachments: {
|
|
20
|
+
title: '6 vedlegg',
|
|
21
|
+
items: [
|
|
22
|
+
{
|
|
23
|
+
href: '#',
|
|
24
|
+
label: '1-0 Castro.pdf',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
href: '#',
|
|
28
|
+
label: '2-0 Kornvig.pdf',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
href: '#',
|
|
32
|
+
label: '3-0 Kartum.pdf',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
href: '#',
|
|
36
|
+
label: '3-1 Zinkernagel.pdf',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
href: '#',
|
|
40
|
+
label: '4-1 Castro.pdf',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
36
44
|
},
|
|
37
45
|
{
|
|
38
46
|
createdAt: '2004-09-09 13:34',
|
|
@@ -40,11 +48,15 @@ const meta = {
|
|
|
40
48
|
name: 'Eirik Horneland',
|
|
41
49
|
},
|
|
42
50
|
summary: 'Brann vant 1-0 i Haugesund.',
|
|
43
|
-
attachments:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
attachments: {
|
|
52
|
+
title: '1 vedlegg',
|
|
53
|
+
items: [
|
|
54
|
+
{
|
|
55
|
+
href: '#',
|
|
56
|
+
label: 'Målet til Heggebø.pdf',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
48
60
|
},
|
|
49
61
|
],
|
|
50
62
|
},
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { ActionFooter, ActionHeader, ActionMenu, DialogListItem, ListBase, Snackbar } from '../';
|
|
4
|
-
import type { HeaderProps } from '../
|
|
5
|
-
import type { MenuProps } from '../Menu';
|
|
4
|
+
import type { FooterProps, HeaderProps, MenuProps } from '../';
|
|
6
5
|
import { Layout } from './Layout';
|
|
7
6
|
|
|
8
7
|
const header: HeaderProps = {
|
|
@@ -21,6 +20,34 @@ const header: HeaderProps = {
|
|
|
21
20
|
},
|
|
22
21
|
};
|
|
23
22
|
|
|
23
|
+
const footer: FooterProps = {
|
|
24
|
+
address: 'Postboks 1382 Vika, 0114 Oslo.',
|
|
25
|
+
menu: {
|
|
26
|
+
items: [
|
|
27
|
+
{
|
|
28
|
+
id: '1',
|
|
29
|
+
href: '#',
|
|
30
|
+
title: 'Om Altinn',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: '2',
|
|
34
|
+
href: '#',
|
|
35
|
+
title: 'Driftsmeldinger',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: '3',
|
|
39
|
+
href: '#',
|
|
40
|
+
title: 'Personvern',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: '4',
|
|
44
|
+
href: '#',
|
|
45
|
+
title: 'Tilgjengelighet',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
24
51
|
const menu: MenuProps = {
|
|
25
52
|
groups: {},
|
|
26
53
|
items: [
|
|
@@ -76,6 +103,7 @@ const meta = {
|
|
|
76
103
|
},
|
|
77
104
|
args: {
|
|
78
105
|
header,
|
|
106
|
+
footer,
|
|
79
107
|
sidebar: {
|
|
80
108
|
menu,
|
|
81
109
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { LayoutBase, LayoutBody, LayoutContent, LayoutSidebar, type LayoutTheme } from '.';
|
|
3
|
+
import { Footer, type FooterProps } from '../Footer';
|
|
3
4
|
import { Header, type HeaderProps } from '../Header';
|
|
4
5
|
import { Menu, type MenuProps } from '../Menu';
|
|
5
6
|
|
|
@@ -17,12 +18,13 @@ interface ContentProps {
|
|
|
17
18
|
export interface LayoutProps {
|
|
18
19
|
theme?: LayoutTheme;
|
|
19
20
|
header?: HeaderProps;
|
|
21
|
+
footer?: FooterProps;
|
|
20
22
|
sidebar: SidebarProps;
|
|
21
23
|
content: ContentProps;
|
|
22
24
|
children: ReactNode;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
export const Layout = ({ theme = 'global', header, sidebar = {}, content = {}, children }: LayoutProps) => {
|
|
27
|
+
export const Layout = ({ theme = 'global', header, footer, sidebar = {}, content = {}, children }: LayoutProps) => {
|
|
26
28
|
const { menu, ...sideRestProps } = sidebar;
|
|
27
29
|
return (
|
|
28
30
|
<LayoutBase theme={theme}>
|
|
@@ -32,11 +34,11 @@ export const Layout = ({ theme = 'global', header, sidebar = {}, content = {}, c
|
|
|
32
34
|
<LayoutSidebar hidden={sidebar?.hidden} theme={sidebar?.theme} {...sideRestProps}>
|
|
33
35
|
{menu && <Menu {...menu} />}
|
|
34
36
|
{sidebar?.children}
|
|
35
|
-
{sidebar?.hidden && 'HIDDEN'}
|
|
36
37
|
</LayoutSidebar>
|
|
37
38
|
)}
|
|
38
39
|
<LayoutContent theme={content?.theme}>{children}</LayoutContent>
|
|
39
40
|
</LayoutBody>
|
|
41
|
+
{footer && <Footer {...footer} />}
|
|
40
42
|
</LayoutBase>
|
|
41
43
|
);
|
|
42
44
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import styles from './layoutBase.module.css';
|
|
3
3
|
|
|
4
|
-
export type LayoutTheme = 'global' | 'neutral' | 'company' | 'person';
|
|
4
|
+
export type LayoutTheme = 'global' | 'global-dark' | 'neutral' | 'company' | 'person';
|
|
5
5
|
|
|
6
6
|
export interface LayoutBaseProps {
|
|
7
7
|
theme?: LayoutTheme;
|
|
@@ -6,18 +6,6 @@
|
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
.base[data-theme
|
|
10
|
-
background-color: var(--
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.base[data-theme="neutral"] {
|
|
14
|
-
background-color: var(--neutral-background-subtle);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.base[data-theme="person"] {
|
|
18
|
-
background-color: var(--person-background-subtle);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.base[data-theme="company"] {
|
|
22
|
-
background-color: var(--company-background-subtle);
|
|
9
|
+
.base[data-theme] {
|
|
10
|
+
background-color: var(--theme-background-subtle);
|
|
23
11
|
}
|
|
@@ -11,7 +11,7 @@ export interface ActionHeaderProps {
|
|
|
11
11
|
|
|
12
12
|
export const ActionHeader = ({ hidden = false, title, dismissable = true, onDismiss }: ActionHeaderProps) => {
|
|
13
13
|
return (
|
|
14
|
-
<header className={styles.header} aria-hidden={hidden}>
|
|
14
|
+
<header className={styles.header} aria-hidden={hidden} data-theme="global-dark">
|
|
15
15
|
<h2 className={styles.title}>{title}</h2>
|
|
16
16
|
{dismissable && <IconButton icon="x-mark" onClick={onDismiss} className={styles.dismiss} />}
|
|
17
17
|
</header>
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { MenuBase, MenuItem, type MenuItemProps } from '../Menu';
|
|
2
2
|
import styles from './actionMenu.module.css';
|
|
3
3
|
|
|
4
|
+
type ActionMenuTheme = 'inherit' | 'global-dark';
|
|
5
|
+
|
|
4
6
|
export interface ActionMenuProps {
|
|
7
|
+
theme?: ActionMenuTheme;
|
|
5
8
|
items?: MenuItemProps[];
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
export const ActionMenu = ({ items = [] }: ActionMenuProps) => {
|
|
11
|
+
export const ActionMenu = ({ theme = 'inherit', items = [] }: ActionMenuProps) => {
|
|
9
12
|
return (
|
|
10
|
-
<MenuBase className={styles.menu}>
|
|
13
|
+
<MenuBase theme={theme} className={styles.menu}>
|
|
11
14
|
<ul className={styles.list}>
|
|
12
15
|
{items.map((item) => {
|
|
13
16
|
return (
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
.menu {
|
|
2
|
-
background-color: var(--global-base-default);
|
|
3
|
-
color: white;
|
|
4
2
|
padding: 0 .5rem;
|
|
5
3
|
border-radius: 0.375rem;
|
|
6
4
|
}
|
|
7
5
|
|
|
6
|
+
.menu[data-theme] {
|
|
7
|
+
background-color: var(--theme-background-subtle);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.menu[data-theme="inherit"] {
|
|
11
|
+
background-color: inherit;
|
|
12
|
+
}
|
|
13
|
+
|
|
8
14
|
.list {
|
|
9
15
|
display: flex;
|
|
10
16
|
flex-direction: column;
|
|
@@ -19,7 +25,3 @@
|
|
|
19
25
|
width: auto;
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
|
-
|
|
23
|
-
.list .item:hover {
|
|
24
|
-
background-color: var(--global-base-hover);
|
|
25
|
-
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { LayoutBase, LayoutSidebar, type LayoutTheme } from '../Layout';
|
|
3
|
+
import { MetaItem } from '../Meta';
|
|
4
|
+
import { MenuBase } from './MenuBase';
|
|
2
5
|
import { MenuItem } from './MenuItem';
|
|
6
|
+
import type { MenuItemColor } from './MenuItemBase';
|
|
3
7
|
|
|
4
8
|
const meta = {
|
|
5
9
|
title: 'Menu/MenuItem',
|
|
@@ -130,3 +134,31 @@ export const CompanyAccount: Story = {
|
|
|
130
134
|
description: 'Org nr.: XX.XX.XXXX',
|
|
131
135
|
},
|
|
132
136
|
};
|
|
137
|
+
|
|
138
|
+
export const ThemesAndColors = () => {
|
|
139
|
+
const themes: LayoutTheme[] = ['global', 'neutral', 'company', 'person', 'global-dark'];
|
|
140
|
+
const colors: MenuItemColor[] = ['neutral', 'subtle', 'strong', 'company', 'person'];
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div style={{ display: 'flex', width: '100%' }}>
|
|
144
|
+
{themes.map((theme) => {
|
|
145
|
+
return (
|
|
146
|
+
<div key={theme} style={{ flexGrow: 1 }}>
|
|
147
|
+
<LayoutBase theme={theme}>
|
|
148
|
+
<MenuBase>
|
|
149
|
+
{colors.map((color) => {
|
|
150
|
+
return (
|
|
151
|
+
<div key={color}>
|
|
152
|
+
<MenuItem icon="inbox" title="Title" color={color} id="inbox" />
|
|
153
|
+
<MetaItem>{theme + '/' + color}</MetaItem>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
})}
|
|
157
|
+
</MenuBase>
|
|
158
|
+
</LayoutBase>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
})}
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
};
|
|
@@ -4,7 +4,7 @@ import { Badge, type BadgeProps } from '../Badge';
|
|
|
4
4
|
import { Icon, type IconName } from '../Icon';
|
|
5
5
|
import styles from './menuItemBase.module.css';
|
|
6
6
|
|
|
7
|
-
export type MenuItemColor = '
|
|
7
|
+
export type MenuItemColor = 'neutral' | 'subtle' | 'strong' | 'company' | 'person';
|
|
8
8
|
export type MenuItemSize = 'sm' | 'md' | 'lg';
|
|
9
9
|
|
|
10
10
|
export interface MenuItemBaseProps {
|
|
@@ -87,8 +87,6 @@
|
|
|
87
87
|
color: var(--theme-text-subtle);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
/* colors */
|
|
91
|
-
|
|
92
90
|
.item:hover {
|
|
93
91
|
background-color: var(--theme-surface-default);
|
|
94
92
|
}
|
|
@@ -107,8 +105,6 @@
|
|
|
107
105
|
color: var(--theme-background-default);
|
|
108
106
|
}
|
|
109
107
|
|
|
110
|
-
/* company */
|
|
111
|
-
|
|
112
108
|
.item[data-color="company"]:hover {
|
|
113
109
|
background-color: var(--company-background-subtle);
|
|
114
110
|
}
|
|
@@ -121,8 +117,6 @@
|
|
|
121
117
|
background-color: var(--company-surface-default);
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
/* person */
|
|
125
|
-
|
|
126
120
|
.item[data-color="person"]:hover {
|
|
127
121
|
background-color: var(--person-background-subtle);
|
|
128
122
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
.item {
|
|
2
|
-
background-color: transparent;
|
|
3
2
|
display: flex;
|
|
4
3
|
align-items: center;
|
|
5
4
|
column-gap: 4px;
|
|
@@ -43,30 +42,25 @@
|
|
|
43
42
|
|
|
44
43
|
/* colors */
|
|
45
44
|
|
|
45
|
+
.item {
|
|
46
|
+
background-color: transparent;
|
|
47
|
+
color: var(--theme-text-default);
|
|
48
|
+
}
|
|
49
|
+
|
|
46
50
|
.item:hover {
|
|
47
|
-
background-color: var(--theme-
|
|
51
|
+
background-color: var(--theme-surface-hover);
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
.item[aria-selected="true"] {
|
|
51
55
|
background-color: var(--theme-background-default);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
background-color: var(--company-background-subtle);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.item[data-color="company"][aria-selected="true"] {
|
|
61
|
-
background-color: var(--company-surface-default);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* person */
|
|
65
|
-
|
|
66
|
-
.item[data-color="person"]:hover {
|
|
67
|
-
background-color: var(--person-background-subtle);
|
|
58
|
+
.media[data-color="subtle"] {
|
|
59
|
+
background-color: var(--theme-background-default);
|
|
60
|
+
color: var(--theme-text-default);
|
|
68
61
|
}
|
|
69
62
|
|
|
70
|
-
.
|
|
71
|
-
background-color: var(--
|
|
63
|
+
.media[data-color="strong"] {
|
|
64
|
+
background-color: var(--theme-base-default);
|
|
65
|
+
color: var(--theme-background-default);
|
|
72
66
|
}
|
|
@@ -29,8 +29,10 @@
|
|
|
29
29
|
|
|
30
30
|
.media[data-color="company"] {
|
|
31
31
|
background-color: var(--company-surface-default);
|
|
32
|
+
color: var(--company-text-default);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
.media[data-color="person"] {
|
|
35
36
|
background-color: var(--person-surface-default);
|
|
37
|
+
color: var(--person-text-default);
|
|
36
38
|
}
|
package/lib/components/index.ts
CHANGED
package/lib/css/global.css
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[data-theme="global-dark"] {
|
|
2
|
+
--theme-background-default: var(--company-base-hover);
|
|
3
|
+
--theme-background-subtle: var(--company-base-default);
|
|
4
|
+
|
|
5
|
+
--theme-base-default: var(--company-background-subtle);
|
|
6
|
+
--theme-base-hover: var(--company-base-hover);
|
|
7
|
+
--theme-base-active: var(--company-base-active);
|
|
8
|
+
|
|
9
|
+
--theme-border-default: var(--neutral-border-default);
|
|
10
|
+
--theme-border-strong: var(--neutral-border-strong);
|
|
11
|
+
--theme-border-subtle: var(--neutral-border-subtle);
|
|
12
|
+
|
|
13
|
+
--theme-surface-default: var(--company-base-default);
|
|
14
|
+
--theme-surface-hover: var(--company-base-hover);
|
|
15
|
+
--theme-surface-active: var(--company-base-active);
|
|
16
|
+
|
|
17
|
+
--theme-text-default: var(--company-background-default);
|
|
18
|
+
--theme-text-subtle: var(--company-background-subtle);
|
|
19
|
+
}
|