1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-11 05:59:15 +00:00

feat: support for url based icons (#840)

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Kyle Mendell
2025-09-29 10:07:55 -05:00
committed by GitHub
parent 47bd5ba1ba
commit 6bdf5fa37a
19 changed files with 650 additions and 442 deletions

View File

@@ -0,0 +1,85 @@
<script lang="ts">
import FileInput from '$lib/components/form/file-input.svelte';
import FormattedMessage from '$lib/components/formatted-message.svelte';
import { Button, buttonVariants } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import * as Popover from '$lib/components/ui/popover';
import { m } from '$lib/paraglide/messages';
import { cn } from '$lib/utils/style';
import { LucideChevronDown } from '@lucide/svelte';
let {
label,
accept,
onchange
}: {
label: string;
accept?: string;
onchange: (file: File | string | null) => void;
} = $props();
let url = $state('');
let hasError = $state(false);
async function handleFileChange(e: Event) {
const file = (e.target as HTMLInputElement).files?.[0] || null;
url = '';
hasError = false;
onchange(file);
}
async function handleUrlChange(e: Event) {
const url = (e.target as HTMLInputElement).value.trim();
if (!url) return;
try {
new URL(url);
hasError = false;
} catch {
hasError = true;
return;
}
onchange(url);
}
</script>
<div class="flex">
<FileInput
id="logo"
variant="secondary"
{accept}
onchange={handleFileChange}
onclick={(e: any) => (e.target.value = '')}
>
<Button variant="secondary" class="rounded-r-none">
{label}
</Button>
</FileInput>
<Popover.Root>
<Popover.Trigger
class={cn(buttonVariants({ variant: 'secondary' }), 'rounded-l-none border-l')}
>
<LucideChevronDown class="size-4" /></Popover.Trigger
>
<Popover.Content class="w-80">
<Label for="file-url" class="text-xs">URL</Label>
<Input
id="file-url"
placeholder=""
value={url}
oninput={(e) => (url = e.currentTarget.value)}
onfocusout={handleUrlChange}
aria-invalid={hasError}
/>
{#if hasError}
<p class="text-destructive mt-1 text-start text-xs">{m.invalid_url()}</p>
{/if}
<p class="text-muted-foreground mt-2 text-xs">
<FormattedMessage m={m.logo_from_url_description()} />
</p>
</Popover.Content>
</Popover.Root>
</div>

View File

@@ -1,10 +1,25 @@
<script lang="ts">
import { cn } from '$lib/utils/style';
import { LucideImageOff } from '@lucide/svelte';
import type { HTMLImgAttributes } from 'svelte/elements';
let props: HTMLImgAttributes & {} = $props();
let error = $state(false);
$effect(() => {
props.src;
error = false;
});
</script>
<div class={'bg-muted flex items-center justify-center rounded-2xl p-3'}>
<img class={cn('size-24 object-contain', props.class)} {...props} />
{#if error}
<LucideImageOff class={cn('text-muted-foreground p-5', props.class)} />
{:else}
<img
{...props}
class={cn('object-contain', props.class)}
onerror={() => (error = true)}
/>
{/if}
</div>