mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-05-01 08:41:08 +00:00
feat: account switching
This commit is contained in:
parent
2b47eeb146
commit
e78279114a
6 changed files with 98 additions and 31 deletions
|
@ -75,13 +75,15 @@ class AccountStore implements Readable<Account[]> {
|
||||||
await this.identityFileDB.updateIdentityFile(identityFile);
|
await this.identityFileDB.updateIdentityFile(identityFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createAccount(profile: BlahProfile, password: string) {
|
async createAccount(profile: BlahProfile, password: string): Promise<string> {
|
||||||
const idKeyPair = await BlahKeyPair.generate(true);
|
const idKeyPair = await BlahKeyPair.generate(true);
|
||||||
const actKeyPair = await BlahKeyPair.generate(false);
|
const actKeyPair = await BlahKeyPair.generate(false);
|
||||||
const identity = await BlahIdentity.create(idKeyPair, actKeyPair, profile);
|
const identity = await BlahIdentity.create(idKeyPair, actKeyPair, profile);
|
||||||
const encodedIdKeyPair = await idKeyPair.encode(password);
|
const encodedIdKeyPair = await idKeyPair.encode(password);
|
||||||
await this.keyDB.addAccount(idKeyPair.id, actKeyPair, encodedIdKeyPair);
|
await this.keyDB.addAccount(idKeyPair.id, actKeyPair, encodedIdKeyPair);
|
||||||
await this.saveIdentityFile(identity);
|
await this.saveIdentityFile(identity);
|
||||||
|
await this.loadAccounts();
|
||||||
|
return idKeyPair.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:element
|
<svelte:element
|
||||||
this={href ? 'a' : 'div'}
|
this={href ? 'a' : 'button'}
|
||||||
{href}
|
{href}
|
||||||
class={tw(
|
class={tw(
|
||||||
'flex cursor-default items-center gap-2 px-4 py-3 font-medium text-sf-primary first:rounded-t-lg last:rounded-b-lg',
|
'flex w-full cursor-default items-center gap-2 px-4 py-3 font-medium text-sf-primary first:rounded-t-lg last:rounded-b-lg',
|
||||||
selected && 'bg-accent-500 text-white shadow-inner dark:bg-accent-900 dark:text-sf-primary'
|
selected && 'bg-accent-500 text-white shadow-inner dark:bg-accent-900 dark:text-sf-primary'
|
||||||
)}
|
)}
|
||||||
|
tabindex="0"
|
||||||
|
role="button"
|
||||||
|
on:click
|
||||||
>
|
>
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<Icon
|
<Icon
|
||||||
|
|
|
@ -2,31 +2,25 @@
|
||||||
import {
|
import {
|
||||||
currentAccountStore,
|
currentAccountStore,
|
||||||
openAccountStore,
|
openAccountStore,
|
||||||
type Account,
|
|
||||||
type AccountStore
|
type AccountStore
|
||||||
} from '$lib/accounts/accountStore';
|
} from '$lib/accounts/accountStore';
|
||||||
import ProfilePicture from '$lib/components/ProfilePicture.svelte';
|
import ProfilePicture from '$lib/components/ProfilePicture.svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
export let size: number = 32;
|
export let size: number = 32;
|
||||||
|
|
||||||
let accountStore: AccountStore;
|
let accountStore: AccountStore;
|
||||||
|
|
||||||
async function getAccount(idKeyId: string | null): Promise<Account | undefined> {
|
onMount(() => {
|
||||||
if (!accountStore) {
|
openAccountStore().then((store) => {
|
||||||
accountStore = await openAccountStore();
|
accountStore = store;
|
||||||
}
|
});
|
||||||
if (!idKeyId) return;
|
});
|
||||||
let currentAccount = $accountStore.find((account) => account.id_key === idKeyId);
|
|
||||||
if (!currentAccount && $accountStore.length > 0) {
|
|
||||||
currentAccount = $accountStore[0];
|
|
||||||
$currentAccountStore = currentAccount.id_key;
|
|
||||||
}
|
|
||||||
return currentAccount;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await getAccount($currentAccountStore)}
|
{#if accountStore}
|
||||||
<ProfilePicture account={undefined} />
|
{@const currentAccount = $accountStore.find((account) => account.id_key === $currentAccountStore)}
|
||||||
{:then currentAccount}
|
|
||||||
<ProfilePicture account={currentAccount} {size} />
|
<ProfilePicture account={currentAccount} {size} />
|
||||||
{/await}
|
{:else}
|
||||||
|
<ProfilePicture account={undefined} {size} />
|
||||||
|
{/if}
|
||||||
|
|
71
src/routes/(app)/settings/SettingsAccountSections.svelte
Normal file
71
src/routes/(app)/settings/SettingsAccountSections.svelte
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { GroupedListItem, GroupedListSection } from '$lib/components/GroupedList';
|
||||||
|
import { ArrowRightEndOnRectangle, UserPlus } from 'svelte-hero-icons';
|
||||||
|
import SettingsListItem from './SettingsListItem.svelte';
|
||||||
|
import {
|
||||||
|
openAccountStore,
|
||||||
|
currentAccountStore,
|
||||||
|
type AccountStore,
|
||||||
|
type Account
|
||||||
|
} from '$lib/accounts/accountStore';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import ProfilePicture from '$lib/components/ProfilePicture.svelte';
|
||||||
|
import { flip } from 'svelte/animate';
|
||||||
|
import { blur, scale } from 'svelte/transition';
|
||||||
|
|
||||||
|
let accountStore: AccountStore;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
openAccountStore().then((store) => {
|
||||||
|
accountStore = store;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function switchToAccount(account: Account) {
|
||||||
|
$currentAccountStore = account.id_key;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if accountStore}
|
||||||
|
{@const currentAccount = $accountStore.find((acc) => acc.id_key === $currentAccountStore)}
|
||||||
|
{@const remainingAccounts = $accountStore
|
||||||
|
.filter((acc) => acc.id_key !== $currentAccountStore)
|
||||||
|
.toSorted((a, b) => a.profile.signee.payload.name.localeCompare(b.profile.signee.payload.name))}
|
||||||
|
{#if currentAccount}
|
||||||
|
{#key currentAccount.id_key}
|
||||||
|
<div class="mt-6 p-4 text-center" in:blur>
|
||||||
|
<div class="inline-block">
|
||||||
|
<ProfilePicture account={currentAccount} size={68} />
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<span class="text-xl font-semibold text-sf-primary">
|
||||||
|
{currentAccount.profile.signee.payload.name}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<code class="text-sm text-sf-secondary">
|
||||||
|
{currentAccount.profile.signee.id_key.slice(0, 6) +
|
||||||
|
'...' +
|
||||||
|
currentAccount.profile.signee.id_key.slice(-6)}
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{/key}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<GroupedListSection>
|
||||||
|
{#each remainingAccounts as account (account.id_key)}
|
||||||
|
<div animate:flip={{ duration: 250 }} transition:blur>
|
||||||
|
<GroupedListItem on:click={() => switchToAccount(account)}>
|
||||||
|
<div class="-mx-0.5"><ProfilePicture {account} size={24} /></div>
|
||||||
|
{account.profile.signee.payload.name}
|
||||||
|
</GroupedListItem>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</GroupedListSection>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<GroupedListSection>
|
||||||
|
<SettingsListItem icon={ArrowRightEndOnRectangle} route="/account/add">Sign in</SettingsListItem>
|
||||||
|
<SettingsListItem icon={UserPlus} route="/account/new">Create Account</SettingsListItem>
|
||||||
|
</GroupedListSection>
|
|
@ -3,18 +3,17 @@
|
||||||
import { GroupedListSection, GroupedListItem } from '$lib/components/GroupedList';
|
import { GroupedListSection, GroupedListItem } from '$lib/components/GroupedList';
|
||||||
import { tw } from '$lib/tw';
|
import { tw } from '$lib/tw';
|
||||||
import {
|
import {
|
||||||
ArrowRightEndOnRectangle,
|
|
||||||
Bell,
|
Bell,
|
||||||
Cog,
|
Cog,
|
||||||
DevicePhoneMobile,
|
DevicePhoneMobile,
|
||||||
InformationCircle,
|
InformationCircle,
|
||||||
LockClosed,
|
LockClosed,
|
||||||
QuestionMarkCircle,
|
QuestionMarkCircle
|
||||||
UserPlus
|
|
||||||
} from 'svelte-hero-icons';
|
} from 'svelte-hero-icons';
|
||||||
import { scale } from 'svelte/transition';
|
import { scale } from 'svelte/transition';
|
||||||
import SettingsListItem from './SettingsListItem.svelte';
|
import SettingsListItem from './SettingsListItem.svelte';
|
||||||
import PageHeader from '$lib/components/PageHeader.svelte';
|
import PageHeader from '$lib/components/PageHeader.svelte';
|
||||||
|
import SettingsAccountSections from './SettingsAccountSections.svelte';
|
||||||
|
|
||||||
let className = '';
|
let className = '';
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
@ -30,18 +29,15 @@
|
||||||
<Button href="/account/profile">Edit</Button>
|
<Button href="/account/profile">Edit</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div class="flex-1 overflow-y-scroll">
|
<div class="flex-1 overflow-y-scroll">
|
||||||
<GroupedListSection>
|
<SettingsAccountSections />
|
||||||
<SettingsListItem icon={ArrowRightEndOnRectangle} route="/account/add">
|
|
||||||
Sign in
|
|
||||||
</SettingsListItem>
|
|
||||||
<SettingsListItem icon={UserPlus} route="/account/new">Create Account</SettingsListItem>
|
|
||||||
</GroupedListSection>
|
|
||||||
<GroupedListSection>
|
<GroupedListSection>
|
||||||
<SettingsListItem icon={Cog} route="">General</SettingsListItem>
|
<SettingsListItem icon={Cog} route="">General</SettingsListItem>
|
||||||
<GroupedListItem icon={Bell}>Notifications</GroupedListItem>
|
<GroupedListItem icon={Bell}>Notifications</GroupedListItem>
|
||||||
<GroupedListItem icon={LockClosed}>Privacy and Security</GroupedListItem>
|
<GroupedListItem icon={LockClosed}>Privacy and Security</GroupedListItem>
|
||||||
<GroupedListItem icon={DevicePhoneMobile}>Devices</GroupedListItem>
|
<GroupedListItem icon={DevicePhoneMobile}>Devices</GroupedListItem>
|
||||||
</GroupedListSection>
|
</GroupedListSection>
|
||||||
|
|
||||||
<GroupedListSection>
|
<GroupedListSection>
|
||||||
<GroupedListItem icon={InformationCircle}>About Blah & Weblah</GroupedListItem>
|
<GroupedListItem icon={InformationCircle}>About Blah & Weblah</GroupedListItem>
|
||||||
<GroupedListItem icon={QuestionMarkCircle}>Ask a Question</GroupedListItem>
|
<GroupedListItem icon={QuestionMarkCircle}>Ask a Question</GroupedListItem>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { openAccountStore } from '$lib/accounts/accountStore';
|
import { currentAccountStore, openAccountStore } from '$lib/accounts/accountStore';
|
||||||
import Button from '$lib/components/Button.svelte';
|
import Button from '$lib/components/Button.svelte';
|
||||||
import {
|
import {
|
||||||
GroupedListContainer,
|
GroupedListContainer,
|
||||||
|
@ -57,7 +57,8 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const accountStore = await openAccountStore();
|
const accountStore = await openAccountStore();
|
||||||
await accountStore.createAccount(profile, password);
|
const idKeyId = await accountStore.createAccount(profile, password);
|
||||||
|
$currentAccountStore = idKeyId;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue