Jay V 9 miesięcy temu
rodzic
commit
e1c897c1ae

+ 68 - 40
app/packages/web/src/components/Share.tsx

@@ -2,6 +2,8 @@ import { createSignal, onCleanup, onMount, Show, For } from "solid-js"
 import styles from "./share.module.css"
 import { type UIMessage } from "ai"
 
+type Status = "disconnected" | "connecting" | "connected" | "error" | "reconnecting"
+
 type Message = {
   key: string
   content: string
@@ -15,11 +17,22 @@ type SessionInfo = {
   }
 }
 
+function getStatusText(status: [Status, string?]): string {
+  switch (status[0]) {
+    case "connected": return "Connected"
+    case "connecting": return "Connecting..."
+    case "disconnected": return "Disconnected"
+    case "reconnecting": return "Reconnecting..."
+    case "error": return status[1] || "Error"
+    default: return "Unknown"
+  }
+}
+
 export default function Share(props: { api: string }) {
   let params = new URLSearchParams(document.location.search)
   const sessionId = params.get("id")
 
-  const [connectionStatus, setConnectionStatus] = createSignal("Disconnected")
+  const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"])
   const [sessionInfo, setSessionInfo] = createSignal<SessionInfo | null>(null)
   const [systemMessage, setSystemMessage] = createSignal<Message | null>(null)
   const [messages, setMessages] = createSignal<Message[]>([])
@@ -33,13 +46,13 @@ export default function Share(props: { api: string }) {
 
     if (!sessionId) {
       console.error("Session ID not found in environment variables")
-      setConnectionStatus("Error: Session ID not found")
+      setConnectionStatus(["error", "Session ID not found"])
       return
     }
 
     if (!apiUrl) {
       console.error("API URL not found in environment variables")
-      setConnectionStatus("Error: API URL not found")
+      setConnectionStatus(["error", "API URL not found"])
       return
     }
 
@@ -53,7 +66,7 @@ export default function Share(props: { api: string }) {
         socket.close()
       }
 
-      setConnectionStatus("Connecting...")
+      setConnectionStatus(["connecting"])
 
       // Always use secure WebSocket protocol (wss)
       const wsBaseUrl = apiUrl.replace(/^https?:\/\//, "wss://")
@@ -65,7 +78,7 @@ export default function Share(props: { api: string }) {
 
       // Handle connection opening
       socket.onopen = () => {
-        setConnectionStatus("Connected")
+        setConnectionStatus(["connected"])
         console.log("WebSocket connection established")
       }
 
@@ -113,13 +126,13 @@ export default function Share(props: { api: string }) {
       // Handle errors
       socket.onerror = (error) => {
         console.error("WebSocket error:", error)
-        setConnectionStatus("Error: Connection failed")
+        setConnectionStatus(["error", "Connection failed"])
       }
 
       // Handle connection close and reconnection
       socket.onclose = (event) => {
         console.log(`WebSocket closed: ${event.code} ${event.reason}`)
-        setConnectionStatus("Disconnected, reconnecting...")
+        setConnectionStatus(["reconnecting"])
 
         // Try to reconnect after 2 seconds
         clearTimeout(reconnectTimer)
@@ -144,43 +157,58 @@ export default function Share(props: { api: string }) {
   })
 
   return (
-    <main>
+    <main class={`${styles.root} not-content`}>
       <div class={styles.header}>
-        <h1>Untitled conversation</h1>
-        <p>
-          <span>&#9679;</span>
-          <span>{connectionStatus()}</span>
-        </p>
+        <div data-section="title">
+          <h1>Untitled conversation</h1>
+          <p>
+            <span data-status={connectionStatus()[0]}>&#9679;</span>
+            <span>{getStatusText(connectionStatus())}</span>
+          </p>
+        </div>
+        <div data-section="row">
+          <ul class={styles.stats}>
+            <li>
+              <span>Cost</span>
+              {sessionInfo()?.cost ?
+                <span>{sessionInfo()?.cost}</span>
+                :
+                <span data-placeholder>&mdash;</span>
+              }
+            </li>
+            <li>
+              <span>Input Tokens</span>
+              {sessionInfo()?.tokens?.input ?
+                <span>{sessionInfo()?.tokens?.input}</span>
+                :
+                <span data-placeholder>&mdash;</span>
+              }
+            </li>
+            <li>
+              <span>Output Tokens</span>
+              {sessionInfo()?.tokens?.output ?
+                <span>{sessionInfo()?.tokens?.output}</span>
+                :
+                <span data-placeholder>&mdash;</span>
+              }
+            </li>
+            <li>
+              <span>Reasoning Tokens</span>
+              {sessionInfo()?.tokens?.reasoning ?
+                <span>{sessionInfo()?.tokens?.reasoning}</span>
+                :
+                <span data-placeholder>&mdash;</span>
+              }
+            </li>
+          </ul>
+          <div class={styles.context}>
+            <button>View Context &gt;</button>
+          </div>
+        </div>
       </div>
 
       <div style={{ margin: "2rem 0" }}>
 
-        <Show when={sessionInfo()}>
-          <div
-            style={{
-              padding: "1rem",
-              marginBottom: "1rem",
-              border: "1px solid #dee2e6",
-            }}
-          >
-            <h4 style={{ margin: "0 0 0.75rem 0" }}>Session Information</h4>
-            <div style={{ display: "flex", gap: "1.5rem" }}>
-              <div>
-                <strong>Input Tokens:</strong>{" "}
-                {sessionInfo()?.tokens?.input || 0}
-              </div>
-              <div>
-                <strong>Output Tokens:</strong>{" "}
-                {sessionInfo()?.tokens?.output || 0}
-              </div>
-              <div>
-                <strong>Reasoning Tokens:</strong>{" "}
-                {sessionInfo()?.tokens?.reasoning || 0}
-              </div>
-            </div>
-          </div>
-        </Show>
-
         {/* Display system message as context in the Session Information block */}
         <Show when={systemMessage()}>
           <div
@@ -687,6 +715,6 @@ export default function Share(props: { api: string }) {
           </Show>
         </div>
       </div>
-    </main>
+    </main >
   )
 }

+ 73 - 6
app/packages/web/src/components/share.module.css

@@ -1,22 +1,89 @@
+.root {
+  line-height: 1;
+}
+
 .header {
   display: flex;
-  align-items: center;
-  justify-content: space-between;
+  flex-direction: column;
+  gap: 0.75rem;
+
+  [data-section="title"] {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  [data-section="row"] {
+    display: flex;
+    flex-direction: column;
+    gap: 0.375rem;
+  }
 
   h1 {
-    font-size: 1.125rem;
+    font-size: 1.75rem;
     font-weight: 500;
   }
   p {
     display: flex;
+    gap: 0.375rem;
+    font-size: 0.75rem;
+
+    span:first-child {
+      color: var(--sl-color-gray-5);
+
+      &[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="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;
+    }
+  }
+}
+
+.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:first-child {
-      &.connected { color: var(--sl-color-green); }
-      &.connecting { color: var(--sl-color-orange); }
-      &.disconnected { color: var(--sl-color-hairline); }
+      color: var(--sl-color-text-dimmed);
+      text-transform: uppercase;
+      letter-spacing: 0.05em;
+    }
+    span:last-child {
+      &[data-placeholder] {
+        color: var(--sl-color-text-dimmed);
+      }
     }
   }
 }
 
+.context {
+  button {
+    appearance: none;
+    background: none;
+    border: none;
+    padding: 0;
+    margin: 0;
+    font-size: 0.875rem;
+    color: var(--sl-color-text-dimmed);
+    cursor: pointer;
+
+    &:hover {
+      color: var(--sl-color-primary);
+    }
+  }
+}