Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
69b2af5
[diffshub] Add theme switcher to header
necolas May 20, 2026
b201f75
[diffs] Propagate theme swaps to collapsed and pooled containers
necolas May 21, 2026
ba2fa13
[diffshub] Theme the tree sidebar with the selected Shiki theme
necolas May 21, 2026
e743d87
[diffshub] Theme the sidebar chrome text and icons
necolas May 21, 2026
94aae11
[diffshub] Persist light/dark theme picks across reloads
necolas May 21, 2026
95d2aaf
[diffshub] Source sidebar primary text from sideBar.foreground
necolas May 21, 2026
7f893e2
[trees] Reject list.hoverBackground when it would erase row text
necolas May 21, 2026
7989a45
[diffshub] Theme the header chrome and surface comment cards
necolas May 21, 2026
fbb9172
Revert "[diffs] Propagate theme swaps to collapsed and pooled contain…
amadeus May 21, 2026
fb28fed
Remove codeview theme related changes
amadeus May 22, 2026
94f809f
[diffshub] Style the theme list with the shared mini scrollbar
necolas May 21, 2026
e3d4893
[diffshub] Wait for theme hydration before pushing to the WorkerPool
necolas May 21, 2026
d0a34c3
[diffshub] Pick chrome fg/muted by contrast and mirror into the tree
necolas May 22, 2026
7311c13
[diffshub] Auto-scroll the theme list to the selected row
necolas May 22, 2026
41b251b
[diffshub] Theme the Comments tab count badge
necolas May 22, 2026
2211c86
[diffshub] Add a theme-cycle button to the System Monitor
necolas May 22, 2026
7385d7c
[diffs] Fix theme switching for collapsed, cached, and pool-recycled …
necolas May 22, 2026
8eb651b
[diffshub] Fix unreadable muted chrome text on ayu-dark
necolas May 22, 2026
2cb13ae
[diffshub] Sync chrome and diff repaints across a theme swap
necolas May 22, 2026
85c361f
[diffshub] Theme comment cards and menus
necolas May 22, 2026
c94268a
Fix sticky header border bottom color
amadeus May 23, 2026
c8a32f3
Revert Diff Fixes (#743)
amadeus May 25, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@ function getCommentLineClassName(
if (lineType === 'context') {
return 'text-muted-foreground';
}
// The themed chrome sets --diffshub-comment-add-fg / -del-fg with a shade
// chosen from the active Shiki surface's luminance, so addition/deletion
// labels stay legible even on mixed-palette themes (e.g. slack-ochin's
// "light" classification with a dark navy sidebar, where the global
// `dark:` variant would otherwise leave us with low-contrast 700 shades
// on a dark card). The Tailwind shades stay as fallbacks for the
// first-render window before the chrome style applies.
return side === 'additions'
? 'text-emerald-700 dark:text-emerald-400'
: 'text-rose-700 dark:text-rose-400';
? 'text-[var(--diffshub-comment-add-fg,#047857)] dark:text-[var(--diffshub-comment-add-fg,#34d399)]'
: 'text-[var(--diffshub-comment-del-fg,#be123c)] dark:text-[var(--diffshub-comment-del-fg,#fb7185)]';
}

// Wraps a click handler so users can drag-select text inside the row without
Expand Down Expand Up @@ -117,12 +124,24 @@ export const CodeViewCommentsList = memo(function CodeViewCommentsList({
{section.path}
</div>
)}
<div className="rounded-lg border border-[rgb(0_0_0_/_0.1)] dark:border-[rgb(255_255_255_/_0.15)]">
<div className="rounded-lg border border-[var(--diffshub-card-border,rgb(0_0_0_/_0.1))] dark:border-[var(--diffshub-card-border,rgb(255_255_255_/_0.15))]">
{section.comments.map((comment) => (
<button
key={comment.key}
type="button"
className="focus-visible:ring-ring hover:bg-muted bg-card flex w-full cursor-pointer items-start gap-2 border-b border-[rgb(0_0_0_/_0.1)] p-3 text-left text-sm transition-colors outline-none first:rounded-t-lg last:rounded-b-lg last:border-b-0 focus-visible:ring-2 dark:border-[rgb(255_255_255_/_0.15)] dark:bg-neutral-800 dark:hover:bg-[var(--diffshub-sidebar-bg)]"
// Card surface, hover, and border come from the themed
// chrome (set on the sidebar wrapper) so cards stay
// on-palette for mixed-light/dark themes like slack-ochin
// (light-typed but uses a dark navy sidebar). The
// hardcoded fallbacks cover the brief window before the
// Shiki theme resolves on first render.
// No `transition-colors` here: the bg / border / text
// colors are driven by CSS variables that flip the entire
// chrome on every theme swap, so a smooth color transition
// on each card visibly trails the rest of the UI (header,
// file tree, diff body) which snap instantly. Hover bg is
// snappy enough without an interpolated transition.
className="focus-visible:ring-ring flex w-full cursor-pointer items-start gap-2 border-b border-[var(--diffshub-card-border,rgb(0_0_0_/_0.1))] bg-[var(--diffshub-card-bg,var(--color-card))] p-3 text-left text-sm outline-none first:rounded-t-lg last:rounded-b-lg last:border-b-0 hover:bg-[var(--diffshub-card-hover-bg,var(--color-muted))] focus-visible:ring-2 dark:border-[var(--diffshub-card-border,rgb(255_255_255_/_0.15))]"
onClick={(event) =>
handleRowClick(event, () => onSelectComment?.(comment))
}
Expand Down
39 changes: 17 additions & 22 deletions apps/docs/app/(diffshub)/(view)/_components/CodeViewFileTree.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
'use client';

import { type DiffsThemeNames } from '@pierre/diffs';
import { useStableCallback } from '@pierre/diffs/react';
import darkSoftTheme from '@pierre/theme/pierre-dark-soft';
import lightSoftTheme from '@pierre/theme/pierre-light-soft';
import type {
FileTreeBatchOperation,
FileTree as FileTreeModel,
FileTreeOptions,
} from '@pierre/trees';
import { themeToTreeStyles } from '@pierre/trees';
import { FileTree, useFileTree } from '@pierre/trees/react';
import {
type CSSProperties,
Expand All @@ -26,11 +24,7 @@ import {
getInitialBatchSize,
} from './constants';
import type { CodeViewFileTreeSource } from './types';
import { useTheme } from '@/components/theme-provider';

// Computed once at module level so they're never re-derived on every render.
const LIGHT_SOFT_TREE_STYLES = themeToTreeStyles(lightSoftTheme);
const DARK_SOFT_TREE_STYLES = themeToTreeStyles(darkSoftTheme);
import { useResolvedTreeThemeStyles } from './useResolvedTreeThemeStyles';
type FileTreeSortComparator = Exclude<
NonNullable<FileTreeOptions['sort']>,
'default'
Expand All @@ -39,19 +33,23 @@ type FileTreeSortComparator = Exclude<
// follows the same patch path sequence that drives the code view.
const PRESERVE_INPUT_ORDER_SORT: FileTreeSortComparator = () => 0;

// These override vars take precedence over the --trees-theme-* vars set by
// themeToTreeStyles, so diffshub-specific layout tweaks are always preserved.
// Layout-only overrides. Colors flow through from the resolved Shiki theme
// (via themeToTreeStyles) so the sidebar matches the diff theme, but the
// density and padding stay tuned for the diffshub layout regardless of
// which theme the user picks. `--trees-git-renamed-color-override` is kept
// because most Shiki themes don't define a "renamed" decoration color.
const DENSITY_OVERRIDE_STYLES = {
'--trees-bg-override': 'var(--diffshub-sidebar-bg)',
'--trees-density-override': 0.8,
'--trees-selected-fg-override': 'light-dark(#1c1c1e, #f0f0f2)',
'--trees-padding-inline-override': 8,
'--trees-bg-muted': 'light-dark(#f5f5f5, #262626)',
'--trees-search-bg-override': 'light-dark(#fff, #262626)',
'--trees-git-renamed-color-override': 'light-dark(#007aff, #007aff)',
} as CSSProperties;

interface CodeViewFileTreeProps {
// Themes selected in the header's theme switcher. Resolved via shiki
// (cached after first use) and mapped to tree CSS variables so the
// sidebar tracks the same Shiki theme as the diff viewer.
darkTheme: DiffsThemeNames;
lightTheme: DiffsThemeNames;
// Callback invoked with the underlying tree model once it's mounted, and
// again with `null` on unmount. Lets parents drive imperative APIs like
// search open/close without owning the model creation.
Expand All @@ -61,19 +59,16 @@ interface CodeViewFileTreeProps {
}

export const CodeViewFileTree = memo(function CodeViewFileTree({
darkTheme,
lightTheme,
onModelReady,
onSelectItem,
source,
}: CodeViewFileTreeProps) {
const { resolvedTheme } = useTheme();
const activeStyles = useResolvedTreeThemeStyles(lightTheme, darkTheme);
const themeStyles = useMemo(
() => ({
...(resolvedTheme === 'dark'
? DARK_SOFT_TREE_STYLES
: LIGHT_SOFT_TREE_STYLES),
...DENSITY_OVERRIDE_STYLES,
}),
[resolvedTheme]
() => ({ ...activeStyles, ...DENSITY_OVERRIDE_STYLES }),
[activeStyles]
);
const sourceRef = useRef(source);
const previousSourceRef = useRef(source);
Expand Down
Loading
Loading