From ca2b18d9da270be8e77ed59ed5177a140f0b747d Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Tue, 7 Jan 2025 00:33:27 -0800 Subject: [PATCH] scrollbar styles recursive --- .../contrib/void/browser/media/void.css | 66 +++++++++++- .../react/src/sidebar-tsx/SidebarChat.tsx | 66 +----------- .../react/src/util/useScrollbarStyles.tsx | 101 ++++++++++++++++++ 3 files changed, 166 insertions(+), 67 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/react/src/util/useScrollbarStyles.tsx diff --git a/src/vs/workbench/contrib/void/browser/media/void.css b/src/vs/workbench/contrib/void/browser/media/void.css index 0ec9730b..41177002 100644 --- a/src/vs/workbench/contrib/void/browser/media/void.css +++ b/src/vs/workbench/contrib/void/browser/media/void.css @@ -75,32 +75,90 @@ + +.void-scrollable-element::-webkit-scrollbar, .void-scrollable-element *::-webkit-scrollbar { width: 14px !important; height: 14px !important; } +.void-scrollable-element::-webkit-scrollbar-track, .void-scrollable-element *::-webkit-scrollbar-track { background: transparent !important; } +.void-scrollable-element::-webkit-scrollbar-thumb, .void-scrollable-element *::-webkit-scrollbar-thumb { background-color: transparent !important; border-radius: 0px !important; } -.void-scrollable-element.show-scrollbar *::-webkit-scrollbar-thumb { - background-color: var(--vscode-scrollbarSlider-background) !important; -} - +.void-scrollable-element::-webkit-scrollbar-thumb:hover, .void-scrollable-element *::-webkit-scrollbar-thumb:hover { background-color: var(--vscode-scrollbarSlider-hoverBackground) !important; } +.void-scrollable-element::-webkit-scrollbar-thumb:active, .void-scrollable-element *::-webkit-scrollbar-thumb:active { background-color: var(--vscode-scrollbarSlider-activeBackground) !important; } +.void-scrollable-element::-webkit-scrollbar-corner, .void-scrollable-element *::-webkit-scrollbar-corner { background-color: transparent !important; } + +.void-scrollable-element.show-scrollbar-0::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-0 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 0%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-1::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-1 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 10%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-2::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-2 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 20%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-3::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-3 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 30%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-4::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-4 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 40%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-5::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-5 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 50%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-6::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-6 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 60%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-7::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-7 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 70%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-8::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-8 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 80%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-9::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-9 *::-webkit-scrollbar-thumb { + background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 90%, transparent) !important; +} + +.void-scrollable-element.show-scrollbar-10::-webkit-scrollbar-thumb, +.void-scrollable-element.show-scrollbar-10 *::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background) !important; +} diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index c7a514e1..e1fc9fc4 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -25,6 +25,7 @@ import { ISidebarStateService } from '../../../sidebarStateService.js'; import { ILLMMessageService } from '../../../../../../../platform/void/common/llmMessageService.js'; import { IModelService } from '../../../../../../../editor/common/services/model.js'; import { SidebarThreadSelector } from './SidebarThreadSelector.js'; +import { useScrollbarStyles } from '../util/useScrollbarStyles.js'; const IconX = ({ size, className = '', ...props }: { size: number, className?: string } & React.SVGProps) => { @@ -416,64 +417,6 @@ const ChatBubble = ({ chatMessage, isLoading }: { } - -const useScrollFade = (ref: React.MutableRefObject) => { - useEffect(() => { - if (!ref.current) return; - - let fadeTimeout: NodeJS.Timeout | null = null; - const parent = ref.current; - const scrollElement = parent.querySelector('[class*="void-overflow-"]'); - if (!scrollElement) return; - - const onMouseEnter = () => { - parent.classList.add('show-scrollbar'); - }; - - const onMouseLeave = () => { - if (fadeTimeout) { - clearTimeout(fadeTimeout); - } - fadeTimeout = setTimeout(() => { - parent.classList.remove('show-scrollbar'); - }, 1000); - }; - - scrollElement.addEventListener('mouseenter', onMouseEnter); - scrollElement.addEventListener('mouseleave', onMouseLeave); - - return () => { - scrollElement.removeEventListener('mouseenter', onMouseEnter); - scrollElement.removeEventListener('mouseleave', onMouseLeave); - if (fadeTimeout) { - clearTimeout(fadeTimeout); - } - }; - }, [ref]); -}; - - -const Test = ({ children, className = "", }: { children: React.ReactNode; className?: string; maxHeight?: string; maxWidth?: string; }) => { - - - const ref = useRef(null) - - useScrollFade(ref) - - return ( -
-
- {children} -
-
- ); -}; - - export const SidebarChat = () => { const inputBoxRef: React.MutableRefObject = useRef(null); @@ -519,6 +462,8 @@ export const SidebarChat = () => { const [formRef, formDimensions] = useResizeObserver() const [historyRef, historyDimensions] = useResizeObserver() + useScrollbarStyles(sidebarRef) + // const [formHeight, setFormHeight] = useState(0) // TODO should use resize observer instead // const [sidebarHeight, setSidebarHeight] = useState(0) const onChangeText = useCallback((newStr: string) => { setInstructions(newStr) }, [setInstructions]) @@ -636,11 +581,6 @@ export const SidebarChat = () => { ref={sidebarRef} className={`w-full h-full`} > - - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa - {/* thread selector */}
) => { + + useEffect(() => { + if (!containerRef.current) return; + + // Create selector for specific overflow classes + const overflowSelector = [ + '[class*="overflow-auto"]', + '[class*="overflow-x-auto"]', + '[class*="overflow-y-auto"]' + ].join(','); + + // Get all matching elements within the container, including the container itself + const scrollElements = [ + ...(containerRef.current.matches(overflowSelector) ? [containerRef.current] : []), + ...Array.from(containerRef.current.querySelectorAll(overflowSelector)) + ]; + + // Apply styles and listeners to each scroll element + scrollElements.forEach(element => { + // Add the scrollable class directly to the overflow element + element.classList.add('void-scrollable-element'); + + let fadeTimeout: NodeJS.Timeout | null = null; + let fadeInterval: NodeJS.Timeout | null = null; + + const fadeIn = () => { + if (fadeInterval) clearInterval(fadeInterval); + + let step = 0; + fadeInterval = setInterval(() => { + if (step <= 10) { + element.classList.remove(`show-scrollbar-${step - 1}`); + element.classList.add(`show-scrollbar-${step}`); + step++; + } else { + clearInterval(fadeInterval!); + } + }, 10); + }; + + const fadeOut = () => { + if (fadeInterval) clearInterval(fadeInterval); + + let step = 10; + fadeInterval = setInterval(() => { + if (step >= 0) { + element.classList.remove(`show-scrollbar-${step + 1}`); + element.classList.add(`show-scrollbar-${step}`); + step--; + } else { + clearInterval(fadeInterval!); + } + }, 60); + }; + + const onMouseEnter = () => { + if (fadeTimeout) clearTimeout(fadeTimeout); + if (fadeInterval) clearInterval(fadeInterval); + fadeIn(); + }; + + const onMouseLeave = () => { + if (fadeTimeout) clearTimeout(fadeTimeout); + fadeTimeout = setTimeout(() => { + fadeOut(); + }, 10); + }; + + element.addEventListener('mouseenter', onMouseEnter); + element.addEventListener('mouseleave', onMouseLeave); + + // Store cleanup function + const cleanup = () => { + element.removeEventListener('mouseenter', onMouseEnter); + element.removeEventListener('mouseleave', onMouseLeave); + if (fadeTimeout) clearTimeout(fadeTimeout); + if (fadeInterval) clearInterval(fadeInterval); + element.classList.remove('void-scrollable-element'); + // Remove any remaining show-scrollbar classes + for (let i = 0; i <= 10; i++) { + element.classList.remove(`show-scrollbar-${i}`); + } + }; + + // Store the cleanup function on the element for later use + (element as any).__scrollbarCleanup = cleanup; + }); + + return () => { + // Clean up all scroll elements + scrollElements.forEach(element => { + if ((element as any).__scrollbarCleanup) { + (element as any).__scrollbarCleanup(); + } + }); + }; + }, [containerRef]); +};