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 () { setFontStack(value)} - selectedKey={fontStack} + selectedKey={fontStack ?? "Transitional"} > {(item) => (