styling share

This commit is contained in:
Jay V
2025-05-27 20:38:23 -04:00
parent b9f009c529
commit 37082b2176
5 changed files with 6312 additions and 53 deletions

View File

@@ -1,4 +1,15 @@
import { createSignal, onCleanup, onMount, Show, For, createMemo } from "solid-js"
import {
For,
Show,
Match,
Switch,
onMount,
onCleanup,
createMemo,
createSignal,
} from "solid-js"
import { DateTime } from "luxon"
import { IconCpuChip, IconSparkles, IconUserCircle, IconWrenchScrewdriver } from "./icons"
import styles from "./share.module.css"
import { type UIMessage } from "ai"
import { createStore, reconcile } from "solid-js/store"
@@ -8,17 +19,17 @@ type Status = "disconnected" | "connecting" | "connected" | "error" | "reconnect
type SessionMessage = UIMessage<{
time: {
created: number;
completed?: number;
};
sessionID: string;
created: number
completed?: number
}
sessionID: string
tool: Record<string, {
properties: Record<string, any>;
properties: Record<string, any>
time: {
start: number;
end: number;
};
}>;
start: number
end: number
}
}>
}>
type SessionInfo = {
@@ -41,6 +52,14 @@ function getStatusText(status: [Status, string?]): string {
}
}
function TextPart(props: { text: string }) {
return (
<div data-element-message-text>
<pre>{props.text}</pre>
</div>
)
}
export default function Share(props: { api: string }) {
let params = new URLSearchParams(document.location.search)
const sessionId = params.get("id")
@@ -151,6 +170,16 @@ export default function Share(props: { api: string }) {
})
})
function renderTime(time: number) {
return (
<span title={
DateTime.fromMillis(time).toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS)
}>
{DateTime.fromMillis(time).toLocaleString(DateTime.TIME_WITH_SECONDS)}
</span>
)
}
return (
<main class={`${styles.root} not-content`}>
<div class={styles.header}>
@@ -158,13 +187,13 @@ export default function Share(props: { api: string }) {
<h1>{store.info?.title}</h1>
<p>
<span data-status={connectionStatus()[0]}>&#9679;</span>
<span>{getStatusText(connectionStatus())}</span>
<span data-element-label>{getStatusText(connectionStatus())}</span>
</p>
</div>
<div data-section="row">
<ul class={styles.stats}>
<ul data-section="stats">
<li>
<span>Input Tokens</span>
<span data-element-label>Input Tokens</span>
{store.info?.tokens?.input ?
<span>{store.info?.tokens?.input}</span>
:
@@ -172,7 +201,7 @@ export default function Share(props: { api: string }) {
}
</li>
<li>
<span>Output Tokens</span>
<span data-element-label>Output Tokens</span>
{store.info?.tokens?.output ?
<span>{store.info?.tokens?.output}</span>
:
@@ -180,7 +209,7 @@ export default function Share(props: { api: string }) {
}
</li>
<li>
<span>Reasoning Tokens</span>
<span data-element-label>Reasoning Tokens</span>
{store.info?.tokens?.reasoning ?
<span>{store.info?.tokens?.reasoning}</span>
:
@@ -188,12 +217,74 @@ export default function Share(props: { api: string }) {
}
</li>
</ul>
<div class={styles.context}>
<button>View Context &gt;</button>
<div data-section="date">
{messages().length > 0 && messages()[0].metadata?.time.created ?
<span title={
DateTime.fromMillis(
messages()[0].metadata?.time.created || 0
).toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS)
}>
{DateTime.fromMillis(
messages()[0].metadata?.time.created || 0
).toLocaleString(DateTime.DATE_MED)}
</span>
:
<span data-element-label data-placeholder>Started at &mdash;</span>
}
</div>
</div>
</div>
<div>
<Show
when={messages().length > 0}
fallback={<p>Waiting for messages...</p>}
>
<div class={styles.parts}>
<For each={messages()}>
{(msg) => (
<For each={msg.parts}>
{(part) => (
<div
data-section="part"
data-message-role={msg.role}
data-part-type={part.type}
>
<div data-section="decoration">
<div>
<Switch fallback={
<IconWrenchScrewdriver width={16} height={16} />
}>
<Match when={msg.role === "assistant" && (part.type === "text" || part.type === "step-start")}>
<IconSparkles width={18} height={18} />
</Match>
<Match when={msg.role === "system"}>
<IconCpuChip width={18} height={18} />
</Match>
<Match when={msg.role === "user"}>
<IconUserCircle width={18} height={18} />
</Match>
</Switch>
</div>
<div></div>
</div>
<div data-section="content">
<TextPart text={JSON.stringify(part, null, 2)} />
{renderTime(
msg.metadata?.time.completed
|| msg.metadata?.time.created
|| 0
)}
</div>
</div>
)}
</For>
)}
</For>
</div>
</Show>
</div>
<div style={{ margin: "2rem 0" }}>
<div
style={{

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,17 @@
.root {
padding-top: 0.5rem;
display: flex;
flex-direction: column;
gap: 2.5rem;
line-height: 1;
}
[data-element-label] {
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--sl-color-text-dimmed);
}
.header {
display: flex;
flex-direction: column;
@@ -37,33 +47,34 @@
&[data-status="reconnecting"] { color: var(--sl-color-orange); }
&[data-status="error"] { color: var(--sl-color-red); }
}
span:last-child {
color: var(--sl-color-text-dimmed);
text-transform: uppercase;
letter-spacing: 0.05em;
}
[data-section="stats"] {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
gap: 1rem;
li {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
span:last-child {
&[data-placeholder] {
color: var(--sl-color-text-dimmed);
}
}
}
}
}
.stats {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
gap: 1rem;
[data-section="date"] {
span {
font-size: 0.875rem;
color: var(--sl-color-text);
li {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
span:first-child {
color: var(--sl-color-text-dimmed);
text-transform: uppercase;
letter-spacing: 0.05em;
}
span:last-child {
&[data-placeholder] {
color: var(--sl-color-text-dimmed);
}
@@ -71,19 +82,63 @@
}
}
.context {
button {
appearance: none;
background: none;
border: none;
padding: 0;
margin: 0;
font-size: 0.875rem;
color: var(--sl-color-text-dimmed);
cursor: pointer;
.parts {
display: flex;
flex-direction: column;
gap: 0.625rem;
&:hover {
color: var(--sl-color-primary);
[data-section="part"] {
display: flex;
gap: 0.5rem;
}
[data-section="decoration"] {
flex: 0 0 auto;
display: flex;
flex-direction: column;
gap: 0.625rem;
align-items: center;
justify-content: flex-start;
div:first-child {
flex: 0 0 auto;
width: 18px;
svg {
color: var(--sl-color-text-secondary);
display: block;
}
}
div:last-child {
width: 3px;
height: 100%;
border-radius: 1px;
background-color: var(--sl-color-hairline);
}
}
[data-section="content"] {
flex: 1 1 auto;
padding: 0.125rem 0 0.375rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
span:last-child {
font-size: 0.75rem;
color: var(--sl-color-text-dimmed);
}
}
}
[data-element-message-text] {
pre {
font-size: 0.875rem;
color: var(--sl-color-text);
background-color: var(--sl-color-bg-nav);
padding: 0.5rem;
border-radius: 0.5rem;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
}