initial commit

This commit is contained in:
Moon.eth
2026-07-29 09:16:38 +09:00
commit 586b599d4c
67 changed files with 9906 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
<script lang="ts">
/**
* "Contacting Tom" — the two-column action list.
*
* Follow state comes from `/api/v1/accounts/relationships`, which is only
* available when signed in; logged out, the actions become sign-in prompts
* rather than disappearing, so the box keeps its shape.
*/
import type { Account, Relationship } from '$lib/api/types'
import { session } from '$lib/stores/session.svelte'
import { blockAccount, followAccount, unblockAccount, unfollowAccount } from '$lib/api/endpoints'
import { displayNameOf } from '$lib/util/profile'
import Module from '../common/Module.svelte'
interface Props {
account: Account
relationship: Relationship | null
onrelationship?: (relationship: Relationship) => void
}
let { account, relationship, onrelationship }: Props = $props()
let busy = $state(false)
let error = $state<string | null>(null)
const firstName = $derived(displayNameOf(account).split(/\s+/)[0])
const isSelf = $derived(session.me?.id === account.id)
const following = $derived(relationship?.following ?? false)
const requested = $derived(relationship?.requested ?? false)
const blocking = $derived(relationship?.blocking ?? false)
const followLabel = $derived(
blocking
? 'Unblock User'
: following
? 'Remove from Friends'
: requested
? 'Cancel Friend Request'
: account.locked
? 'Request to Add'
: 'Add to Friends',
)
async function run(action: () => Promise<Relationship>): Promise<void> {
if (busy) return
busy = true
error = null
try {
onrelationship?.(await action())
} catch (cause) {
error = cause instanceof Error ? cause.message : 'That didnt work.'
} finally {
busy = false
}
}
function toggleFollow(): void {
if (blocking) {
void run(() => unblockAccount(session.api, account.id))
} else if (following || requested) {
void run(() => unfollowAccount(session.api, account.id))
} else {
void run(() => followAccount(session.api, account.id))
}
}
function toggleBlock(): void {
void run(() =>
blocking ? unblockAccount(session.api, account.id) : blockAccount(session.api, account.id),
)
}
</script>
<Module title={`Contacting ${firstName}`}>
{#if error}
<p class="error-note" role="alert">{error}</p>
{/if}
<ul class="action-list">
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
{#if session.signedIn}
<a class="action-list-label" href={`#/compose?to=${encodeURIComponent(account.acct)}`}>Send Message</a>
{:else}
<a class="action-list-label" href="#/login">Send Message</a>
{/if}
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true">👤</span>
{#if isSelf}
<span class="action-list-label muted">This is you</span>
{:else if session.signedIn}
<button
type="button"
class="link-button action-list-label"
disabled={busy}
aria-pressed={following ? 'true' : 'false'}
onclick={toggleFollow}
>
{followLabel}
</button>
{:else}
<a class="action-list-label" href="#/login">Add to Friends</a>
{/if}
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
<a class="action-list-label" href={account.url} target="_blank" rel="noopener noreferrer">
View on {account.acct.includes('@') ? account.acct.split('@')[1] : session.host}
</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
<a class="action-list-label" href={`#/@${account.acct}/friends`}>Forward to Friend</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true">💬</span>
<a class="action-list-label" href={`#/@${account.acct}/blog`}>Instant Message</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
{#if isSelf || !session.signedIn}
<span class="action-list-label muted">Block User</span>
{:else}
<button type="button" class="link-button action-list-label" disabled={busy} onclick={toggleBlock}>
{blocking ? 'Unblock User' : 'Block User'}
</button>
{/if}
</li>
</ul>
{#if relationship?.followed_by && !isSelf}
<p class="contact-note muted">{firstName} has you on their friends list.</p>
{/if}
</Module>