diff --git a/bun.lock b/bun.lock
index 2af4931..394f321 100644
--- a/bun.lock
+++ b/bun.lock
@@ -25,6 +25,7 @@
"react-stately": "latest",
"runtypes": "latest",
"shevyjs": "latest",
+ "temporal-polyfill": "latest",
"true-myth": "latest",
},
"devDependencies": {
@@ -347,7 +348,7 @@
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
- "@types/bun": ["@types/bun@1.2.1", "", { "dependencies": { "bun-types": "1.2.1" } }, "sha512-iiCeMAKMkft8EPQJxSbpVRD0DKqrh91w40zunNajce3nMNNFd/LnAquVisSZC+UpTMjDwtcdyzbWct08IvEqRA=="],
+ "@types/bun": ["@types/bun@1.2.2", "", { "dependencies": { "bun-types": "1.2.2" } }, "sha512-tr74gdku+AEDN5ergNiBnplr7hpDp3V1h7fqI2GcR/rsUaM39jpSeKH0TFibRvU0KwniRx5POgaYnaXbk0hU+w=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
@@ -379,7 +380,7 @@
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
- "bun-types": ["bun-types@1.2.1", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-p7bmXUWmrPWxhcbFVk7oUXM5jAGt94URaoa3qf4mz43MEhNAo/ot1urzBqctgvuq7y9YxkuN51u+/qm4BiIsHw=="],
+ "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
@@ -459,7 +460,7 @@
"isomorphic-dompurify": ["isomorphic-dompurify@2.20.0", "", { "dependencies": { "dompurify": "^3.2.3", "jsdom": "^26.0.0" } }, "sha512-zOq12fJPtNE+4dPd2S0xpWXl8NZj0C6k2xikT1yl/Lv/5p3QLafZqlVFy4xTGU9qHSkyEENcIbp2c0oahCNRYg=="],
- "jotai": ["jotai@2.11.2", "", { "peerDependencies": { "@types/react": ">=17.0.0", "react": ">=17.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-H3xOvsdqjBJnXTvpgAWfff2y1B3wabi1iSA6FFd0FrLaM4ENsRJd+RJQtkNhY4PZgvAODa4PQhau9dheK+pUkw=="],
+ "jotai": ["jotai@2.11.3", "", { "peerDependencies": { "@types/react": ">=17.0.0", "react": ">=17.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-B/PsewAQ0UOS5e2+TTWegUPQ3SCLPCjPY24LYUjfn2EorGlluTA2dFjVLgF1+xHLjK9Jit3y5mKHyMG3Xq/GZg=="],
"jotai-effect": ["jotai-effect@1.1.6", "", { "peerDependencies": { "jotai": ">=2.5.0" } }, "sha512-ZPLNZgRSxuTjyzMqLE9ervx1YjH6FwcaEC0kw77W7sEpZLgqjRm6UZTHjsyAxUWUCSwKQ8A3ai3Vkz0tZxSPgw=="],
@@ -563,6 +564,10 @@
"symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="],
+ "temporal-polyfill": ["temporal-polyfill@0.2.5", "", { "dependencies": { "temporal-spec": "^0.2.4" } }, "sha512-ye47xp8Cb0nDguAhrrDS1JT1SzwEV9e26sSsrWzVu+yPZ7LzceEcH0i2gci9jWfOfSCCgM3Qv5nOYShVUUFUXA=="],
+
+ "temporal-spec": ["temporal-spec@0.2.4", "", {}, "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ=="],
+
"tldts": ["tldts@6.1.74", "", { "dependencies": { "tldts-core": "^6.1.74" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-O5vTZ1UmmEmrLl/59U9igitnSMlprALLaLgbv//dEvjobPT9vyURhHXKMCDLEhn3qxZFIkb9PwAfNYV0Ol7RPQ=="],
"tldts-core": ["tldts-core@6.1.74", "", {}, "sha512-gTwtY6L2GfuxiL4CWpLknv9JDYYqBvKCk/BT5uAaAvCA0s6pzX7lr2IrkQZSUlnSjRHIjTl8ZwKCVXJ7XNRWYw=="],
@@ -577,7 +582,7 @@
"turbo-stream": ["turbo-stream@2.4.0", "", {}, "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="],
- "typescript": ["typescript@5.8.0-dev.20250131", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-q7nLABAsnnq3BdqOdWnRGVhe7Gv3QkditzT6YMfWpKHsZoJ1TVo+C4ZCZHK4fCuu2vHYUwV0zUUsEZZXdnxB2w=="],
+ "typescript": ["typescript@5.8.0-dev.20250201", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-dH6JX5ZdOLme/jasEkBV2/HbhOp5RuYxeMasdzndYrC3HVpSSoU/OEIiBRl1+2zzhRLkAjYknZtbvm6EW+Qadw=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
diff --git a/package.json b/package.json
index 77e3f8e..379d9ac 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"react-stately": "latest",
"runtypes": "latest",
"shevyjs": "latest",
+ "temporal-polyfill": "latest",
"true-myth": "latest"
}
}
diff --git a/src/components/ExperimentPreview.tsx b/src/components/ExperimentPreview.tsx
new file mode 100644
index 0000000..80a9909
--- /dev/null
+++ b/src/components/ExperimentPreview.tsx
@@ -0,0 +1,38 @@
+import { atom, useAtom } from "jotai";
+import { useMemo } from "react";
+import { Temporal } from "temporal-polyfill";
+
+import type { Experiment } from "../types";
+import { entangledAtom } from "../utils/entanglement";
+import { ChatPreview } from "./chat";
+import { View } from "./view";
+
+const timezoneAtom = entangledAtom(
+ "tz",
+ atom(() => {
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
+ }),
+);
+
+export function ExperimentPreview({ experiment }: { experiment: Experiment }) {
+ const [timezone] = useAtom(timezoneAtom);
+
+ const meta = useMemo(() => {
+ if (Array.isArray(experiment)) {
+ return null;
+ }
+ const { messages, ...meta } = experiment;
+ if (meta.timestamp) {
+ const instant = Temporal.Instant.from(meta.timestamp);
+ const zoned = instant.toZonedDateTimeISO(timezone);
+ meta.timestamp = zoned.toLocaleString(undefined, { timeStyle: "full", dateStyle: "full" });
+ }
+ return meta;
+ }, [experiment, timezone]);
+ return (
+ <>
+ {meta && {meta}}
+
+ >
+ );
+}
diff --git a/src/feature/router/Experiment.tsx b/src/feature/router/Experiment.tsx
index 2e4b4f6..1943bcd 100644
--- a/src/feature/router/Experiment.tsx
+++ b/src/feature/router/Experiment.tsx
@@ -1,22 +1,22 @@
-import { atom, useAtom, useSetAtom, type Setter } from "jotai";
+import { type Setter, atom, useAtom, useSetAtom } from "jotai";
import { useParams } from "react-router";
-import { ChatPreview, selectionAtom } from "../../components/chat";
+import { useEffect } from "react";
+import { navigateAtom, titleOverrideAtom } from ".";
import {
- experimentAtom,
type ExperimentCursor,
+ experimentAtom,
getExperimentAtom,
parentAtom,
templatesAtom,
} from "../../atoms/common";
+import { type Config, ConfigRenderer } from "../../components/ConfigRenderer";
+import { ExperimentPreview } from "../../components/ExperimentPreview";
+import { DesktopOnly } from "../../components/Mobile";
+import { selectionAtom } from "../../components/chat";
+import type { Experiment } from "../../types";
import { entangledAtom } from "../../utils/entanglement";
import { Actions, Page } from "./_page";
-import type { Experiment } from "../../types";
-import { DesktopOnly } from "../../components/Mobile";
-import { useEffect, useMemo } from "react";
-import { View } from "../../components/view";
-import { navigateAtom, titleOverrideAtom } from ".";
-import { ConfigRenderer, type Config } from "../../components/ConfigRenderer";
const cursorAtom = entangledAtom("cursor", atom(null));
const selectedExperimentAtom = entangledAtom(
@@ -110,22 +110,13 @@ export default function () {
return () => setTitleOverride(null);
}, []);
- const meta = useMemo(() => {
- if (Array.isArray(experiment)) {
- return null;
- }
- const { messages, ...meta } = experiment;
- return meta;
- }, [experiment]);
-
return (
<>
{title}
- {meta && {meta}}
-
+
{config}
diff --git a/src/feature/router/Import.tsx b/src/feature/router/Import.tsx
index 4cea8cd..61735dd 100644
--- a/src/feature/router/Import.tsx
+++ b/src/feature/router/Import.tsx
@@ -12,6 +12,7 @@ import { View } from "../../components/view";
import type { ExperimentWithMeta } from "../../types";
import { Actions, Page } from "./_page";
import { SidebarInput } from "./navigation";
+import { ExperimentPreview } from "../../components/ExperimentPreview";
const SidebarContents = () => {
const [chats] = useAtom(filenames);
@@ -125,13 +126,6 @@ export default function () {
setTitleOverride(title);
return () => setTitleOverride(null);
}, []);
- const meta = useMemo(() => {
- if (Array.isArray(experiment) || !experiment) {
- return null;
- }
- const { messages, ...meta } = experiment;
- return meta;
- }, [experiment]);
const [{ config, counter }] = useAtom(actionsAtom);
@@ -139,10 +133,7 @@ export default function () {
<>
{experiment ?
- <>
- {meta && {meta}}
-
- >
+
: <>
{title}
diff --git a/src/feature/router/NewExperiment.tsx b/src/feature/router/NewExperiment.tsx
index 9c79474..b06bb0b 100644
--- a/src/feature/router/NewExperiment.tsx
+++ b/src/feature/router/NewExperiment.tsx
@@ -372,6 +372,7 @@ export default function () {