Skip to content

Commit 03e8649

Browse files
committed
Implement account design system component
1 parent bc28883 commit 03e8649

16 files changed

Lines changed: 392 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { html } from 'lit'
2+
3+
import './Account'
4+
import { USER_OPTIONS } from '../../../storybook/stubs'
5+
import { defineAuthStoryRender } from '../../../storybook'
6+
7+
const meta = {
8+
title: 'Design System/Account',
9+
args: {
10+
user: 'Alice',
11+
},
12+
argTypes: {
13+
user: USER_OPTIONS.control,
14+
}
15+
} as const
16+
17+
const render = defineAuthStoryRender<typeof meta.argTypes>(() => html`<solid-ui-account></solid-ui-account>`)
18+
19+
export default meta
20+
21+
export const Primary = { render }
22+
export const Guest = {
23+
render,
24+
args: {
25+
user: 'Guest',
26+
}
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@import '../../styles/common.styles.css';
2+
3+
:host {
4+
display: inline-flex;
5+
flex-direction: row;
6+
gap: 10px;
7+
}
8+
9+
:host(:state(loggedIn)) {
10+
--padding: 4px;
11+
--border-width: 1px;
12+
--image-size: 1.875rem; /* 30px */
13+
14+
button {
15+
display: inline-flex;
16+
align-items: center;
17+
justify-content: center;
18+
gap: 5px;
19+
background-color: var(--solid-ui-color-body-grey);
20+
padding: var(--padding);
21+
border-radius: calc((var(--image-size) + 2 * var(--padding) + 2 * var(--border-width)) / 2);
22+
color: var(--solid-ui-color-white);
23+
24+
solid-avatar {
25+
width: var(--image-size);
26+
height: var(--image-size);
27+
border: var(--border-width) solid var(--solid-ui-color-white);
28+
border-radius: 50%;
29+
}
30+
31+
icon-lucide-chevron-down {
32+
width: 16px;
33+
height: 16px;
34+
}
35+
}
36+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { html } from 'lit'
2+
import { customElement, state } from 'lit/decorators.js'
3+
4+
import '../../../design-system/components/button'
5+
import '../../../primitives/components/avatar'
6+
import '../../../primitives/components/login-button'
7+
import '../../../primitives/components/signup-button'
8+
import '../../../primitives/components/logout-button'
9+
import '../menu'
10+
import '../menu-items'
11+
import '../menu-item'
12+
import '~icons/lucide/user'
13+
import '~icons/lucide/log-in'
14+
import '~icons/lucide/chevron-down'
15+
import WebComponent from '../../../primitives/lib/WebComponent'
16+
import { consume } from '@lit/context'
17+
import { authContext, AuthContext, DEFAULT_AUTH_CONTEXT } from '../../../primitives/lib/auth/context'
18+
import styles from './Account.styles.css'
19+
import '~icons/lucide/log-out'
20+
21+
@customElement('solid-ui-account')
22+
export default class Account extends WebComponent {
23+
static styles = styles
24+
static states = {
25+
loggedIn: (component: Account) => !!component.auth.account,
26+
}
27+
28+
@state()
29+
@consume({ context: authContext })
30+
private auth: AuthContext = DEFAULT_AUTH_CONTEXT
31+
32+
render () {
33+
if (!this.auth.account) {
34+
return html`
35+
<solid-login-button>
36+
<solid-ui-button slot="trigger">
37+
<icon-lucide-user slot="left-icon"></icon-lucide-user>
38+
Log In
39+
</solid-ui-button>
40+
</solid-login-button>
41+
<solid-signup-button>
42+
<solid-ui-button slot="trigger" variant="secondary">
43+
<icon-lucide-log-in slot="left-icon"></icon-lucide-log-in>
44+
Sign Up
45+
</solid-ui-button>
46+
</solid-signup-button>
47+
`
48+
}
49+
50+
return html`
51+
<solid-ui-menu>
52+
<button type="button" slot="trigger">
53+
<solid-avatar></solid-avatar>
54+
<icon-lucide-chevron-down slot="right-icon"></icon-lucide-chevron-down>
55+
</button>
56+
57+
<solid-ui-menu-items>
58+
<solid-logout-button>
59+
<solid-ui-menu-item slot="trigger">
60+
<icon-lucide-log-out slot="left-icon"></icon-lucide-log-out>
61+
Sign out
62+
</solid-ui-menu-item>
63+
</solid-logout-button>
64+
</solid-ui-menu-items>
65+
</solid-ui-menu>
66+
`
67+
}
68+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import Account from './Account'
2+
3+
export { Account }
4+
export default Account
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@import '../../styles/common.styles.css';
2+
3+
button {
4+
width: 100%;
5+
display: flex;
6+
justify-content: flex-start;
7+
align-items: center;
8+
gap: 5px;
9+
padding: 10px;
10+
border-radius: 5px;
11+
color: var(--solid-ui-color-gray-600);
12+
font-weight: 500;
13+
font-size: var(--solid-ui-font-size-md);
14+
15+
&:hover {
16+
background-color: var(--solid-ui-color-slate-200);
17+
}
18+
19+
::slotted([slot="left-icon"]), ::slotted([slot="right-icon"]) {
20+
width: var(--solid-ui-font-size-xl);
21+
height: var(--solid-ui-font-size-xl);
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { customElement } from 'lit/decorators.js'
2+
import WebComponent from '../../../primitives/lib/WebComponent'
3+
import { html } from 'lit'
4+
5+
import styles from './MenuItem.styles.css'
6+
7+
@customElement('solid-ui-menu-item')
8+
export default class MenuItem extends WebComponent {
9+
static styles = styles
10+
11+
render () {
12+
return html`
13+
<button type="button">
14+
<slot name="left-icon"></slot>
15+
<slot></slot>
16+
<slot name="right-icon"></slot>
17+
</button>
18+
`
19+
}
20+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import MenuItem from './MenuItem'
2+
3+
export { MenuItem }
4+
export default MenuItem
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@import '../../styles/common.styles.css';
2+
3+
:host {
4+
position: absolute;
5+
top: calc(anchor(bottom) + 5px);
6+
right: anchor(right);
7+
left: auto;
8+
bottom: auto;
9+
overflow: visible;
10+
position-try-fallbacks: flip-block, flip-inline;
11+
12+
/* Also set in JS for global tree-scoped reference */
13+
position-anchor: --menu-anchor;
14+
15+
/* [popover] resets */
16+
border: none;
17+
background: transparent;
18+
padding: 0;
19+
20+
21+
div {
22+
min-width: 300px;
23+
background: var(--solid-ui-color-slate-50);
24+
border: 1px solid var(--solid-ui-color-slate-200);
25+
border-radius: 5px;
26+
box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.35);
27+
padding: 10px 5px;
28+
display: flex;
29+
flex-direction: column;
30+
gap: 5px;
31+
}
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { customElement } from 'lit/decorators.js'
2+
import WebComponent from '../../../primitives/lib/WebComponent'
3+
import { consume } from '@lit/context'
4+
import { menuContext, MenuContext } from '../menu'
5+
6+
import styles from './MenuItems.styles.css'
7+
import { html } from 'lit'
8+
9+
@customElement('solid-ui-menu-items')
10+
export default class MenuItems extends WebComponent {
11+
static styles = styles
12+
13+
@consume({ context: menuContext })
14+
private context?: MenuContext
15+
16+
connectedCallback () {
17+
super.connectedCallback()
18+
19+
this.setAttribute('popover', 'auto')
20+
this.setAttribute('role', 'menu')
21+
22+
this.style.positionAnchor = '--menu-anchor'
23+
24+
if (this.context) {
25+
this.id = `${this.context.id}-menu-items`
26+
}
27+
}
28+
29+
render () {
30+
return html`
31+
<div>
32+
<slot></slot>
33+
</div>
34+
`
35+
}
36+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import MenuItems from './MenuItems'
2+
3+
export { MenuItems }
4+
export default MenuItems

0 commit comments

Comments
 (0)