Files
beavergram/frontend/src/lib/components/media/FileChip.svelte
T

180 lines
3.6 KiB
Svelte

<script lang="ts">
import { downloadMedia } from "$lib/api/download";
import type { MediaRef } from "$lib/api/types";
import Icon from "$lib/components/ui/Icon.svelte";
import { formatBytes, mediaKindLabel } from "$lib/format/media";
import { shareUi } from "$lib/stores/shares.svelte";
import { toasts } from "$lib/stores/toasts.svelte";
interface Props {
media: MediaRef;
own?: boolean;
}
const { media, own = false }: Props = $props();
let saving = $state(false);
const name = $derived(
media.file_name ?? mediaKindLabel(media.kind) ?? "Файл"
);
const size = $derived(formatBytes(media.file_size));
async function save() {
if (media.id === null || saving) {
return;
}
saving = true;
try {
await downloadMedia(media.id);
} catch {
toasts.error("Не удалось скачать файл");
} finally {
saving = false;
}
}
function share() {
if (media.id !== null) {
shareUi.share({ kind: "media", mediaId: media.id }, name);
}
}
</script>
<div class="FileChip" class:own>
<button class="file-main" type="button" title={name} onclick={save}>
<span class="file-glyph" class:own>
<Icon name={saving ? "timer" : "document"} size="1.25rem" />
</span>
<span class="file-text">
<span class="file-name">{name}</span>
<span class="file-sub">{size || mediaKindLabel(media.kind)}</span>
</span>
</button>
<button
class="file-share"
type="button"
aria-label="Доступ по ссылке"
onclick={share}
>
<Icon name="allow-share" size="1.125rem" />
</button>
</div>
<style lang="scss">
.FileChip {
display: flex;
align-items: center;
gap: 0.25rem;
width: 100%;
max-width: 20rem;
padding: 0.25rem 0.375rem 0.25rem 0.25rem;
border-radius: var(--border-radius-default-small);
background-color: var(--color-primary-tint);
&.own {
background-color: var(--color-code-own-bg);
}
}
.file-main {
cursor: pointer;
display: flex;
flex: 1;
align-items: center;
gap: 0.625rem;
min-width: 0;
padding: 0.25rem;
border: 0;
font-family: inherit;
text-align: start;
background: transparent;
}
.file-glyph :global(.icon) {
transform: translate(0.5px, -0.5px);
}
.file-glyph {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 2.25rem;
height: 2.25rem;
border-radius: 50%;
color: var(--color-white);
background-color: var(--color-primary);
&.own {
color: var(--color-own-links);
background-color: color-mix(
in srgb,
var(--color-own-links) 20%,
transparent
);
}
}
.file-text {
display: flex;
flex-direction: column;
min-width: 0;
}
.file-name {
overflow: hidden;
font-size: 0.9375rem;
color: var(--color-text);
text-overflow: ellipsis;
white-space: nowrap;
}
.file-sub {
font-size: 0.75rem;
color: var(--color-text-secondary);
}
.own .file-sub {
color: var(--color-message-meta-own);
}
.file-share {
cursor: pointer;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
border: 0;
border-radius: 50%;
color: var(--color-primary);
background: transparent;
&:hover {
background-color: var(--color-primary-opacity);
}
}
.own .file-share {
color: var(--color-own-links);
&:hover {
background-color: color-mix(in srgb, currentcolor 18%, transparent);
}
}
</style>