You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

100 lines
2.5 KiB

<script>
import { createEventDispatcher, onMount } from "svelte";
import Spinner from "./Spinner.svelte";
import CodeFormatter from "./CodeFormatter.svelte";
const dispatch = createEventDispatcher();
export let content = "";
export let src="";
export let original = "";
// as usual there are timing issues so give some default values
let slot_content = {textContent: "Loading..."};
let code = "";
let copied = false;
export let language="generic";
let timer;
let code_promise;
const load_code = async () => {
if(src) {
// load from url
let res = await fetch(src);
let content = res.status == 200 ? await res.text() : `Error getting ${src}: ${res.status}`;
original = content;
} else if(content) {
// it's in a variable
original = content;
} else {
// must be in the slot
original = slot_content.textContent;
}
// we keep the original content for the copy/past functionality
code = original.trim();
}
const copy_code = () => {
navigator.clipboard.writeText(original).then(() => {
if(timer) clearTimeout(timer);
copied = true;
timer = setTimeout(() => copied = false, 200);
dispatch("copy");
}, () => {
copied = false;
});
}
// A common Svelte footgun is that updating the variables to a component do not cause it to update. They have "reasons" but I feel all of their reasons are wrong.
$: if(content !== code) code_promise = load_code();
onMount(() => {
code_promise = load_code();
});
</script>
<style>
/* NOTE: .line-numbers is really only used to make the Prism
line-numbers plugin run. The CSS doesn't use that class and
instead just add line numbers to every code block inside a pre.
*/
#slot-content {
display: none;
}
pre:hover {
cursor: copy;
}
@keyframes flash {
0% { opacity: 0.5; }
100% { opacity: 1; }
}
pre.copied {
animation: flash 0.2s;
}
</style>
{#if content}
{#await code_promise}
<Spinner />
{:then}
<pre on:click={ copy_code } class:copied>
<code data-language={ language } class="line-numbers language-{ language }">{code}</code>
</pre>
<CodeFormatter />
{/await}
{:else}
<span id="slot-content" bind:this={slot_content}><slot /></span>
{#await code_promise}
<Spinner />
{:then}
<pre on:click={ copy_code } class:copied>
<code data-language={ language } class="line-numbers language-{ language }">
{code}
</code>
</pre>
<CodeFormatter />
{/await}
{/if}