refactor: Update account creation UI and bump @blah-im/core

Improve identity provider selection with proper self-hosting flow options.
Fix empty state detection in rich text editor and display shortened
account ID key in settings screen.
This commit is contained in:
Shibo Lyu 2025-04-12 22:34:01 +08:00
parent a27b585f26
commit 6b32bda600
6 changed files with 53 additions and 28 deletions

View file

@ -38,7 +38,7 @@
"vitest": "^3.1.1"
},
"dependencies": {
"@blah-im/core": "^0.5.0",
"@blah-im/core": "^0.5.1",
"@melt-ui/svelte": "^0.86.6",
"@zeabur/svelte-adapter": "^1.0.0",
"bits-ui": "^1.3.19",

10
pnpm-lock.yaml generated
View file

@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@blah-im/core':
specifier: ^0.5.0
version: 0.5.0
specifier: ^0.5.1
version: 0.5.1
'@melt-ui/svelte':
specifier: ^0.86.6
version: 0.86.6(svelte@5.25.12)
@ -143,8 +143,8 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@blah-im/core@0.5.0':
resolution: {integrity: sha512-Joaj8K+yd4DVwQrSe8NRxwjMFtzibvj9z70fl/s3ulw+1+dZtsCaRoYnNHS0hE8CZ7g2QshLG6ymvWBQo4rXNQ==}
'@blah-im/core@0.5.1':
resolution: {integrity: sha512-JEyIS4vTZFlYP67BtdJute+yT3hDBJoOLGZ+YZ5j5UQ2ttP9vAFeXsaX7ErstoXskQU7d9f7u0T0vmnzomVv8g==}
'@esbuild/aix-ppc64@0.19.12':
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
@ -2091,7 +2091,7 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
'@blah-im/core@0.5.0':
'@blah-im/core@0.5.1':
dependencies:
zod: 3.24.2

View file

@ -1,4 +1,6 @@
<script lang="ts">
import { tw } from '$lib/tw';
interface Props {
children?: import('svelte').Snippet;
}
@ -7,7 +9,10 @@
</script>
<label
class="flex gap-2 px-4 py-3 font-medium text-sf-primary [align-items:first_baseline] [&>input]:flex-1 [&>input]:bg-transparent [&>input]:text-end [&>input]:outline-hidden [&>input]:placeholder:opacity-50"
class={tw(
'text-sf-primary flex [align-items:first_baseline] gap-2 px-4 py-3 font-medium',
'[&>input]:flex-1 [&>input]:bg-transparent [&>input]:text-end [&>input]:outline-hidden [&>input]:placeholder:opacity-50'
)}
>
{@render children?.()}
</label>

View file

@ -21,6 +21,7 @@
const initialDoc = DOMParser.fromSchema(stateConfiguration.schema).parse(domEl);
domEl.replaceChildren();
onDocChange?.(initialDoc);
isEmpty = initialDoc.textContent.length === 0;
const state = createProseMirrorEditorState({ initialDoc, ...stateConfiguration });
editorView = new EditorView(

View file

@ -44,9 +44,7 @@
</p>
<p>
<code class="text-sf-secondary text-sm">
{currentAccount.profile.signee.id_key.slice(0, 6) +
'...' +
currentAccount.profile.signee.id_key.slice(-6)}
{currentAccount.id_key.slice(0, 4) + '..' + currentAccount.id_key.slice(-4)}
</code>
</p>
</div>

View file

@ -6,7 +6,6 @@
import {
GroupedListContainer,
GroupedListSection,
GroupedListItem,
GroupedListInputItem
} from '$lib/components/GroupedList';
import LoadingIndicator from '$lib/components/LoadingIndicator.svelte';
@ -24,12 +23,18 @@
let password: string = $state('');
let repeatPassword: string = $state('');
let identityServer: string = $state('other.blue');
let selfhostDomain: string = $state('');
let isBusy: boolean = $state(false);
let passwordMatch = $derived(password === repeatPassword);
let canCreate = $derived(name.length > 0 && password.length > 0 && passwordMatch);
let customize = $derived(page.url.hash === '#customize');
const passwordMatch = $derived(password === repeatPassword);
const selfhostIdentity = $derived(page.url.hash === '#identity-selfhost');
const canCreate = $derived(
name.length > 0 &&
password.length > 0 &&
passwordMatch &&
(selfhostIdentity ? selfhostDomain.length > 0 : false)
);
async function createAccount() {
const profile: BlahProfile = {
@ -37,7 +42,7 @@
name,
bio: bioDoc?.textContent,
preferred_chat_server_urls: [],
id_urls: []
id_urls: selfhostIdentity ? ['https://' + selfhostDomain] : []
};
isBusy = true;
@ -114,7 +119,27 @@
</div>
{/snippet}
</GroupedListSection>
{#if customize}
{#if selfhostIdentity}
<GroupedListSection header="Profile Hosting">
<GroupedListInputItem>
Domain Name
<input type="text" bind:value={selfhostDomain} placeholder="example.com" />
</GroupedListInputItem>
{#snippet footer()}
<div class="space-y-1">
<p>
After creating account, you need to serve your profile file to a specific location under
this domain.
<Link href="/" variant="secondary">Learn more about hosting your own profile...</Link>
</p>
<p>
<Link href="#" variant="secondary">Use identity service</Link> if you you want a simple way
to start. You can always switch to self-hosting later.
</p>
</div>
{/snippet}
</GroupedListSection>
{:else}
<GroupedListSection header="Identity Service">
<GroupedListInputItem>
Initial Service
@ -123,23 +148,19 @@
{#snippet footer()}
<div class="space-y-1">
<p>
Your profile is stored and served to other users on the identity service.
By creating an account on <em>{identityServer}</em>, which stores and serve this public
profile to other users, you agree to Terms of Service and Privacy Policy of
<em>{identityServer}</em>.
<Link href="/" variant="secondary">Learn more about identity services...</Link>
</p>
<p>You can add, replace or remove identity services later in account settings.</p>
<p>
If you own or can afford a domain name, you can
<Link href="#identity-selfhost" variant="secondary">host your own profile</Link>
instead of using a service.
</p>
</div>
{/snippet}
</GroupedListSection>
{/if}
<div class="text-sf-tertiary px-8 text-sm">
<p>
By creating an account, you agree to Terms of Service and Privacy Policy of
<em>{identityServer}</em>, which stores and serve your public profile to other users.
{#if customize}
<Link href="#">Use default</Link>
{:else}
<Link href="#customize">Customize...</Link>
{/if}
</p>
</div>
</GroupedListContainer>