1<script lang="ts">
 2	import hljs from 'highlight.js';
 3	import { browser } from '$app/environment';
 4	import { mode } from 'mode-watcher';
 5
 6	import githubDarkCss from 'highlight.js/styles/github-dark.css?inline';
 7	import githubLightCss from 'highlight.js/styles/github.css?inline';
 8
 9	interface Props {
10		code: string;
11		language?: string;
12		class?: string;
13		maxHeight?: string;
14		maxWidth?: string;
15	}
16
17	let {
18		code,
19		language = 'text',
20		class: className = '',
21		maxHeight = '60vh',
22		maxWidth = ''
23	}: Props = $props();
24
25	let highlightedHtml = $state('');
26
27	function loadHighlightTheme(isDark: boolean) {
28		if (!browser) return;
29
30		const existingThemes = document.querySelectorAll('style[data-highlight-theme-preview]');
31		existingThemes.forEach((style) => style.remove());
32
33		const style = document.createElement('style');
34		style.setAttribute('data-highlight-theme-preview', 'true');
35		style.textContent = isDark ? githubDarkCss : githubLightCss;
36
37		document.head.appendChild(style);
38	}
39
40	$effect(() => {
41		const currentMode = mode.current;
42		const isDark = currentMode === 'dark';
43
44		loadHighlightTheme(isDark);
45	});
46
47	$effect(() => {
48		if (!code) {
49			highlightedHtml = '';
50			return;
51		}
52
53		try {
54			// Check if the language is supported
55			const lang = language.toLowerCase();
56			const isSupported = hljs.getLanguage(lang);
57
58			if (isSupported) {
59				const result = hljs.highlight(code, { language: lang });
60				highlightedHtml = result.value;
61			} else {
62				// Try auto-detection or fallback to plain text
63				const result = hljs.highlightAuto(code);
64				highlightedHtml = result.value;
65			}
66		} catch {
67			// Fallback to escaped plain text
68			highlightedHtml = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
69		}
70	});
71</script>
72
73<div
74	class="code-preview-wrapper overflow-auto rounded-lg border border-border bg-muted {className}"
75	style="max-height: {maxHeight}; max-width: {maxWidth};"
76>
77	<!-- Needs to be formatted as single line for proper rendering -->
78	<pre class="m-0 overflow-x-auto p-4"><code class="hljs text-sm leading-relaxed"
79			>{@html highlightedHtml}</code
80		></pre>
81</div>
82
83<style>
84	.code-preview-wrapper {
85		font-family:
86			ui-monospace, SFMono-Regular, 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas,
87			'Liberation Mono', Menlo, monospace;
88	}
89
90	.code-preview-wrapper pre {
91		background: transparent;
92	}
93
94	.code-preview-wrapper code {
95		background: transparent;
96	}
97</style>