feat: [wip] identity menu & creation

This commit is contained in:
Shibo Lyu 2024-09-02 03:43:45 +08:00
parent 0989ed4fa8
commit 3a76e2f9f8
14 changed files with 282 additions and 3 deletions

View file

@ -4,6 +4,7 @@
@layer base {
.weblah-light-theme {
--weblah-color-sb-overlay: theme(colors.white);
--weblah-color-sb-primary: theme(colors.slate.50);
--weblah-color-sb-secondary: theme(colors.slate.100);
--weblah-color-sb-tertiary: theme(colors.slate.200);
@ -17,6 +18,7 @@
}
.weblah-dark-theme {
--weblah-color-sb-overlay: theme(colors.slate.800);
--weblah-color-sb-primary: theme(colors.slate.900);
--weblah-color-sb-secondary: theme(colors.slate.950);
--weblah-color-sb-tertiary: theme(colors.black);

View file

@ -11,7 +11,7 @@
</head>
<body
data-sveltekit-preload-data="hover"
class="relative flex h-[100dvh] max-w-[100vw] touch-pan-x touch-pan-y select-none flex-col overflow-hidden bg-sb-secondary text-sf-primary"
class="relative flex h-[100dvh] max-w-[100vw] touch-pan-x touch-pan-y select-none flex-col overflow-hidden bg-sb-primary text-sf-primary"
>
<div style="display: contents">%sveltekit.body%</div>
</body>

View file

@ -16,6 +16,9 @@ export class BlahKeyPair {
get id() {
return this.publicIdentity.id;
}
get name() {
return this.publicIdentity.name;
}
private constructor(publicIdentity: BlahPublicIdentity, privateKey: CryptoKey) {
this.publicIdentity = publicIdentity;

View file

@ -1,14 +1,26 @@
import canonicalize from 'canonicalize';
import type { BlahSignedPayload } from './signedPayload';
import { bufToHex, hexToBuf } from './utils';
import { adjectives, animals, uniqueNamesGenerator } from 'unique-names-generator';
export function generateName(id: string) {
return uniqueNamesGenerator({
seed: id,
style: 'capital',
separator: ' ',
dictionaries: [adjectives, animals]
});
}
export class BlahPublicIdentity {
private publicKey: CryptoKey;
id: string;
name: string;
private constructor(publicKey: CryptoKey, id: string) {
this.publicKey = publicKey;
this.id = id;
this.name = generateName(id);
}
static async fromPublicKey(publicKey: CryptoKey): Promise<BlahPublicIdentity> {

View file

@ -0,0 +1,9 @@
import { DropdownMenu } from 'bits-ui';
import Content from './DropdownMenu/Content.svelte';
import Trigger from './DropdownMenu/Trigger.svelte';
import Item from './DropdownMenu/Item.svelte';
const { Root, RadioGroup, RadioItem, Separator } = DropdownMenu;
export { Root, Trigger, Content, Item, RadioGroup, RadioItem, Separator };

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { DropdownMenu, type DropdownMenuContentProps } from 'bits-ui';
interface $$Props extends DropdownMenuContentProps {}
</script>
<DropdownMenu.Content
class="bg-sb-overlay min-w-32 rounded-lg border border-ss-secondary p-1 shadow-xl"
sideOffset={4}
{...$$restProps}
>
<slot />
</DropdownMenu.Content>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { DropdownMenu, type DropdownMenuItemProps } from 'bits-ui';
type $$Props = DropdownMenuItemProps;
</script>
<DropdownMenu.Item
class="cursor-default rounded px-1.5 py-0.5 text-sf-primary transition-colors duration-200 hover:bg-accent-50 dark:hover:bg-white/5"
on:click
{...$$restProps}
>
<slot />
</DropdownMenu.Item>

View file

@ -0,0 +1,8 @@
<script lang="ts">
import { DropdownMenu, type DropdownMenuTriggerProps } from 'bits-ui';
type $$Props = DropdownMenuTriggerProps;
</script>
<DropdownMenu.Trigger class="cursor-default" {...$$restProps}>
<slot />
</DropdownMenu.Trigger>

View file

@ -2,3 +2,4 @@ import type { EncodedBlahKeyPair } from './blah/crypto';
import { localStore } from './localstore';
export const keyStore = localStore<EncodedBlahKeyPair[]>('weblah-keypairs', []);
export const currentKeyIndex = localStore<number>('weblah-current-key-index', 0);

View file

@ -1,11 +1,11 @@
<script lang="ts">
import Button from '$lib/components/Button.svelte';
import InputFrame from '$lib/components/InputFrame.svelte';
import { AvatarBeam } from 'svelte-boring-avatars';
import IdentityMenu from './IdentityMenu.svelte';
</script>
<header class="flex items-center justify-stretch gap-2 border-b border-ss-secondary p-2 shadow-sm">
<div><AvatarBeam size={30} name="Shibo Lyu" /></div>
<IdentityMenu />
<InputFrame class="flex-1">
<svg
xmlns="http://www.w3.org/2000/svg"

View file

@ -0,0 +1,47 @@
<script lang="ts">
import * as DropdownMenu from '$lib/components/DropdownMenu';
import { AvatarBeam } from 'svelte-boring-avatars';
import { keyStore, currentKeyIndex } from '$lib/keystore';
import { BlahKeyPair, generateName } from '$lib/blah/crypto';
let currentKeyId: string | undefined;
$: currentKeyId = $keyStore[$currentKeyIndex]?.id;
$: currentKeyName = currentKeyId ? generateName(currentKeyId) : null;
async function createKeyPair() {
const newKeyPair = await BlahKeyPair.generate();
const encoded = await newKeyPair.encode();
$keyStore = [...$keyStore, encoded];
$currentKeyIndex = $keyStore.length - 1;
}
</script>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
{#if currentKeyId}
<AvatarBeam size={30} name={currentKeyId} />
<span class="sr-only">Using identity {currentKeyName}</span>
{:else}
<div
class="box-border size-[30px] rounded-full border-2 border-dashed border-ss-primary"
aria-hidden
/>
<span class="sr-only">Using no identity</span>
{/if}
</DropdownMenu.Trigger>
<DropdownMenu.Content>
{#if $keyStore.length > 0}
<DropdownMenu.RadioGroup bind:value={currentKeyId}>
{#each $keyStore as { id }}
{@const name = generateName(id)}
<DropdownMenu.RadioItem value={id}>
<AvatarBeam size={30} {name} />
<span>{name}</span>
</DropdownMenu.RadioItem>
{/each}
</DropdownMenu.RadioGroup>
<DropdownMenu.Separator />
{/if}
<DropdownMenu.Item on:click={createKeyPair}>Create new identity</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>