Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions scripts/generate_prism_css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ for (const [key, value] of Object.entries(vscDarkPlus as Record<string, unknown>
}

// Convert CSS properties object to CSS string
function cssPropertiesToString(props: CSSProperties): string {
return Object.entries(props)
function cssPropertiesToString(props: CSSProperties, selector: string): string {
const entries = Object.entries(props)
.filter(([key]) => {
// Skip font-family and font-size - we want to inherit these
return key !== "fontFamily" && key !== "fontSize";
Expand All @@ -35,8 +35,14 @@ function cssPropertiesToString(props: CSSProperties): string {
// Convert camelCase to kebab-case
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
return ` ${cssKey}: ${value};`;
})
.join("\n");
});

// Add background: transparent to pre/code elements to prevent double backgrounds
if (selector.startsWith("pre") || selector.startsWith("code")) {
entries.push(" background: transparent;");
}

return entries.join("\n");
}

// Generate CSS content
Expand All @@ -55,7 +61,7 @@ function generateCSS(): string {
];

for (const [selector, props] of Object.entries(syntaxStyleNoBackgrounds)) {
const cssRules = cssPropertiesToString(props);
const cssRules = cssPropertiesToString(props, selector);
if (cssRules.trim().length > 0) {
// Handle selectors that need .token prefix
let cssSelector = selector;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Messages/AssistantMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const RawContent = styled.pre`
word-break: break-word;
margin: 0;
padding: 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
`;

Expand Down
2 changes: 1 addition & 1 deletion src/components/Messages/MarkdownComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const markdownComponents = {
padding: "0.25em 0.5em",
border: "1px solid rgba(255, 255, 255, 0.1)",
borderRadius: "4px",
background: "rgba(0, 0, 0, 0.2)",
background: "var(--color-code-bg)",
}}
>
{children}
Expand Down
6 changes: 3 additions & 3 deletions src/components/Messages/Mermaid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export const Mermaid: React.FC<{ chart: string }> = ({ chart }) => {
<div
style={{
color: "var(--color-text-secondary)",
background: "rgba(0, 0, 0, 0.2)",
background: "var(--color-code-bg)",
padding: "12px",
fontStyle: "italic",
}}
Expand All @@ -189,7 +189,7 @@ export const Mermaid: React.FC<{ chart: string }> = ({ chart }) => {
style={{
position: "relative",
margin: "1em 0",
background: "rgba(0, 0, 0, 0.2)",
background: "var(--color-code-bg)",
borderRadius: "4px",
padding: "16px",
}}
Expand Down Expand Up @@ -243,7 +243,7 @@ export const Mermaid: React.FC<{ chart: string }> = ({ chart }) => {
ref={modalContainerRef}
className="mermaid-container mermaid-modal"
style={{
background: "rgba(0, 0, 0, 0.2)",
background: "var(--color-code-bg)",
padding: "24px",
borderRadius: "8px",
minWidth: "80vw",
Expand Down
43 changes: 40 additions & 3 deletions src/components/RightSidebar/CodeReview/FileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
* FileTree - Displays file hierarchy with diff statistics
*/

import React, { useState } from "react";
import React from "react";
import styled from "@emotion/styled";
import type { FileTreeNode } from "@/utils/git/numstatParser";
import { usePersistedState } from "@/hooks/usePersistedState";
import { getFileTreeExpandStateKey } from "@/constants/storage";

const TreeContainer = styled.div`
flex: 1;
Expand Down Expand Up @@ -194,8 +196,30 @@ const TreeNodeContent: React.FC<{
onSelectFile: (path: string | null) => void;
commonPrefix: string | null;
getFileReadStatus?: (filePath: string) => { total: number; read: number } | null;
}> = ({ node, depth, selectedPath, onSelectFile, commonPrefix, getFileReadStatus }) => {
const [isOpen, setIsOpen] = useState(depth < 2); // Auto-expand first 2 levels
expandStateMap: Record<string, boolean>;
setExpandStateMap: (
value: Record<string, boolean> | ((prev: Record<string, boolean>) => Record<string, boolean>)
) => void;
}> = ({
node,
depth,
selectedPath,
onSelectFile,
commonPrefix,
getFileReadStatus,
expandStateMap,
setExpandStateMap,
}) => {
// Check if user has manually set expand state for this directory
const hasManualState = node.path in expandStateMap;
const isOpen = hasManualState ? expandStateMap[node.path] : depth < 2; // Default: auto-expand first 2 levels

const setIsOpen = (open: boolean) => {
setExpandStateMap((prev) => ({
...prev,
[node.path]: open,
}));
};

const handleClick = (e: React.MouseEvent) => {
if (node.isDirectory) {
Expand Down Expand Up @@ -295,6 +319,8 @@ const TreeNodeContent: React.FC<{
onSelectFile={onSelectFile}
commonPrefix={commonPrefix}
getFileReadStatus={getFileReadStatus}
expandStateMap={expandStateMap}
setExpandStateMap={setExpandStateMap}
/>
))}
</>
Expand All @@ -308,6 +334,7 @@ interface FileTreeExternalProps {
isLoading?: boolean;
commonPrefix?: string | null;
getFileReadStatus?: (filePath: string) => { total: number; read: number } | null;
workspaceId: string;
}

export const FileTree: React.FC<FileTreeExternalProps> = ({
Expand All @@ -317,7 +344,15 @@ export const FileTree: React.FC<FileTreeExternalProps> = ({
isLoading = false,
commonPrefix = null,
getFileReadStatus,
workspaceId,
}) => {
// Use persisted state for expand/collapse per workspace (lifted to parent to avoid O(n) re-renders)
const [expandStateMap, setExpandStateMap] = usePersistedState<Record<string, boolean>>(
getFileTreeExpandStateKey(workspaceId),
{},
{ listener: true }
);

// Find the node at the common prefix path to start rendering from
const startNode = React.useMemo(() => {
if (!commonPrefix || !root) return root;
Expand Down Expand Up @@ -355,6 +390,8 @@ export const FileTree: React.FC<FileTreeExternalProps> = ({
onSelectFile={onSelectFile}
commonPrefix={commonPrefix}
getFileReadStatus={getFileReadStatus}
expandStateMap={expandStateMap}
setExpandStateMap={setExpandStateMap}
/>
))
) : (
Expand Down
2 changes: 1 addition & 1 deletion src/components/RightSidebar/CodeReview/HunkViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const HunkContent = styled.div`
font-size: 11px;
line-height: 1.4;
overflow-x: auto;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);

/* CSS Grid ensures all diff lines span the same width (width of longest line) */
display: grid;
Expand Down
1 change: 1 addition & 0 deletions src/components/RightSidebar/CodeReview/ReviewPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
isLoading={isLoadingTree}
commonPrefix={commonPrefix}
getFileReadStatus={getFileReadStatus}
workspaceId={workspaceId}
/>
</FileTreeSection>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/DiffRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export const DiffIndicator = styled.span<{ type: DiffLineType }>`
export const DiffContainer = styled.div<{ fontSize?: string; maxHeight?: string }>`
margin: 0;
padding: 6px 0;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
font-size: ${({ fontSize }) => fontSize ?? "12px"};
line-height: 1.4;
Expand Down
2 changes: 1 addition & 1 deletion src/components/tools/BashToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ScriptPreview = styled.span`
const OutputBlock = styled.pre`
margin: 0;
padding: 6px 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
border-left: 2px solid #4caf50;
font-size: 11px;
Expand Down
4 changes: 2 additions & 2 deletions src/components/tools/FileReadToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const MetadataText = styled.span`
const ContentBlock = styled.div`
margin: 0;
padding: 6px 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
font-size: 11px;
line-height: 1.4;
Expand Down Expand Up @@ -79,7 +79,7 @@ const FileInfoRow = styled.div`
flex-wrap: wrap;
gap: 16px;
padding: 6px 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
font-size: 11px;
line-height: 1.4;
Expand Down
2 changes: 1 addition & 1 deletion src/components/tools/ProposePlanToolCall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const RawContent = styled.pre`
word-break: break-word;
margin: 0;
padding: 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
`;

Expand Down
2 changes: 1 addition & 1 deletion src/components/tools/shared/ToolPrimitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const DetailLabel = styled.div`
export const DetailContent = styled.pre`
margin: 0;
padding: 6px 8px;
background: rgba(0, 0, 0, 0.2);
background: var(--color-code-bg);
border-radius: 3px;
font-size: 11px;
line-height: 1.4;
Expand Down
12 changes: 11 additions & 1 deletion src/constants/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ export function getReviewExpandStateKey(workspaceId: string): string {
return `reviewExpandState:${workspaceId}`;
}

/**
* Get the localStorage key for FileTree expand/collapse state in Review tab
* Stores directory expand/collapse preferences per workspace
* Format: "fileTreeExpandState:{workspaceId}"
*/
export function getFileTreeExpandStateKey(workspaceId: string): string {
return `fileTreeExpandState:${workspaceId}`;
}

/**
* List of workspace-scoped key functions that should be copied on fork and deleted on removal
* Note: Excludes ephemeral keys like getCompactContinueMessageKey
Expand All @@ -105,6 +114,7 @@ const PERSISTENT_WORKSPACE_KEY_FUNCTIONS: Array<(workspaceId: string) => string>
getAutoRetryKey,
getRetryStateKey,
getReviewExpandStateKey,
getFileTreeExpandStateKey,
];

/**
Expand All @@ -117,7 +127,7 @@ const EPHEMERAL_WORKSPACE_KEY_FUNCTIONS: Array<(workspaceId: string) => string>

/**
* Copy all workspace-specific localStorage keys from source to destination workspace
* This includes: model, input, mode, thinking level, auto-retry, retry state, review expand state
* This includes: model, input, mode, thinking level, auto-retry, retry state, review expand state, file tree expand state
*/
export function copyWorkspaceStorage(sourceWorkspaceId: string, destWorkspaceId: string): void {
for (const getKey of PERSISTENT_WORKSPACE_KEY_FUNCTIONS) {
Expand Down
5 changes: 5 additions & 0 deletions src/styles/colors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ export const GlobalColors = () => (
--color-text: hsl(0 0% 83%);
--color-text-secondary: hsl(0 0% 42%);

/* Code Block Background */
--color-code-bg: hsl(
0deg 6.43% 8.04%
); /* Slightly darker than main background for code/diff containers */

/* Button Colors */
--color-button-bg: hsl(0 0% 24%);
--color-button-text: hsl(0 0% 80%);
Expand Down
15 changes: 8 additions & 7 deletions src/styles/prism-syntax.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ pre[class*="language-"] {
ms-hyphens: none;
hyphens: none;
padding: 1em;
margin: .5em 0;
margin: 0.5em 0;
overflow: auto;
background: transparent;
}

code[class*="language-"] {
Expand Down Expand Up @@ -64,17 +65,17 @@ code[class*="language-"] *::selection {
}

:not(pre) > code[class*="language-"] {
padding: .1em .3em;
border-radius: .3em;
padding: 0.1em 0.3em;
border-radius: 0.3em;
color: #db4c69;
}

.namespace {
-opacity: .7;
-opacity: 0.7;
}

doctype.doctype-tag {
color: #569CD6;
color: #569cd6;
}

doctype.name {
Expand Down Expand Up @@ -170,7 +171,7 @@ doctype.name {
}

operator.arrow {
color: #569CD6;
color: #569cd6;
}

.token.atrule {
Expand All @@ -194,7 +195,7 @@ atrule.url.punctuation {
}

.token.keyword {
color: #569CD6;
color: #569cd6;
}

keyword.module {
Expand Down