This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

web: use a shared function for copy feedback

Signed-off-by: dawn <dawn@tangled.org>

author
dawn
date (Aug 1, 2026, 2:21 AM +0300) commit d89ba19e parent 20dd700c change-id squqnruq
+8 -20
+4 -12
web/src/lib/components/repo/CloneDropdown.svelte
··· 5 5 import Download from "$icon/download"; 6 6 import Checkbox from "$lib/components/ui/Checkbox.svelte"; 7 7 import Dropdown from "$lib/components/ui/Dropdown.svelte"; 8 + import { createCopyFeedback } from "$lib/copy.svelte"; 8 9 import type { RepoInfo } from "./types"; 9 10 10 11 interface Props { ··· 25 26 const origin = $derived(page.url.origin); 26 27 27 28 let permalink = $state(false); 28 - let copied = $state<string | null>(null); 29 + const copyFeedback = createCopyFeedback(); 29 30 30 31 const urls = $derived([ 31 32 { ··· 48 49 return url.toString(); 49 50 }; 50 51 51 - const copy = async (label: string, value: string) => { 52 - try { 53 - await navigator.clipboard.writeText(value); 54 - copied = label; 55 - setTimeout(() => (copied = copied === label ? null : copied), 2000); 56 - } catch { 57 - // clipboard was denied, the text is still selectable 58 - } 59 - }; 60 52 </script> 61 53 62 54 <Dropdown ··· 98 90 class="cursor-pointer px-3 py-2 text-foreground-subtle hover:text-foreground-default" 99 91 title="Copy to clipboard" 100 92 aria-label={`Copy ${entry.label} clone url`} 101 - onclick={() => copy(entry.label, value)} 93 + onclick={() => void copyFeedback.copy(entry.label, value)} 102 94 > 103 - {#if copied === entry.label} 95 + {#if copyFeedback.copied === entry.label} 104 96 <Check class="size-4" aria-hidden="true" /> 105 97 {:else} 106 98 <Copy class="size-4" aria-hidden="true" />
+4 -8
web/src/routes/[handle]/[repo]/settings/rename/+page.svelte
··· 11 11 import CopyCheck from "$icon/copy-check"; 12 12 import Plus from "$icon/plus"; 13 13 import X from "$icon/x"; 14 + import { createCopyFeedback } from "$lib/copy.svelte"; 14 15 15 16 let { data } = $props(); 16 17 ··· 20 21 // the point of the screen: these survive a rename, the handle-based ones don't 21 22 const stableUrls = $derived([`https://tangled.org/${did}`, `git@tangled.org:${did}`]); 22 23 23 - let copied = $state<string | null>(null); 24 - const copy = async (url: string) => { 25 - await navigator.clipboard.writeText(url); 26 - copied = url; 27 - setTimeout(() => (copied === url ? (copied = null) : null), 1500); 28 - }; 24 + const copyFeedback = createCopyFeedback(); 29 25 30 26 let name = $state(""); 31 27 const valid = $derived(name.trim().length > 0 && name.trim() !== data.repo.name); ··· 51 47 </code> 52 48 <button 53 49 type="button" 54 - onclick={() => copy(url)} 50 + onclick={() => void copyFeedback.copy(url)} 55 51 aria-label="Copy {url}" 56 52 class="cursor-pointer text-foreground-muted hover:text-foreground-default" 57 53 > 58 - {#if copied === url} 54 + {#if copyFeedback.copied === url} 59 55 <CopyCheck class="size-3.5" aria-hidden="true" /> 60 56 {:else} 61 57 <Copy class="size-3.5" aria-hidden="true" />