Skip to content

Commit 60c1276

Browse files
feat(details): render video players in comments and body
1 parent 712adde commit 60c1276

File tree

2 files changed

+109
-1
lines changed

2 files changed

+109
-1
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script lang="ts">
2+
import type { HTMLAnchorAttributes } from "svelte/elements";
3+
import { dev } from "$app/environment";
4+
5+
type Props = {
6+
attributes: HTMLAnchorAttributes;
7+
};
8+
9+
let { attributes }: Props = $props();
10+
let { children, ...rest } = $derived(attributes);
11+
let { href } = $derived(rest);
12+
13+
// source: https://en.wikipedia.org/wiki/HTML_video#Browser_support
14+
const videoExtensions = [
15+
"ogg",
16+
"ogv",
17+
"oga",
18+
"ogx",
19+
"ogm",
20+
"spx",
21+
"mp4",
22+
"m4a",
23+
"m4p",
24+
"m4b",
25+
"m4r",
26+
"m4v",
27+
"webm"
28+
];
29+
// source: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#supported_image_formats
30+
const imageExtensions = [
31+
"apng",
32+
"png",
33+
"avif",
34+
"gif",
35+
"jpg",
36+
"jpeg",
37+
"jpe",
38+
"jif",
39+
"jfif",
40+
"svg",
41+
"webp"
42+
];
43+
</script>
44+
45+
<!-- Renders -->
46+
{#snippet link()}
47+
<a {...rest}>
48+
{@render children?.()}
49+
</a>
50+
{/snippet}
51+
52+
{#snippet image(alt?: string)}
53+
<img src={href} alt={alt ?? href?.split("/").pop()} />
54+
{/snippet}
55+
56+
{#snippet video()}
57+
<video src={href} controls>
58+
<track kind="captions" />
59+
</video>
60+
{/snippet}
61+
62+
<!-- Main logic -->
63+
{#if href}
64+
{@const hasExtension = /\.[a-zA-Z\d]+$/.test(href)}
65+
{#if hasExtension}
66+
{@const filename = href.split("/").pop()}
67+
{@const extension = filename?.split(".").pop() ?? ""}
68+
{#if videoExtensions.includes(extension)}
69+
{@render video()}
70+
{:else if imageExtensions.includes(extension)}
71+
{@render image(filename)}
72+
{:else}
73+
{@render link()}
74+
{/if}
75+
{:else if href.startsWith("https://github.com/user-attachments/assets/")}
76+
<!-- special case for faster responses for known GH URLs -->
77+
{@render video()}
78+
{:else if new URL(href).pathname === "/"}
79+
<!-- we'll assume nothing else than a link can come from a URL without pathname -->
80+
{@render link()}
81+
{:else if !dev}
82+
<!-- fetching the URL's content type (only in prod because CORS) -->
83+
{#await fetch(href, { method: "HEAD" }) then response}
84+
{@const contentType = response.headers.get("Content-Type")}
85+
{#if contentType?.startsWith("video/")}
86+
{@render video()}
87+
{:else if contentType?.startsWith("image/")}
88+
{@render image()}
89+
{:else}
90+
{@render link()}
91+
{/if}
92+
{:catch}
93+
{@render link()}
94+
{/await}
95+
{:else}
96+
{@render link()}
97+
{/if}
98+
{:else}
99+
{@render link()}
100+
{/if}

src/routes/[pid=pid]/[org]/[repo]/[id=number]/PageRenderer.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import Reactions from "$lib/components/Reactions.svelte";
7272
import Step from "$lib/components/Step.svelte";
7373
import Steps from "$lib/components/Steps.svelte";
74+
import LinkRenderer from "$lib/components/renderers/LinkRenderer.svelte";
7475
import BottomCollapsible from "./BottomCollapsible.svelte";
7576
import {
7677
transformerDiffMarking,
@@ -435,6 +436,9 @@
435436
{#snippet h6(props)}
436437
{@render headingRenderer("h6", props)}
437438
{/snippet}
439+
{#snippet a(props)}
440+
<LinkRenderer attributes={props} />
441+
{/snippet}
438442
</MarkdownRenderer>
439443
{#if "reactions" in info}
440444
<Reactions reactions={info.reactions} reactionItemUrl={info.html_url} class="mt-4" />
@@ -532,7 +536,11 @@
532536
{ remarkPlugin: remarkGemoji },
533537
shikiPlugin
534538
]}
535-
/>
539+
>
540+
{#snippet a(props)}
541+
<LinkRenderer attributes={props} />
542+
{/snippet}
543+
</MarkdownRenderer>
536544
<Reactions
537545
reactions={comment.reactions}
538546
reactionItemUrl={comment.html_url}

0 commit comments

Comments
 (0)