mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-07-08 23:15:33 +00:00
refactor: continue to migrate components
This commit is contained in:
parent
1e95dc0830
commit
4129cac511
24 changed files with 147 additions and 262 deletions
|
@ -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;
|
||||
}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue