refactor: continue to migrate components

This commit is contained in:
Shibo Lyu 2025-03-17 01:54:56 +08:00
parent 1e95dc0830
commit 4129cac511
24 changed files with 147 additions and 262 deletions

View file

@ -12,8 +12,6 @@
let { searchQuery = $bindable(''), isSearchFocused = $bindable() }: Props = $props();
let inputElement: HTMLInputElement = $state();
function onTapClear(e: MouseEvent) {
e.preventDefault();
e.stopPropagation();
@ -21,7 +19,7 @@
}
</script>
<header class="flex items-center justify-stretch gap-2 border-b border-ss-secondary p-2 shadow-xs">
<header class="border-ss-secondary flex items-center justify-stretch gap-2 border-b p-2 shadow-xs">
<a
class={tw(
'transition-[opacity,transform] duration-200',
@ -38,9 +36,8 @@
<input
type="search"
placeholder="Search"
class="w-full flex-1 bg-transparent text-sm leading-4 text-sf-primary focus:outline-hidden"
class="text-sf-primary w-full flex-1 bg-transparent text-sm leading-4 focus:outline-hidden"
bind:value={searchQuery}
bind:this={inputElement}
onfocus={() => {
isSearchFocused = true;
}}

View file

@ -1,13 +1,11 @@
<script lang="ts">
import { run } from 'svelte/legacy';
import { AvatarBeam } from 'svelte-boring-avatars';
import { formatMessageDate, formatUnreadCount } from '$lib/formatters';
import { formatMessageDate, formatFullMessageDate, formatUnreadCount } from '$lib/formatters';
import type { Chat } from '$lib/types';
import { currentKeyPair } from '$lib/keystore';
import { blahRichTextToPlainText } from '$lib/richText';
import { page } from '$app/stores';
import { toPlainText } from '@blah-im/core/richText';
import { page } from '$app/state';
import { tw } from '$lib/tw';
interface Props {
@ -16,19 +14,20 @@
let { chat }: Props = $props();
let urlSafeEndpoint: string = $state();
run(() => {
function urlSafeEndpointForChat(chat: Chat) {
const url = new URL(chat.server);
urlSafeEndpoint = encodeURIComponent(url.hostname + url.pathname);
});
return encodeURIComponent(url.hostname + url.pathname);
}
let isSelected = $derived($page.params.chatId === chat.id);
let urlSafeEndpoint = $derived(urlSafeEndpointForChat(chat));
let isSelected = $derived(page.params.chatId === chat.id);
</script>
<li
class={tw(
'relative after:absolute after:bottom-0 after:end-0 after:start-14 after:border-t-[0.5px] after:border-ss-secondary',
isSelected && 'bg-accent-100 shadow-inner dark:bg-accent-950'
'after:border-ss-secondary relative after:absolute after:start-14 after:end-0 after:bottom-0 after:border-t-[0.5px]',
isSelected && 'bg-accent-100 dark:bg-accent-950 shadow-inner'
)}
>
<a
@ -44,16 +43,16 @@
<h3 class="flex-1 truncate text-sm font-semibold">{chat.name}</h3>
{#if chat.lastMessage}
<time
class="truncate text-xs text-sf-tertiary"
class="text-sf-tertiary truncate text-xs"
datetime={chat.lastMessage.date.toISOString()}
title={formatMessageDate(chat.lastMessage.date, true)}
title={formatFullMessageDate(chat.lastMessage.date)}
>
{formatMessageDate(chat.lastMessage.date)}
</time>
{/if}
</div>
<div class="flex items-end gap-1">
<p class="line-clamp-2 h-[2.5em] flex-1 text-sm leading-tight text-sf-secondary">
<p class="text-sf-secondary line-clamp-2 h-[2.5em] flex-1 text-sm leading-tight">
{#if chat.lastMessage}
{#if chat.id !== chat.lastMessage.sender.id}
<span class="text-sf-primary">
@ -62,12 +61,12 @@
: chat.lastMessage.sender.name}:
</span>
{/if}
{blahRichTextToPlainText(chat.lastMessage.content)}
{toPlainText(chat.lastMessage.content)}
{/if}
</p>
{#if chat.unreadCount}
<span
class="whitespace-nowrap rounded-full bg-slate-400 px-1.5 py-0.5 text-xs text-slate-50 dark:bg-slate-500 dark:text-slate-950"
class="rounded-full bg-slate-400 px-1.5 py-0.5 text-xs whitespace-nowrap text-slate-50 dark:bg-slate-500 dark:text-slate-950"
>
{formatUnreadCount(chat.unreadCount)}
</span>

View file

@ -13,7 +13,7 @@
let { size = 32 }: Props = $props();
let accountStore: AccountStore = $state();
let accountStore: AccountStore | undefined = $state();
onMount(() => {
openAccountStore().then((store) => {
@ -22,7 +22,7 @@
});
</script>
{#if accountStore}
{#if accountStore && $accountStore}
{@const currentAccount = $accountStore.find((account) => account.id_key === $currentAccountStore)}
<ProfilePicture account={currentAccount} {size} />
{:else}

View file

@ -13,12 +13,12 @@
<li>
<h3
class="ms-2 border-b-[0.5px] border-ss-secondary pb-1 pe-2 pt-2 text-xs font-semibold uppercase text-sf-secondary"
class="border-ss-secondary text-sf-secondary ms-2 border-b-[0.5px] pe-2 pt-2 pb-1 text-xs font-semibold uppercase"
>
{name}
</h3>
<ul>
{#each results as chat}
{#each results as chat (chat.id)}
<ChatListItem {chat} />
{/each}
</ul>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import { chatServerConnectionPool } from '$lib/chatServers';
import { ChatBubbleLeftRight, Icon } from 'svelte-hero-icons';
import ChatListItem from './ChatListItem.svelte';
import SearchChatResultSection from './SearchChatResultSection.svelte';
interface Props {
@ -18,7 +17,7 @@
{#await search(searchQuery)}
<div class="flex size-full items-center justify-center">
<Icon src={ChatBubbleLeftRight} solid class="w-1/3 animate-pulse fill-sf-tertiary" />
<Icon src={ChatBubbleLeftRight} solid class="fill-sf-tertiary w-1/3 animate-pulse" />
</div>
{:then results}
{#if results.joined.length === 0 && results.public.length === 0}

View file

@ -1,7 +1,7 @@
<script lang="ts">
import Button from '$lib/components/Button.svelte';
import RichTextInput from '$lib/components/RichTextInput.svelte';
import { deltaToBlahRichText, type BlahRichText } from '$lib/richText';
import { deltaToBlahRichText, type BlahRichText } from '@blah-im/core/richText';
import { createEventDispatcher } from 'svelte';
import type { Delta, Editor } from 'typewriter-editor';

View file

@ -8,7 +8,7 @@
import ChatHeader from './ChatHeader.svelte';
import ChatHistory from './ChatHistory.svelte';
import ChatInput from './ChatInput.svelte';
import type { BlahRichText } from '$lib/richText';
import type { BlahRichText } from '@blah-im/core/richText';
import type { MessageSection } from '$lib/chat';
interface Props {

View file

@ -11,9 +11,9 @@
import { onMount } from 'svelte';
import ProfilePicture from '$lib/components/ProfilePicture.svelte';
import { flip } from 'svelte/animate';
import { blur, scale } from 'svelte/transition';
import { blur } from 'svelte/transition';
let accountStore: AccountStore = $state();
let accountStore: AccountStore | undefined = $state();
onMount(() => {
openAccountStore().then((store) => {
@ -26,7 +26,7 @@
}
</script>
{#if accountStore}
{#if accountStore && $accountStore}
{@const currentAccount = $accountStore.find((acc) => acc.id_key === $currentAccountStore)}
{@const remainingAccounts = $accountStore
.filter((acc) => acc.id_key !== $currentAccountStore)
@ -38,12 +38,12 @@
<ProfilePicture account={currentAccount} size={68} />
</div>
<p>
<span class="text-xl font-semibold text-sf-primary">
<span class="text-sf-primary text-xl font-semibold">
{currentAccount.profile.signee.payload.name}
</span>
</p>
<p>
<code class="text-sm text-sf-secondary">
<code class="text-sf-secondary text-sm">
{currentAccount.profile.signee.id_key.slice(0, 6) +
'...' +
currentAccount.profile.signee.id_key.slice(-6)}
@ -57,7 +57,7 @@
<GroupedListSection>
{#each remainingAccounts as account (account.id_key)}
<div animate:flip={{ duration: 250 }} transition:blur>
<GroupedListItem on:click={() => switchToAccount(account)}>
<GroupedListItem onclick={() => switchToAccount(account)}>
<div class="-mx-0.5"><ProfilePicture {account} size={24} /></div>
{account.profile.signee.payload.name}
</GroupedListItem>