fix(api,frontend): render files by name without fetching, previewable share links
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import { fetchMedia } from "$lib/api/endpoints";
|
||||
import {
|
||||
type InlineMedia,
|
||||
isPreviewable,
|
||||
loadInlineMedia,
|
||||
visualKind,
|
||||
} from "$lib/api/media";
|
||||
@@ -16,7 +17,7 @@
|
||||
import ContextMenuItem from "$lib/components/ui/ContextMenuItem.svelte";
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import Spinner from "$lib/components/ui/Spinner.svelte";
|
||||
import { mediaKindLabel } from "$lib/format/media";
|
||||
import { formatBytes, mediaKindLabel } from "$lib/format/media";
|
||||
import { poster } from "$lib/media/poster";
|
||||
import { shareUi } from "$lib/stores/shares.svelte";
|
||||
import { toasts } from "$lib/stores/toasts.svelte";
|
||||
@@ -38,8 +39,13 @@
|
||||
let queuing = $state(false);
|
||||
let saving = $state(false);
|
||||
|
||||
const ref = $derived(message.media[0] ?? null);
|
||||
const asFile = $derived(
|
||||
ref !== null && ref.id !== null && !isPreviewable(ref.kind, ref.mime)
|
||||
);
|
||||
|
||||
const ready = $derived(media?.state === "ready" ? media : null);
|
||||
const kind = $derived(ready?.kind ?? "");
|
||||
const kind = $derived(ready?.kind ?? ref?.kind ?? "");
|
||||
const mime = $derived(ready?.mime ?? "");
|
||||
const isImage = $derived(kind === "photo");
|
||||
const isStaticSticker = $derived(
|
||||
@@ -60,7 +66,10 @@
|
||||
const label = $derived(
|
||||
media && media.state !== "missing" ? media.kind : "media"
|
||||
);
|
||||
const storedId = $derived(ready?.mediaId ?? null);
|
||||
const storedId = $derived(
|
||||
ready?.mediaId ?? (asFile ? ref?.id : null) ?? null
|
||||
);
|
||||
const fileName = $derived(ref?.file_name ?? mediaKindLabel(kind) ?? "Файл");
|
||||
|
||||
function delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
@@ -69,6 +78,10 @@
|
||||
}
|
||||
|
||||
async function start() {
|
||||
if (asFile) {
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
media = await loadInlineMedia(message.chat_id, message.message_id);
|
||||
loaded = true;
|
||||
}
|
||||
@@ -116,10 +129,7 @@
|
||||
|
||||
function share() {
|
||||
if (storedId !== null) {
|
||||
shareUi.share(
|
||||
{ kind: "media", mediaId: storedId },
|
||||
mediaKindLabel(kind) ?? "Файл"
|
||||
);
|
||||
shareUi.share({ kind: "media", mediaId: storedId }, fileName);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -132,6 +142,18 @@
|
||||
<Icon name="timer" size="1.25rem" />
|
||||
<span>Самоуничтожающееся медиа</span>
|
||||
</button>
|
||||
{:else if asFile}
|
||||
<button class="media-file" onclick={save} type="button">
|
||||
<span class="file-glyph">
|
||||
<Icon name={saving ? "timer" : "document"} size="1.25rem" />
|
||||
</span>
|
||||
<span class="file-text">
|
||||
<span class="file-name">{fileName}</span>
|
||||
<span class="file-sub">
|
||||
{formatBytes(ref?.file_size ?? null) || mediaKindLabel(kind)}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{:else if !loaded}
|
||||
<div class="media-skeleton"><Spinner /></div>
|
||||
{:else if ready && kind === "voice"}
|
||||
@@ -145,7 +167,7 @@
|
||||
{:else if ready && kind === "video_note"}
|
||||
<VideoNote url={ready.url} transcript={ready.transcript} />
|
||||
{:else if ready && kind === "audio"}
|
||||
<AudioFile url={ready.url} title={ready.mime ?? "Audio"} {own} />
|
||||
<AudioFile url={ready.url} title={fileName} {own} />
|
||||
{:else if ready && isImage}
|
||||
<button class="media-thumb" onclick={onopen} type="button">
|
||||
<img src={ready.url} alt="attachment">
|
||||
@@ -348,6 +370,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
.media-file {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
|
||||
width: 100%;
|
||||
max-width: 18rem;
|
||||
padding: 0.5rem 0.75rem 0.5rem 0.5rem;
|
||||
border: 0;
|
||||
border-radius: var(--border-radius-default-small);
|
||||
|
||||
text-align: start;
|
||||
|
||||
background-color: var(--color-primary-tint);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.media-chip {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user