Browse Source

styling share

Jay V 9 months ago
parent
commit
71bab45065

+ 3 - 0
app/packages/web/astro.config.mjs

@@ -34,6 +34,9 @@ export default defineConfig({
 			markdown: {
 				headingLinks: false,
 			},
+			customCss: [
+				"./src/styles/custom.css",
+			],
 			logo: {
 				light: "./src/assets/logo-light.svg",
 				dark: "./src/assets/logo-dark.svg",

+ 5 - 0
app/packages/web/src/components/Header.astro

@@ -54,4 +54,9 @@ const links = config.social || [];
 		}
 	}
 </style>
+<style is:global>
+body > div.page > header {
+	border-color: var(--sl-color-divider);
+}
+</style>
 

+ 64 - 4
app/packages/web/src/components/Share.tsx

@@ -6,6 +6,7 @@ import {
   onMount,
   onCleanup,
   createMemo,
+  createEffect,
   createSignal,
 } from "solid-js"
 import { DateTime } from "luxon"
@@ -42,6 +43,16 @@ type SessionInfo = {
   }
 }
 
+function getPartTitle(role: string, type: string): string | undefined {
+  return role === "system"
+    ? role
+    : role === "user"
+      ? undefined
+      : type === "text"
+        ? "AI"
+        : type
+}
+
 function getStatusText(status: [Status, string?]): string {
   switch (status[0]) {
     case "connected": return "Connected"
@@ -53,10 +64,47 @@ function getStatusText(status: [Status, string?]): string {
   }
 }
 
-function TextPart(props: { text: string }) {
+function TextPart(props: { text: string, highlight?: boolean }) {
+  const [expanded, setExpanded] = createSignal(false)
+  const [overflowed, setOverflowed] = createSignal(false);
+  let preEl: HTMLPreElement | undefined;
+
+  const checkOverflow = () => {
+    if (preEl) {
+      setOverflowed(preEl.scrollHeight > preEl.clientHeight + 1);
+    }
+  };
+
+  onMount(() => {
+    checkOverflow();
+    window.addEventListener('resize', checkOverflow);
+  });
+
+  createEffect(() => {
+    props.text;
+    setTimeout(checkOverflow, 0);
+  });
+
+  onCleanup(() => {
+    window.removeEventListener('resize', checkOverflow);
+  });
+
   return (
-    <div data-element-message-text>
-      <pre>{props.text}</pre>
+    <div
+      data-element-message-text
+      data-expanded={expanded()}
+      data-highlight={props.highlight}
+    >
+      <pre ref={el => (preEl = el)}>{props.text}</pre>
+      {overflowed() &&
+        <button
+          type="button"
+          data-element-button-text
+          onClick={() => setExpanded(e => !e)}
+        >
+          {expanded() ? "Show less" : "Show more"}
+        </button>
+      }
     </div>
   )
 }
@@ -270,7 +318,19 @@ export default function Share(props: { api: string }) {
                         <div></div>
                       </div>
                       <div data-section="content">
-                        <TextPart text={JSON.stringify(part, null, 2)} />
+                        {getPartTitle(msg.role, part.type)
+                          ? <span data-element-label>
+                            {getPartTitle(msg.role, part.type)}
+                          </span>
+                          : null
+                        }
+                        {part.type === "text"
+                          ? <TextPart
+                            text={part.text}
+                            highlight={msg.role === "user"}
+                          />
+                          : <TextPart text={JSON.stringify(part, null, 2)} />
+                        }
                         {renderTime(
                           msg.metadata?.time.completed
                           || msg.metadata?.time.created

+ 64 - 8
app/packages/web/src/components/share.module.css

@@ -6,6 +6,19 @@
   line-height: 1;
 }
 
+[data-element-button-text] {
+  cursor: pointer;
+  appearance: none;
+  background-color: transparent;
+  border: none;
+  padding: 0;
+  color: var(--sl-color-text-secondary);
+
+  &:hover {
+    color: var(--sl-color-text);
+  }
+}
+
 [data-element-label] {
   text-transform: uppercase;
   letter-spacing: 0.05em;
@@ -39,11 +52,11 @@
     font-size: 0.75rem;
 
     span:first-child {
-      color: var(--sl-color-gray-5);
+      color: var(--sl-color-divider);
 
       &[data-status="connected"] { color: var(--sl-color-green); }
       &[data-status="connecting"] { color: var(--sl-color-orange); }
-      &[data-status="disconnected"] { color: var(--sl-color-gray-5); }
+      &[data-status="disconnected"] { color: var(--sl-color-divider); }
       &[data-status="reconnecting"] { color: var(--sl-color-orange); }
       &[data-status="error"] { color: var(--sl-color-red); }
     }
@@ -118,12 +131,15 @@
   }
 
   [data-section="content"] {
-    flex: 1 1 auto;
-    padding: 0.125rem 0 0.375rem;
+    padding: 3px 0 0.375rem;
     display: flex;
     flex-direction: column;
     gap: 0.5rem;
 
+    span:first-child {
+      font-size: 0.75rem;
+    }
+
     span:last-child {
       font-size: 0.75rem;
       color: var(--sl-color-text-dimmed);
@@ -132,13 +148,53 @@
 }
 
 [data-element-message-text] {
+  background-color: var(--sl-color-bg-surface);
+  padding: 0.5rem calc(0.5rem + 3px);
+  border-radius: 0.25rem;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  color: var(--sl-color-text);
+  gap: 1rem;
+
   pre {
+    line-height: 1.5;
     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;
   }
+
+  button {
+    flex: 0 0 auto;
+    padding: 2px 0;
+    font-size: 0.75rem;
+  }
+
+  &[data-highlight="true"] {
+    background-color: var(--sl-color-blue-high);
+    color: var(--sl-color-text-invert);
+
+    button {
+      opacity: 0.85;
+      color: var(--sl-color-text-invert);
+
+      &:hover {
+        opacity: 1;
+      }
+    }
+  }
+
+  &[data-expanded="true"] {
+    pre {
+      display: block;
+    }
+  }
+  &[data-expanded="false"] {
+    pre {
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+      -webkit-line-clamp: 3;
+      overflow: hidden;
+    }
+  }
 }

+ 4 - 0
app/packages/web/src/styles/custom.css

@@ -0,0 +1,4 @@
+:root {
+  --sl-color-bg-surface: var(--sl-color-bg-nav);
+  --sl-color-divider: var(--sl-color-gray-5);
+}