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, '&').replace(/</g, '<').replace(/>/g, '>');
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>