Monorepo for Tangled
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138<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"; import { createAction } from "$lib/action.svelte";
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));
const lineCount = $derived(content === "" ? 0 : content.split("\n").length); const byteCount = $derived(new TextEncoder().encode(content).length);
const publish = createAction(async (event: SubmitEvent) => { event.preventDefault(); const agent = auth.agent; if (!agent) return; 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); });</script>
<div class="rounded-sm border border-border-default bg-background-default"> <form onsubmit={publish.run}> <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={publish.loading} class="rounded-sm border border-border-default bg-background-default p-2 typography-paragraph-small 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={publish.loading} class="flex-1 rounded-sm border border-border-default bg-background-default p-2 typography-paragraph-small 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={publish.loading} class="w-full resize-y rounded-sm border border-border-default bg-background-default p-2 font-mono typography-paragraph-small 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="typography-paragraph-small 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={publish.loading} onclick={oncancel} > Cancel </Button> {/if} <Button type="submit" variant="primary" icon={publish.loading ? Spinner : ArrowUp} disabled={publish.loading} > Publish </Button> </div> </div>
{#if publish.error} <div class="px-4 pb-4"> <ErrorAlert label={publish.error} /> </div> {/if} </form></div>