docs: share handle slow loading pages

This commit is contained in:
Jay V 2025-07-03 13:15:18 -04:00
parent 5a0910ea79
commit 3e2a0c7281
2 changed files with 959 additions and 991 deletions

View file

@ -1,8 +1,6 @@
import { import {
type JSX, type JSX,
onCleanup,
splitProps, splitProps,
createEffect,
createResource, createResource,
} from "solid-js" } from "solid-js"
import { codeToHtml } from "shiki" import { codeToHtml } from "shiki"
@ -12,15 +10,15 @@ import { transformerNotationDiff } from "@shikijs/transformers"
interface CodeBlockProps extends JSX.HTMLAttributes<HTMLDivElement> { interface CodeBlockProps extends JSX.HTMLAttributes<HTMLDivElement> {
code: string code: string
lang?: string lang?: string
onRendered?: () => void
} }
function CodeBlock(props: CodeBlockProps) { function CodeBlock(props: CodeBlockProps) {
const [local, rest] = splitProps(props, ["code", "lang", "onRendered"]) const [local, rest] = splitProps(props, ["code", "lang"])
let containerRef!: HTMLDivElement
const [html] = createResource( const [html] = createResource(
() => [local.code, local.lang], () => [local.code, local.lang],
async ([code, lang]) => { async ([code, lang]) => {
// TODO: For testing delays
// await new Promise((resolve) => setTimeout(resolve, 3000))
return (await codeToHtml(code || "", { return (await codeToHtml(code || "", {
lang: lang || "text", lang: lang || "text",
themes: { themes: {
@ -32,25 +30,7 @@ function CodeBlock(props: CodeBlockProps) {
}, },
) )
onCleanup(() => { return <div innerHTML={html()} class={styles.codeblock} {...rest}></div >
if (containerRef) containerRef.innerHTML = ""
})
createEffect(() => {
if (html() && containerRef) {
containerRef.innerHTML = html() as string
local.onRendered?.()
}
})
return (
<>
{html() ? (
<div ref={containerRef} class={styles.codeblock} {...rest}></div>
) : null}
</>
)
} }
export default CodeBlock export default CodeBlock

View file

@ -5,11 +5,13 @@ import {
Match, Match,
Switch, Switch,
onMount, onMount,
Suspense,
onCleanup, onCleanup,
splitProps, splitProps,
createMemo, createMemo,
createEffect, createEffect,
createSignal, createSignal,
SuspenseList,
} from "solid-js" } from "solid-js"
import map from "lang-map" import map from "lang-map"
import { DateTime } from "luxon" import { DateTime } from "luxon"
@ -22,7 +24,6 @@ import {
IconAnthropic, IconAnthropic,
} from "./icons/custom" } from "./icons/custom"
import { import {
IconFolder,
IconHashtag, IconHashtag,
IconSparkles, IconSparkles,
IconGlobeAlt, IconGlobeAlt,
@ -486,6 +487,7 @@ function TerminalPart(props: TerminalPartProps) {
} }
onMount(() => { onMount(() => {
checkOverflow()
window.addEventListener("resize", checkOverflow) window.addEventListener("resize", checkOverflow)
}) })
@ -510,7 +512,6 @@ function TerminalPart(props: TerminalPartProps) {
<CodeBlock <CodeBlock
data-section="error" data-section="error"
lang="text" lang="text"
onRendered={checkOverflow}
ref={(el) => (preEl = el)} ref={(el) => (preEl = el)}
code={local.error || ""} code={local.error || ""}
/> />
@ -518,7 +519,6 @@ function TerminalPart(props: TerminalPartProps) {
<Match when={local.result}> <Match when={local.result}>
<CodeBlock <CodeBlock
lang="console" lang="console"
onRendered={checkOverflow}
ref={(el) => (preEl = el)} ref={(el) => (preEl = el)}
code={local.result || ""} code={local.result || ""}
/> />
@ -596,7 +596,6 @@ export default function Share(props: {
messages: Record<string, Message.Info> messages: Record<string, Message.Info>
}) { }) {
let lastScrollY = 0 let lastScrollY = 0
let hasScrolled = false
let scrollTimeout: number | undefined let scrollTimeout: number | undefined
const id = props.id const id = props.id
@ -606,12 +605,6 @@ export default function Share(props: {
const [showScrollButton, setShowScrollButton] = createSignal(false) const [showScrollButton, setShowScrollButton] = createSignal(false)
const [isButtonHovered, setIsButtonHovered] = createSignal(false) const [isButtonHovered, setIsButtonHovered] = createSignal(false)
const anchorId = createMemo<string | null>(() => {
const raw = window.location.hash.slice(1)
const [id] = raw.split("-")
return id
})
const [store, setStore] = createStore<{ const [store, setStore] = createStore<{
info?: Session.Info info?: Session.Info
messages: Record<string, Message.Info> messages: Record<string, Message.Info>
@ -677,11 +670,6 @@ export default function Share(props: {
if (type === "message") { if (type === "message") {
const [, messageID] = splits const [, messageID] = splits
setStore("messages", messageID, reconcile(d.content)) setStore("messages", messageID, reconcile(d.content))
if (!hasScrolled && messageID === anchorId()) {
scrollToAnchor(window.location.hash.slice(1))
hasScrolled = true
}
} }
} catch (error) { } catch (error) {
console.error("Error parsing WebSocket message:", error) console.error("Error parsing WebSocket message:", error)
@ -789,20 +777,8 @@ export default function Share(props: {
for (let i = 0; i < messages().length; i++) { for (let i = 0; i < messages().length; i++) {
const msg = messages()[i] const msg = messages()[i]
// TODO: Cleanup
// const system = result.messages.length === 0 && msg.role === "system"
const assistant = msg.metadata?.assistant const assistant = msg.metadata?.assistant
// if (system) {
// for (const part of msg.parts) {
// if (part.type === "text") {
// result.system.push(part.text)
// }
// }
// result.created = msg.metadata?.time.created
// continue
// }
result.messages.push(msg) result.messages.push(msg)
if (assistant) { if (assistant) {
@ -889,8 +865,10 @@ export default function Share(props: {
fallback={<p>Waiting for messages...</p>} fallback={<p>Waiting for messages...</p>}
> >
<div class={styles.parts}> <div class={styles.parts}>
<SuspenseList>
<For each={data().messages}> <For each={data().messages}>
{(msg, msgIndex) => ( {(msg, msgIndex) => (
<Suspense>
<For each={msg.parts}> <For each={msg.parts}>
{(part, partIndex) => { {(part, partIndex) => {
if ( if (
@ -930,6 +908,14 @@ export default function Share(props: {
return { metadata, args, result, duration } return { metadata, args, result, duration }
}) })
onMount(() => {
const hash = window.location.hash.slice(1)
if (hash !== "" && hash === anchor()) {
scrollToAnchor(hash)
}
})
return ( return (
<Switch> <Switch>
{/* User text */} {/* User text */}
@ -1875,8 +1861,10 @@ export default function Share(props: {
) )
}} }}
</For> </For>
</Suspense>
)} )}
</For> </For>
</SuspenseList>
<div data-section="part" data-part-type="summary"> <div data-section="part" data-part-type="summary">
<div data-section="decoration"> <div data-section="decoration">
<span data-status={connectionStatus()[0]}></span> <span data-status={connectionStatus()[0]}></span>