Skip to content

Commit bbae908

Browse files
committed
Implement primitive components + auth interface
1 parent aec8f43 commit bbae908

15 files changed

Lines changed: 241 additions & 3 deletions

File tree

.storybook/preview.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import '../src/design-system/styles/variables.css'
2+
import '../src/primitives/styles/variables.css'
23

34
// For backward compatibility, provide rdflib and solid-logic as globals
45
import * as rdflib from 'rdflib'
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { html } from 'lit'
2+
import { defineAuthStoryRender } from '../../../storybook'
3+
4+
import './Guard'
5+
import { USER_OPTIONS } from '../../../storybook/stubs'
6+
7+
const meta = {
8+
title: 'Primitives/Guard',
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`
18+
<solid-guard>
19+
<span slot="guest">Guest content</span>
20+
<span>Logged in content</span>
21+
</solid-guard>
22+
`)
23+
24+
export const Primary = { render }
25+
export const Guest = { render, args: { user: 'Guest' } }
26+
27+
export default meta
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { html } from 'lit'
2+
import { customElement, state } from 'lit/decorators.js'
3+
4+
import WebComponent from '../../lib/WebComponent'
5+
import { consume } from '@lit/context'
6+
import { authContext, DEFAULT_AUTH_CONTEXT, AuthContext } from '../../lib/auth/context'
7+
8+
@customElement('solid-guard')
9+
export default class Guard extends WebComponent {
10+
@state()
11+
@consume({ context: authContext })
12+
private auth: AuthContext = DEFAULT_AUTH_CONTEXT
13+
14+
protected render () {
15+
if (!this.auth.account) {
16+
return html`
17+
<slot name="guest"></slot>
18+
`
19+
}
20+
21+
return html`
22+
<slot></slot>
23+
`
24+
}
25+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import Guard from './Guard'
2+
3+
export { Guard }
4+
export default Guard

src/primitives/lib/WebComponent.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { html, LitElement } from 'lit'
2+
3+
export default abstract class WebComponent extends LitElement {
4+
static states?: Record<string, Function>
5+
6+
protected internals = this.attachInternals()
7+
8+
protected willUpdate (changedProperties: Map<string, any>) {
9+
super.updated(changedProperties)
10+
11+
for (const [state, condition] of Object.entries(this.static().states ?? {})) {
12+
const matches = condition(this)
13+
14+
if (matches && !this.internals.states.has(state)) {
15+
this.internals.states.add(state)
16+
} else if (!matches && this.internals.states.has(state)) {
17+
this.internals.states.delete(state)
18+
}
19+
}
20+
}
21+
22+
protected render () {
23+
return html`<slot></slot>`
24+
}
25+
26+
private static (): typeof WebComponent {
27+
return this.constructor as typeof WebComponent
28+
}
29+
}

src/primitives/lib/auth/Account.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default class Account {
2+
public readonly webId: string
3+
public readonly avatarUrl?: string
4+
5+
constructor (webId: string, avatarUrl?: string) {
6+
this.webId = webId
7+
this.avatarUrl = avatarUrl
8+
}
9+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { AuthContext } from './context'
2+
import Account from './Account'
3+
4+
export default class NoopAuth implements AuthContext {
5+
public get account (): Account | null {
6+
throw new Error('Can\'t use auth, missing context provider')
7+
}
8+
9+
public login (): void {
10+
throw new Error('Can\'t use auth, missing context provider')
11+
}
12+
13+
public signup (): void {
14+
throw new Error('Can\'t use auth, missing context provider')
15+
}
16+
17+
public logout (): void {
18+
throw new Error('Can\'t use auth, missing context provider')
19+
}
20+
}

src/primitives/lib/auth/context.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import NoopAuth from './NoopAuth'
2+
import { createContext } from '@lit/context'
3+
import Account from './Account'
4+
5+
export interface AuthContext {
6+
account: Account | null;
7+
login(): unknown;
8+
signup(): unknown;
9+
logout(): unknown;
10+
}
11+
12+
export const DEFAULT_AUTH_CONTEXT = new NoopAuth()
13+
export const authContext = createContext<AuthContext>(Symbol('auth'))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@import 'tailwindcss/preflight.css';
2+
3+
button {
4+
display: inline-flex;
5+
align-items: center;
6+
justify-content: center;
7+
padding: 10px 20px;
8+
border-radius: 5px;
9+
gap: 5px;
10+
background: var(--solid-color-primary);
11+
color: var(--solid-color-primary-foreground);
12+
13+
&:hover {
14+
background: var(--solid-color-primary-hover);
15+
border-color: var(--solid-color-primary-hover);
16+
}
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
:root {
2+
--solid-color-gray-100: #f8fafc;
3+
--solid-color-gray-200: #cbd5e1;
4+
--solid-color-primary: #7c4dff;
5+
--solid-color-primary-foreground: #ffffff;
6+
--solid-color-primary-hover: #6a3de8;
7+
}

0 commit comments

Comments
 (0)