Download tools/ui/src/lib/components/app/content/SyntaxHighlightedCode.svelte from Parakon/parakon-runtime: direct link, hf CLI and curl.
- Browser
- Download file 4.11 kB
-
https://huggingface.co/Parakon/parakon-runtime/resolve/main/tools/ui/src/lib/components/app/content/SyntaxHighlightedCode.svelte
- Command line
-
hf download hf://Parakon/parakon-runtime/tools/ui/src/lib/components/app/content/SyntaxHighlightedCode.svelte
-
curl -L -o SyntaxHighlightedCode.svelte https://huggingface.co/Parakon/parakon-runtime/resolve/main/tools/ui/src/lib/components/app/content/SyntaxHighlightedCode.svelte
4.11 kB
| <script lang="ts"> | |
| import { browser } from '$app/environment'; | |
| import { SYNTAX_CODE_SCROLL_AT_BOTTOM_THRESHOLD_PX, UI_DATA_ATTRS } from '$lib/constants'; | |
| import { BooleanString, ColorMode } from '$lib/enums'; | |
| import { highlightCode } from '$lib/utils'; | |
| import githubLightCss from 'highlight.js/styles/github.css?inline'; | |
| import githubDarkCss from 'highlight.js/styles/github-dark.css?inline'; | |
| import { mode } from 'mode-watcher'; | |
| interface Props { | |
| code: string; | |
| language?: string; | |
| class?: string; | |
| maxHeight?: string; | |
| maxWidth?: string; | |
| /** Auto-scrolls to the bottom of new chunks; pauses on user scroll-up | |
| * until the user returns to the bottom. */ | |
| streaming?: boolean; | |
| } | |
| let { | |
| class: className = '', | |
| code, | |
| language = 'text', | |
| maxHeight = '60vh', | |
| maxWidth = '', | |
| streaming = false | |
| }: Props = $props(); | |
| const highlightedHtml = $derived(highlightCode(code, language)); | |
| let scrollEl = $state<HTMLDivElement>(); | |
| let userScrolledUp = $state(false); | |
| let lastScrollTop = 0; | |
| const SCROLL_BOTTOM_THRESHOLD_PX = SYNTAX_CODE_SCROLL_AT_BOTTOM_THRESHOLD_PX; | |
| let pendingFrame: number | null = null; | |
| function loadHighlightTheme(isDark: boolean) { | |
| if (!browser) return; | |
| const existingThemes = document.querySelectorAll( | |
| `style[${UI_DATA_ATTRS.HIGHLIGHT_THEME_PREVIEW}]` | |
| ); | |
| existingThemes.forEach((style) => style.remove()); | |
| const style = document.createElement('style'); | |
| style.setAttribute(UI_DATA_ATTRS.HIGHLIGHT_THEME_PREVIEW, BooleanString.TRUE); | |
| style.textContent = isDark ? githubDarkCss : githubLightCss; | |
| document.head.appendChild(style); | |
| } | |
| function isAtBottom(): boolean { | |
| if (!scrollEl) return false; | |
| return ( | |
| scrollEl.scrollHeight - scrollEl.clientHeight - scrollEl.scrollTop <= | |
| SCROLL_BOTTOM_THRESHOLD_PX | |
| ); | |
| } | |
| function scrollToBottomOnFrame() { | |
| if (pendingFrame !== null || !scrollEl || userScrolledUp) return; | |
| pendingFrame = requestAnimationFrame(() => { | |
| pendingFrame = null; | |
| // User may scroll between scheduling and paint. | |
| if (scrollEl && !userScrolledUp) { | |
| scrollEl.scrollTop = scrollEl.scrollHeight; | |
| } | |
| }); | |
| } | |
| function handleScrollEvent() { | |
| if (!scrollEl) return; | |
| const isScrollingUp = scrollEl.scrollTop < lastScrollTop; | |
| if (isScrollingUp && !isAtBottom()) { | |
| userScrolledUp = true; | |
| } else if (isAtBottom()) { | |
| userScrolledUp = false; | |
| } | |
| lastScrollTop = scrollEl.scrollTop; | |
| } | |
| $effect(() => { | |
| const currentMode = mode.current; | |
| const isDark = currentMode === ColorMode.DARK; | |
| loadHighlightTheme(isDark); | |
| }); | |
| // Pin to bottom at the start of each streaming episode. | |
| $effect(() => { | |
| if (streaming) { | |
| userScrolledUp = false; | |
| lastScrollTop = 0; | |
| } | |
| }); | |
| $effect(() => { | |
| void code; | |
| if (!streaming || userScrolledUp) return; | |
| scrollToBottomOnFrame(); | |
| }); | |
| // Layout shifts that don't change `code` (highlight.js re-tokenize, line-wrap reflow). | |
| $effect(() => { | |
| if (!streaming || !scrollEl) return; | |
| const observer = new MutationObserver(() => scrollToBottomOnFrame()); | |
| observer.observe(scrollEl, { | |
| characterData: true, | |
| childList: true, | |
| subtree: true | |
| }); | |
| return () => observer.disconnect(); | |
| }); | |
| </script> | |
| <div | |
| bind:this={scrollEl} | |
| class="code-preview-wrapper min-w-0 max-w-full overflow-auto rounded-xl border shadow-[0_1px_2px_0_rgb(0_0_0_/_0.05)] {className}" | |
| onscroll={handleScrollEvent} | |
| style="border-color: color-mix(in oklch, var(--border) 30%, transparent); background: var(--code-background); max-height: {maxHeight}; {maxWidth | |
| ? `max-width: ${maxWidth};` | |
| : ''}" | |
| > | |
| <!-- Single line: hljs injection depends on a contiguous source string. --> | |
| <pre class="m-0"><code class="hljs text-sm leading-relaxed">{@html highlightedHtml}</code></pre> | |
| </div> | |
| <style> | |
| .code-preview-wrapper { | |
| overscroll-behavior: contain; | |
| } | |
| .code-preview-wrapper pre { | |
| background: transparent; | |
| padding: 0; | |
| } | |
| .code-preview-wrapper code { | |
| background: transparent; | |
| display: block; | |
| padding: 0.5rem; | |
| } | |
| :global(.dark) .code-preview-wrapper { | |
| border-color: color-mix(in oklch, var(--border) 20%, transparent); | |
| } | |
| </style> | |