mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-18 01:00:32 +00:00
Add Foundry Tauri v2 desktop app with UI polish
- Scaffold Tauri v2 desktop package (foundry/packages/desktop) - Sidecar build script compiles backend into standalone Bun binary - Frontend build script packages Vite output for Tauri webview - macOS glass-effect app icon following Big Sur design standards - Collapsible sidebars with smooth width transitions - Inset content framing with borders and nested border-radius (Outer R = Inner R + Padding) - iMessage-style chat bubble styling with proper corner radii - Styled composer input with matching border-radius - Vertical separator between chat and right sidebar - Website download button component - Cargo workspace exclude for standalone Tauri build Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dbc2ff0682
commit
f6656a90af
80 changed files with 6621 additions and 152 deletions
|
|
@ -43,15 +43,15 @@ const TranscriptMessageBody = memo(function TranscriptMessageBody({
|
|||
>
|
||||
<div
|
||||
className={css({
|
||||
maxWidth: "100%",
|
||||
padding: "12px 16px",
|
||||
borderTopLeftRadius: "16px",
|
||||
borderTopRightRadius: "16px",
|
||||
maxWidth: "80%",
|
||||
...(isUser
|
||||
? {
|
||||
padding: "12px 16px",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.10)",
|
||||
color: "#e4e4e7",
|
||||
borderBottomLeftRadius: "16px",
|
||||
borderTopLeftRadius: "18px",
|
||||
borderTopRightRadius: "18px",
|
||||
borderBottomLeftRadius: "18px",
|
||||
borderBottomRightRadius: "4px",
|
||||
}
|
||||
: {
|
||||
|
|
@ -155,7 +155,7 @@ export const MessageList = memo(function MessageList({
|
|||
);
|
||||
|
||||
const messageContentClass = css({
|
||||
maxWidth: "80%",
|
||||
maxWidth: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
});
|
||||
|
|
@ -201,7 +201,7 @@ export const MessageList = memo(function MessageList({
|
|||
<div
|
||||
ref={scrollRef}
|
||||
className={css({
|
||||
padding: "16px 220px 16px 44px",
|
||||
padding: "16px 20px 16px 20px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: 1,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const PromptComposer = memo(function PromptComposer({
|
|||
position: "relative",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.06)",
|
||||
border: `1px solid ${theme.colors.borderOpaque}`,
|
||||
borderRadius: "16px",
|
||||
borderRadius: "12px",
|
||||
minHeight: `${PROMPT_TEXTAREA_MIN_HEIGHT + 36}px`,
|
||||
transition: "border-color 200ms ease",
|
||||
":focus-within": { borderColor: "rgba(255, 255, 255, 0.15)" },
|
||||
|
|
@ -56,7 +56,7 @@ export const PromptComposer = memo(function PromptComposer({
|
|||
padding: "14px 58px 8px 14px",
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
borderRadius: "16px 16px 0 0",
|
||||
borderRadius: "12px 12px 0 0",
|
||||
color: theme.colors.contentPrimary,
|
||||
fontSize: "13px",
|
||||
fontFamily: "inherit",
|
||||
|
|
@ -77,7 +77,7 @@ export const PromptComposer = memo(function PromptComposer({
|
|||
padding: "0",
|
||||
margin: "0",
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
borderRadius: "10px",
|
||||
cursor: "pointer",
|
||||
position: "absolute",
|
||||
right: "12px",
|
||||
|
|
@ -112,7 +112,7 @@ export const PromptComposer = memo(function PromptComposer({
|
|||
return (
|
||||
<div
|
||||
className={css({
|
||||
padding: "12px 16px",
|
||||
padding: "12px 12px",
|
||||
borderTop: "none",
|
||||
flexShrink: 0,
|
||||
display: "flex",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { memo, useCallback, useMemo, useState, type MouseEvent } from "react";
|
||||
import { useStyletron } from "baseui";
|
||||
import { LabelSmall } from "baseui/typography";
|
||||
import { Archive, ArrowUpFromLine, ChevronRight, FileCode, FilePlus, FileX, FolderOpen, GitPullRequest } from "lucide-react";
|
||||
import { Archive, ArrowUpFromLine, ChevronRight, FileCode, FilePlus, FileX, FolderOpen, GitPullRequest, PanelRight } from "lucide-react";
|
||||
|
||||
import { type ContextMenuItem, ContextMenuOverlay, PanelHeaderBar, SPanel, ScrollBody, useContextMenu } from "./ui";
|
||||
import { type FileTreeNode, type Task, diffTabId } from "./view-model";
|
||||
|
|
@ -93,6 +93,7 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
onArchive,
|
||||
onRevertFile,
|
||||
onPublishPr,
|
||||
onToggleSidebar,
|
||||
}: {
|
||||
task: Task;
|
||||
activeTabId: string | null;
|
||||
|
|
@ -100,6 +101,7 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
onArchive: () => void;
|
||||
onRevertFile: (path: string) => void;
|
||||
onPublishPr: () => void;
|
||||
onToggleSidebar?: () => void;
|
||||
}) {
|
||||
const [css, theme] = useStyletron();
|
||||
const [rightTab, setRightTab] = useState<"changes" | "files">("changes");
|
||||
|
|
@ -171,7 +173,7 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
})}
|
||||
>
|
||||
<GitPullRequest size={12} style={{ flexShrink: 0 }} />
|
||||
{pullRequestUrl ? "Open PR" : "Publish PR"}
|
||||
<span className={css({ "@media screen and (max-width: 768px)": { display: "none" } })}>{pullRequestUrl ? "Open PR" : "Publish PR"}</span>
|
||||
</button>
|
||||
<button
|
||||
className={css({
|
||||
|
|
@ -195,7 +197,8 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
":hover": { backgroundColor: "rgba(255, 255, 255, 0.06)", color: "#ffffff" },
|
||||
})}
|
||||
>
|
||||
<ArrowUpFromLine size={12} style={{ flexShrink: 0 }} /> Push
|
||||
<ArrowUpFromLine size={12} style={{ flexShrink: 0 }} />{" "}
|
||||
<span className={css({ "@media screen and (max-width: 768px)": { display: "none" } })}>Push</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={onArchive}
|
||||
|
|
@ -220,13 +223,49 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
":hover": { backgroundColor: "rgba(255, 255, 255, 0.06)", color: "#ffffff" },
|
||||
})}
|
||||
>
|
||||
<Archive size={12} style={{ flexShrink: 0 }} /> Archive
|
||||
<Archive size={12} style={{ flexShrink: 0 }} />{" "}
|
||||
<span className={css({ "@media screen and (max-width: 768px)": { display: "none" } })}>Archive</span>
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
{onToggleSidebar ? (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onToggleSidebar}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") onToggleSidebar();
|
||||
}}
|
||||
className={css({
|
||||
width: "26px",
|
||||
height: "26px",
|
||||
borderRadius: "6px",
|
||||
color: "#71717a",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
":hover": { color: "#a1a1aa", backgroundColor: "rgba(255, 255, 255, 0.06)" },
|
||||
})}
|
||||
>
|
||||
<PanelRight size={14} />
|
||||
</div>
|
||||
) : null}
|
||||
</PanelHeaderBar>
|
||||
|
||||
<div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", borderTop: "1px solid rgba(255, 255, 255, 0.10)" }}>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
borderTop: "1px solid rgba(255, 255, 255, 0.10)",
|
||||
borderRight: "1px solid rgba(255, 255, 255, 0.10)",
|
||||
borderTopRightRadius: "12px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={css({
|
||||
display: "flex",
|
||||
|
|
@ -237,6 +276,7 @@ export const RightSidebar = memo(function RightSidebar({
|
|||
height: "41px",
|
||||
minHeight: "41px",
|
||||
flexShrink: 0,
|
||||
borderTopRightRadius: "12px",
|
||||
})}
|
||||
>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { memo, useRef, useState } from "react";
|
||||
import { useStyletron } from "baseui";
|
||||
import { LabelSmall, LabelXSmall } from "baseui/typography";
|
||||
import { ChevronDown, ChevronUp, CloudUpload, GitPullRequestDraft, ListChecks, Plus } from "lucide-react";
|
||||
import { ChevronDown, ChevronUp, CloudUpload, GitPullRequestDraft, ListChecks, PanelLeft, Plus } from "lucide-react";
|
||||
|
||||
import { formatRelativeAge, type Task, type ProjectSection } from "./view-model";
|
||||
import { ContextMenuOverlay, TaskIndicator, PanelHeaderBar, SPanel, ScrollBody, useContextMenu } from "./ui";
|
||||
|
|
@ -34,6 +34,7 @@ export const Sidebar = memo(function Sidebar({
|
|||
onRenameTask,
|
||||
onRenameBranch,
|
||||
onReorderProjects,
|
||||
onToggleSidebar,
|
||||
}: {
|
||||
projects: ProjectSection[];
|
||||
newTaskRepos: Array<{ id: string; label: string }>;
|
||||
|
|
@ -46,6 +47,7 @@ export const Sidebar = memo(function Sidebar({
|
|||
onRenameTask: (id: string) => void;
|
||||
onRenameBranch: (id: string) => void;
|
||||
onReorderProjects: (fromIndex: number, toIndex: number) => void;
|
||||
onToggleSidebar?: () => void;
|
||||
}) {
|
||||
const [css, theme] = useStyletron();
|
||||
const contextMenu = useContextMenu();
|
||||
|
|
@ -63,6 +65,45 @@ export const Sidebar = memo(function Sidebar({
|
|||
display: none !important;
|
||||
}
|
||||
`}</style>
|
||||
{import.meta.env.VITE_DESKTOP ? (
|
||||
<div
|
||||
className={css({
|
||||
height: "38px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
paddingRight: "10px",
|
||||
flexShrink: 0,
|
||||
position: "relative",
|
||||
zIndex: 9999,
|
||||
})}
|
||||
>
|
||||
{onToggleSidebar ? (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onToggleSidebar}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") onToggleSidebar();
|
||||
}}
|
||||
className={css({
|
||||
width: "26px",
|
||||
height: "26px",
|
||||
borderRadius: "6px",
|
||||
color: "#71717a",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
":hover": { color: "#a1a1aa", backgroundColor: "rgba(255, 255, 255, 0.06)" },
|
||||
})}
|
||||
>
|
||||
<PanelLeft size={14} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<PanelHeaderBar $style={{ backgroundColor: "transparent", borderBottom: "none" }}>
|
||||
<LabelSmall
|
||||
color={theme.colors.contentPrimary}
|
||||
|
|
@ -71,6 +112,30 @@ export const Sidebar = memo(function Sidebar({
|
|||
<ListChecks size={14} />
|
||||
Tasks
|
||||
</LabelSmall>
|
||||
{!import.meta.env.VITE_DESKTOP && onToggleSidebar ? (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={onToggleSidebar}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") onToggleSidebar();
|
||||
}}
|
||||
className={css({
|
||||
width: "26px",
|
||||
height: "26px",
|
||||
borderRadius: "6px",
|
||||
color: "#71717a",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
":hover": { color: "#a1a1aa", backgroundColor: "rgba(255, 255, 255, 0.06)" },
|
||||
})}
|
||||
>
|
||||
<PanelLeft size={14} />
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ export const TranscriptHeader = memo(function TranscriptHeader({
|
|||
":hover": { backgroundColor: "rgba(255, 255, 255, 0.06)", color: theme.colors.contentPrimary },
|
||||
})}
|
||||
>
|
||||
<MailOpen size={12} style={{ flexShrink: 0 }} /> {activeTab.unread ? "Mark read" : "Mark unread"}
|
||||
<MailOpen size={12} style={{ flexShrink: 0 }} />{" "}
|
||||
<span className={css({ "@media screen and (max-width: 768px)": { display: "none" } })}>{activeTab.unread ? "Mark read" : "Mark unread"}</span>
|
||||
</button>
|
||||
) : null}
|
||||
</PanelHeaderBar>
|
||||
|
|
|
|||
|
|
@ -205,4 +205,6 @@ export const PanelHeaderBar = styled("div", ({ $theme }) => ({
|
|||
backgroundColor: $theme.colors.backgroundTertiary,
|
||||
gap: "8px",
|
||||
flexShrink: 0,
|
||||
position: "relative" as const,
|
||||
zIndex: 9999,
|
||||
}));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue