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
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}
|
|
|