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.
svelte-kit-vice/src/uix/air/components/code-block/code-block.svelte

75 lines
1.9 KiB

<script lang="ts">
import { browser } from '$app/environment';
import './code-block.css';
import type { CodeBlockProps } from './types';
let {
language,
filename,
copyable = true,
size = 3,
style,
children,
...restProps
}: CodeBlockProps = $props();
let codeRef = $state<HTMLElement | undefined>();
let copied = $state(false);
let copyTimeout: ReturnType<typeof setTimeout>;
const showHeader = $derived(!!filename || !!language || copyable);
const sizeTokens = $derived(
`--_air-code-block-size:var(--air-text-${size}-size);` +
`--_air-code-block-lh:var(--air-text-${size}-lh);` +
`--_air-code-block-ls:var(--air-text-${size}-ls)`
);
const mergedStyle = $derived(style ? `${sizeTokens};${style}` : sizeTokens);
async function handleCopy() {
if (!browser || !codeRef) return;
const text = codeRef.textContent ?? '';
try {
await navigator.clipboard.writeText(text);
copied = true;
clearTimeout(copyTimeout);
copyTimeout = setTimeout(() => {
copied = false;
}, 2000);
} catch {
// Clipboard no disponible — silencioso
}
}
</script>
<div class="air-code-block" style={mergedStyle} {...restProps}>
{#if showHeader}
<div class="air-code-block-header">
{#if filename}
<span class="air-code-block-filename">{filename}</span>
{/if}
{#if language && !filename}
<span class="air-code-block-lang">{language}</span>
{/if}
{#if language && filename}
<span class="air-code-block-lang">{language}</span>
{/if}
{#if copyable}
<button
type="button"
class="air-code-block-copy"
data-copied={copied ? '' : undefined}
onclick={handleCopy}
aria-label={copied ? 'Copied' : 'Copy code'}
>
{copied ? '✓ Copied' : 'Copy'}
</button>
{/if}
</div>
{/if}
<pre class="air-code-block-pre"><code class="air-code-block-code" bind:this={codeRef}>{@render children?.()}</code></pre>
</div>

Powered by TurnKey Linux.