mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-05-01 00:31:08 +00:00
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:
parent
a27b585f26
commit
6b32bda600
6 changed files with 53 additions and 28 deletions
|
@ -38,7 +38,7 @@
|
||||||
"vitest": "^3.1.1"
|
"vitest": "^3.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blah-im/core": "^0.5.0",
|
"@blah-im/core": "^0.5.1",
|
||||||
"@melt-ui/svelte": "^0.86.6",
|
"@melt-ui/svelte": "^0.86.6",
|
||||||
"@zeabur/svelte-adapter": "^1.0.0",
|
"@zeabur/svelte-adapter": "^1.0.0",
|
||||||
"bits-ui": "^1.3.19",
|
"bits-ui": "^1.3.19",
|
||||||
|
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
@ -9,8 +9,8 @@ importers:
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@blah-im/core':
|
'@blah-im/core':
|
||||||
specifier: ^0.5.0
|
specifier: ^0.5.1
|
||||||
version: 0.5.0
|
version: 0.5.1
|
||||||
'@melt-ui/svelte':
|
'@melt-ui/svelte':
|
||||||
specifier: ^0.86.6
|
specifier: ^0.86.6
|
||||||
version: 0.86.6(svelte@5.25.12)
|
version: 0.86.6(svelte@5.25.12)
|
||||||
|
@ -143,8 +143,8 @@ packages:
|
||||||
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
'@blah-im/core@0.5.0':
|
'@blah-im/core@0.5.1':
|
||||||
resolution: {integrity: sha512-Joaj8K+yd4DVwQrSe8NRxwjMFtzibvj9z70fl/s3ulw+1+dZtsCaRoYnNHS0hE8CZ7g2QshLG6ymvWBQo4rXNQ==}
|
resolution: {integrity: sha512-JEyIS4vTZFlYP67BtdJute+yT3hDBJoOLGZ+YZ5j5UQ2ttP9vAFeXsaX7ErstoXskQU7d9f7u0T0vmnzomVv8g==}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.19.12':
|
'@esbuild/aix-ppc64@0.19.12':
|
||||||
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
|
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
|
||||||
|
@ -2091,7 +2091,7 @@ snapshots:
|
||||||
'@jridgewell/gen-mapping': 0.3.8
|
'@jridgewell/gen-mapping': 0.3.8
|
||||||
'@jridgewell/trace-mapping': 0.3.25
|
'@jridgewell/trace-mapping': 0.3.25
|
||||||
|
|
||||||
'@blah-im/core@0.5.0':
|
'@blah-im/core@0.5.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { tw } from '$lib/tw';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children?: import('svelte').Snippet;
|
children?: import('svelte').Snippet;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +9,10 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label
|
<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?.()}
|
{@render children?.()}
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
const initialDoc = DOMParser.fromSchema(stateConfiguration.schema).parse(domEl);
|
const initialDoc = DOMParser.fromSchema(stateConfiguration.schema).parse(domEl);
|
||||||
domEl.replaceChildren();
|
domEl.replaceChildren();
|
||||||
onDocChange?.(initialDoc);
|
onDocChange?.(initialDoc);
|
||||||
|
isEmpty = initialDoc.textContent.length === 0;
|
||||||
|
|
||||||
const state = createProseMirrorEditorState({ initialDoc, ...stateConfiguration });
|
const state = createProseMirrorEditorState({ initialDoc, ...stateConfiguration });
|
||||||
editorView = new EditorView(
|
editorView = new EditorView(
|
||||||
|
|
|
@ -44,9 +44,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<code class="text-sf-secondary text-sm">
|
<code class="text-sf-secondary text-sm">
|
||||||
{currentAccount.profile.signee.id_key.slice(0, 6) +
|
{currentAccount.id_key.slice(0, 4) + '..' + currentAccount.id_key.slice(-4)}
|
||||||
'...' +
|
|
||||||
currentAccount.profile.signee.id_key.slice(-6)}
|
|
||||||
</code>
|
</code>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import {
|
import {
|
||||||
GroupedListContainer,
|
GroupedListContainer,
|
||||||
GroupedListSection,
|
GroupedListSection,
|
||||||
GroupedListItem,
|
|
||||||
GroupedListInputItem
|
GroupedListInputItem
|
||||||
} from '$lib/components/GroupedList';
|
} from '$lib/components/GroupedList';
|
||||||
import LoadingIndicator from '$lib/components/LoadingIndicator.svelte';
|
import LoadingIndicator from '$lib/components/LoadingIndicator.svelte';
|
||||||
|
@ -24,12 +23,18 @@
|
||||||
let password: string = $state('');
|
let password: string = $state('');
|
||||||
let repeatPassword: string = $state('');
|
let repeatPassword: string = $state('');
|
||||||
let identityServer: string = $state('other.blue');
|
let identityServer: string = $state('other.blue');
|
||||||
|
let selfhostDomain: string = $state('');
|
||||||
|
|
||||||
let isBusy: boolean = $state(false);
|
let isBusy: boolean = $state(false);
|
||||||
|
|
||||||
let passwordMatch = $derived(password === repeatPassword);
|
const passwordMatch = $derived(password === repeatPassword);
|
||||||
let canCreate = $derived(name.length > 0 && password.length > 0 && passwordMatch);
|
const selfhostIdentity = $derived(page.url.hash === '#identity-selfhost');
|
||||||
let customize = $derived(page.url.hash === '#customize');
|
const canCreate = $derived(
|
||||||
|
name.length > 0 &&
|
||||||
|
password.length > 0 &&
|
||||||
|
passwordMatch &&
|
||||||
|
(selfhostIdentity ? selfhostDomain.length > 0 : false)
|
||||||
|
);
|
||||||
|
|
||||||
async function createAccount() {
|
async function createAccount() {
|
||||||
const profile: BlahProfile = {
|
const profile: BlahProfile = {
|
||||||
|
@ -37,7 +42,7 @@
|
||||||
name,
|
name,
|
||||||
bio: bioDoc?.textContent,
|
bio: bioDoc?.textContent,
|
||||||
preferred_chat_server_urls: [],
|
preferred_chat_server_urls: [],
|
||||||
id_urls: []
|
id_urls: selfhostIdentity ? ['https://' + selfhostDomain] : []
|
||||||
};
|
};
|
||||||
isBusy = true;
|
isBusy = true;
|
||||||
|
|
||||||
|
@ -114,7 +119,27 @@
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</GroupedListSection>
|
</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">
|
<GroupedListSection header="Identity Service">
|
||||||
<GroupedListInputItem>
|
<GroupedListInputItem>
|
||||||
Initial Service
|
Initial Service
|
||||||
|
@ -123,23 +148,19 @@
|
||||||
{#snippet footer()}
|
{#snippet footer()}
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<p>
|
<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>
|
<Link href="/" variant="secondary">Learn more about identity services...</Link>
|
||||||
</p>
|
</p>
|
||||||
<p>You can add, replace or remove identity services later in account settings.</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>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</GroupedListSection>
|
</GroupedListSection>
|
||||||
{/if}
|
{/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>
|
</GroupedListContainer>
|
||||||
|
|
Loading…
Add table
Reference in a new issue