feat(frontend): replace native scrollbar styling with OverlayScrollbars

Adopt OverlayScrollbars for cross-platform consistent overlay scrollbars
with auto-hide on pointer leave, hover grow effect, and click-to-scroll.

- Add overlayscrollbars + overlayscrollbars-react dependencies
- Rewrite ScrollArea component from Radix to OverlayScrollbars wrapper
- Define custom theme `os-theme-codeg` in globals.css (6px → 8px on hover)
- Initialize body-level overlay scrollbar via OverlayScrollbarsInit
- Migrate all scrollbar-thin / scrollbar-thin-edge usages to ScrollArea
- Keep native .scrollbar-thin fallback for virtua scroll containers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-12 20:16:46 +08:00
parent ad50cc28fc
commit b1bfc244d1
13 changed files with 411 additions and 335 deletions

View File

@@ -2,6 +2,7 @@
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "@xterm/xterm/css/xterm.css";
@import "overlayscrollbars/overlayscrollbars.css";
@custom-variant dark (&:is(.dark *));
@@ -1002,14 +1003,28 @@
}
}
/* Unified scrollbar style for scrollable containers.
Thin overlay scrollbar — no gutter reserved, no layout shift. */
.scrollbar-thin,
.scrollbar-thin-edge {
/* Native fallback for containers that cannot use OverlayScrollbars (e.g. virtua) */
.scrollbar-thin {
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
/* OverlayScrollbars custom theme */
.os-theme-codeg {
--os-size: 6px;
--os-handle-bg: var(--border);
--os-handle-bg-hover: var(--muted-foreground);
--os-handle-bg-active: var(--muted-foreground);
--os-handle-border-radius: 999px;
--os-handle-perpendicular-size: 100%;
--os-handle-perpendicular-size-hover: 100%;
--os-handle-perpendicular-size-active: 100%;
}
.os-theme-codeg:hover {
--os-size: 8px;
}
/* Streamdown code blocks: dark mode via shiki dual-theme CSS variables */
.dark [data-streamdown="code-block-body"] {
background-color: var(--shiki-dark-bg, var(--sdm-bg, transparent)) !important;

View File

@@ -10,6 +10,7 @@ import { ThemeProvider } from "@/components/theme-provider"
import { toIntlLocale } from "@/lib/i18n"
import { APPEARANCE_INIT_SCRIPT } from "@/lib/appearance-script"
import { AppearanceProvider } from "@/components/appearance-provider"
import { OverlayScrollbarsInit } from "@/components/overlay-scrollbars-init"
const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
@@ -68,7 +69,10 @@ export default async function RootLayout({
enableSystem
disableTransitionOnChange
>
<AppearanceProvider>{children}</AppearanceProvider>
<AppearanceProvider>
<OverlayScrollbarsInit />
{children}
</AppearanceProvider>
</ThemeProvider>
</AppI18nProvider>
</NextIntlClientProvider>