mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-18 05:01:58 +00:00
feat: real org mock data, model picker styling, project icons, task minutes indicator
- Replace fake acme/* mock data with real rivet-dev GitHub org repos and PRs - Fix model picker popover: dark gray surface with backdrop blur instead of pure black - Add colored letter icons to project section headers (swap to chevron on hover) - Add "847 min used" indicator in transcript header - Rename browser tab title from OpenHandoff to Foundry - Reduce transcript header title font weight to 500 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6d0c004269
commit
abd7e06e66
5 changed files with 760 additions and 506 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@
|
||||||
</script>
|
</script>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>OpenHandoff</title>
|
<title>Foundry</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ const ModelPickerContent = memo(function ModelPickerContent({
|
||||||
const [hoveredId, setHoveredId] = useState<ModelId | null>(null);
|
const [hoveredId, setHoveredId] = useState<ModelId | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={css({ minWidth: "200px", padding: "4px 0" })}>
|
<div className={css({ minWidth: "220px", padding: "6px 0" })}>
|
||||||
{MODEL_GROUPS.map((group) => (
|
{MODEL_GROUPS.map((group) => (
|
||||||
<div key={group.provider}>
|
<div key={group.provider}>
|
||||||
<div
|
<div
|
||||||
|
|
@ -62,7 +62,10 @@ const ModelPickerContent = memo(function ModelPickerContent({
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
fontWeight: isActive ? 600 : 400,
|
fontWeight: isActive ? 600 : 400,
|
||||||
color: isActive ? theme.colors.contentPrimary : theme.colors.contentSecondary,
|
color: isActive ? theme.colors.contentPrimary : theme.colors.contentSecondary,
|
||||||
":hover": { backgroundColor: "rgba(255, 255, 255, 0.06)" },
|
borderRadius: "6px",
|
||||||
|
marginLeft: "4px",
|
||||||
|
marginRight: "4px",
|
||||||
|
":hover": { backgroundColor: "rgba(255, 255, 255, 0.08)" },
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AgentIcon agent={agent} size={12} />
|
<AgentIcon agent={agent} size={12} />
|
||||||
|
|
@ -112,13 +115,14 @@ export const ModelPicker = memo(function ModelPicker({
|
||||||
overrides={{
|
overrides={{
|
||||||
Body: {
|
Body: {
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "#000000",
|
backgroundColor: "rgba(32, 32, 32, 0.98)",
|
||||||
borderTopLeftRadius: "8px",
|
backdropFilter: "blur(12px)",
|
||||||
borderTopRightRadius: "8px",
|
borderTopLeftRadius: "10px",
|
||||||
borderBottomLeftRadius: "8px",
|
borderTopRightRadius: "10px",
|
||||||
borderBottomRightRadius: "8px",
|
borderBottomLeftRadius: "10px",
|
||||||
border: `1px solid ${theme.colors.borderOpaque}`,
|
borderBottomRightRadius: "10px",
|
||||||
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.6)",
|
border: "1px solid rgba(255, 255, 255, 0.10)",
|
||||||
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.04)",
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,22 @@ import { ChevronDown, ChevronUp, CloudUpload, GitPullRequestDraft, ListChecks, P
|
||||||
import { formatRelativeAge, type Handoff, type ProjectSection } from "./view-model";
|
import { formatRelativeAge, type Handoff, type ProjectSection } from "./view-model";
|
||||||
import { ContextMenuOverlay, HandoffIndicator, PanelHeaderBar, SPanel, ScrollBody, useContextMenu } from "./ui";
|
import { ContextMenuOverlay, HandoffIndicator, PanelHeaderBar, SPanel, ScrollBody, useContextMenu } from "./ui";
|
||||||
|
|
||||||
|
const PROJECT_COLORS = ["#6366f1", "#f59e0b", "#10b981", "#ef4444", "#8b5cf6", "#ec4899", "#06b6d4", "#f97316"];
|
||||||
|
|
||||||
|
function projectInitial(label: string): string {
|
||||||
|
const parts = label.split("/");
|
||||||
|
const name = parts[parts.length - 1] ?? label;
|
||||||
|
return name.charAt(0).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function projectIconColor(label: string): string {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < label.length; i++) {
|
||||||
|
hash = (hash * 31 + label.charCodeAt(i)) | 0;
|
||||||
|
}
|
||||||
|
return PROJECT_COLORS[Math.abs(hash) % PROJECT_COLORS.length]!;
|
||||||
|
}
|
||||||
|
|
||||||
export const Sidebar = memo(function Sidebar({
|
export const Sidebar = memo(function Sidebar({
|
||||||
projects,
|
projects,
|
||||||
activeId,
|
activeId,
|
||||||
|
|
@ -33,6 +49,9 @@ export const Sidebar = memo(function Sidebar({
|
||||||
[data-project-header]:hover [data-chevron] {
|
[data-project-header]:hover [data-chevron] {
|
||||||
display: inline-flex !important;
|
display: inline-flex !important;
|
||||||
}
|
}
|
||||||
|
[data-project-header]:hover [data-project-icon] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
<PanelHeaderBar>
|
<PanelHeaderBar>
|
||||||
<LabelSmall
|
<LabelSmall
|
||||||
|
|
@ -89,13 +108,33 @@ export const Sidebar = memo(function Sidebar({
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className={css({ display: "flex", alignItems: "center", gap: "4px", overflow: "hidden" })}>
|
<div className={css({ display: "flex", alignItems: "center", gap: "4px", overflow: "hidden" })}>
|
||||||
<span className={css({ display: "none", flexShrink: 0 })} data-chevron>
|
<div className={css({ position: "relative", width: "14px", height: "14px", flexShrink: 0 })}>
|
||||||
|
<span
|
||||||
|
className={css({
|
||||||
|
position: "absolute",
|
||||||
|
inset: 0,
|
||||||
|
display: "inline-flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
borderRadius: "3px",
|
||||||
|
fontSize: "9px",
|
||||||
|
fontWeight: 700,
|
||||||
|
lineHeight: 1,
|
||||||
|
color: "#fff",
|
||||||
|
backgroundColor: projectIconColor(project.label),
|
||||||
|
})}
|
||||||
|
data-project-icon
|
||||||
|
>
|
||||||
|
{projectInitial(project.label)}
|
||||||
|
</span>
|
||||||
|
<span className={css({ position: "absolute", inset: 0, display: "none", alignItems: "center", justifyContent: "center" })} data-chevron>
|
||||||
{isCollapsed ? (
|
{isCollapsed ? (
|
||||||
<ChevronDown size={12} color={theme.colors.contentTertiary} />
|
<ChevronDown size={12} color={theme.colors.contentTertiary} />
|
||||||
) : (
|
) : (
|
||||||
<ChevronUp size={12} color={theme.colors.contentTertiary} />
|
<ChevronUp size={12} color={theme.colors.contentTertiary} />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
<LabelSmall
|
<LabelSmall
|
||||||
color={theme.colors.contentSecondary}
|
color={theme.colors.contentSecondary}
|
||||||
$style={{
|
$style={{
|
||||||
|
|
@ -146,7 +185,6 @@ export const Sidebar = memo(function Sidebar({
|
||||||
transition: "all 200ms ease",
|
transition: "all 200ms ease",
|
||||||
":hover": {
|
":hover": {
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.06)",
|
backgroundColor: "rgba(255, 255, 255, 0.06)",
|
||||||
borderColor: theme.colors.borderOpaque,
|
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { useStyletron } from "baseui";
|
import { useStyletron } from "baseui";
|
||||||
import { LabelSmall } from "baseui/typography";
|
import { LabelSmall } from "baseui/typography";
|
||||||
import { MailOpen } from "lucide-react";
|
import { Clock, MailOpen } from "lucide-react";
|
||||||
|
|
||||||
import { PanelHeaderBar } from "./ui";
|
import { PanelHeaderBar } from "./ui";
|
||||||
import { type AgentTab, type Handoff } from "./view-model";
|
import { type AgentTab, type Handoff } from "./view-model";
|
||||||
|
|
@ -46,7 +46,7 @@ export const TranscriptHeader = memo(function TranscriptHeader({
|
||||||
}}
|
}}
|
||||||
className={css({
|
className={css({
|
||||||
all: "unset",
|
all: "unset",
|
||||||
fontWeight: 600,
|
fontWeight: 500,
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
color: theme.colors.contentPrimary,
|
color: theme.colors.contentPrimary,
|
||||||
borderBottom: "1px solid rgba(255, 255, 255, 0.3)",
|
borderBottom: "1px solid rgba(255, 255, 255, 0.3)",
|
||||||
|
|
@ -58,7 +58,7 @@ export const TranscriptHeader = memo(function TranscriptHeader({
|
||||||
<LabelSmall
|
<LabelSmall
|
||||||
title="Rename"
|
title="Rename"
|
||||||
color={theme.colors.contentPrimary}
|
color={theme.colors.contentPrimary}
|
||||||
$style={{ fontWeight: 600, whiteSpace: "nowrap", cursor: "pointer", ":hover": { textDecoration: "underline" } }}
|
$style={{ fontWeight: 500, whiteSpace: "nowrap", cursor: "pointer", ":hover": { textDecoration: "underline" } }}
|
||||||
onClick={() => onStartEditingField("title", handoff.title)}
|
onClick={() => onStartEditingField("title", handoff.title)}
|
||||||
>
|
>
|
||||||
{handoff.title}
|
{handoff.title}
|
||||||
|
|
@ -113,6 +113,24 @@ export const TranscriptHeader = memo(function TranscriptHeader({
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
<div className={css({ flex: 1 })} />
|
<div className={css({ flex: 1 })} />
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "5px",
|
||||||
|
padding: "3px 10px",
|
||||||
|
borderRadius: "6px",
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
||||||
|
border: "1px solid rgba(255, 255, 255, 0.08)",
|
||||||
|
fontSize: "11px",
|
||||||
|
fontWeight: 500,
|
||||||
|
color: theme.colors.contentSecondary,
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Clock size={11} />
|
||||||
|
<span>847 min used</span>
|
||||||
|
</div>
|
||||||
{activeTab ? (
|
{activeTab ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => onSetActiveTabUnread(!activeTab.unread)}
|
onClick={() => onSetActiveTabUnread(!activeTab.unread)}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue