Monorepo for Tangled
Something went wrong. Try again.
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147<script lang="ts"> import { untrack } from "svelte"; import { now as tidNow } from "@atcute/tid"; import Button from "$lib/components/ui/Button.svelte"; import Spinner from "$lib/components/ui/Spinner.svelte"; import ErrorAlert from "$lib/components/ui/Error.svelte"; import ArrowUp from "$icon/arrow-up"; import X from "$icon/x"; import { getAuth } from "$lib/auth.svelte"; import { putString } from "$lib/api/strings"; import type { StringRecord } from "$lib/api/records";
interface Props { mode?: "create" | "edit"; rkey?: string; createdAt?: string; filename?: string; description?: string; content?: string; onsaved: (rkey: string) => void; oncancel?: () => void; }
let { mode = "create", rkey, createdAt, filename: initialFilename = "", description: initialDescription = "", content: initialContent = "", onsaved, oncancel }: Props = $props();
const auth = getAuth();
let filename = $state(untrack(() => initialFilename)); let description = $state(untrack(() => initialDescription)); let content = $state(untrack(() => initialContent)); let isPublishing = $state(false); let error = $state<string | null>(null);
const lineCount = $derived(content === "" ? 0 : content.split("\n").length); const byteCount = $derived(new TextEncoder().encode(content).length);
const handleSubmit = async (e: SubmitEvent) => { e.preventDefault(); const agent = auth.agent; if (!agent || isPublishing) return; isPublishing = true; error = null; try { const targetRkey = rkey ?? tidNow(); const record: StringRecord = { $type: "sh.tangled.string", filename, description, contents: content, createdAt: createdAt ?? new Date().toISOString() }; await putString(agent, targetRkey, record); onsaved(targetRkey); } catch (err) { error = err instanceof Error ? err.message : "Failed to publish string"; } finally { isPublishing = false; } };</script>
<div class="rounded-sm border border-border-default bg-background-default"> <form onsubmit={handleSubmit}> <div class="flex flex-col gap-2 p-4"> <div class="flex flex-col gap-2 md:flex-row"> <input type="text" id="filename" name="filename" placeholder="Filename" required bind:value={filename} disabled={isPublishing} class="rounded-sm border border-border-default bg-background-default p-2 text-sm text-foreground-default placeholder:text-foreground-placeholder focus:ring-1 focus:ring-border-strong focus:outline-none disabled:opacity-50 md:max-w-64" /> <input type="text" id="description" name="description" placeholder="Description ..." maxlength={280} bind:value={description} disabled={isPublishing} class="flex-1 rounded-sm border border-border-default bg-background-default p-2 text-sm text-foreground-default placeholder:text-foreground-placeholder focus:ring-1 focus:ring-border-strong focus:outline-none disabled:opacity-50" /> </div>
<textarea id="content" name="content" placeholder="Paste your string here!" required rows={20} spellcheck={false} bind:value={content} disabled={isPublishing} class="w-full resize-y rounded-sm border border-border-default bg-background-default p-2 font-mono text-sm text-foreground-default placeholder:text-foreground-placeholder focus:ring-1 focus:ring-border-strong focus:outline-none disabled:opacity-50" ></textarea> </div>
<div class="flex items-center justify-between px-4 py-3"> <div class="text-sm text-foreground-subtle"> <span>{lineCount} line{lineCount !== 1 ? "s" : ""}</span> <span class="px-1 select-none">·</span> <span>{byteCount} byte{byteCount !== 1 ? "s" : ""}</span> </div>
<div class="flex items-center gap-2"> {#if mode === "edit"} <Button type="button" variant="default" icon={X} disabled={isPublishing} onclick={oncancel} > Cancel </Button> {/if} <Button type="submit" variant="primary" icon={isPublishing ? Spinner : ArrowUp} disabled={isPublishing} > Publish </Button> </div> </div>
{#if error} <div class="px-4 pb-4"> <ErrorAlert label={error} /> </div> {/if} </form></div>