web: fix scrollbar styling in sidebar

This commit is contained in:
Abdullah Atta
2025-03-03 11:51:45 +05:00
parent 0220bb4040
commit 2f890fd86b
6 changed files with 114 additions and 18 deletions

View File

@@ -33,10 +33,11 @@ import {
} from "./list-profiles";
import Announcements from "../announcements";
import { ListLoader } from "../loaders/list-loader";
import ScrollContainer from "../scroll-container";
import ScrollContainer, { ScrollContainerProps } from "../scroll-container";
import { useKeyboardListNavigation } from "../../hooks/use-keyboard-list-navigation";
import { VirtualizedGrouping, GroupingKey, Item } from "@notesnook/core";
import {
Components,
FlatScrollIntoViewLocation,
ItemProps,
ScrollerProps,
@@ -49,8 +50,9 @@ import { AppEventManager, AppEvents } from "../../common/app-events";
export const CustomScrollbarsVirtualList = forwardRef<
HTMLDivElement,
ScrollerProps
ScrollerProps & ScrollContainerProps
>(function CustomScrollbarsVirtualList(props, ref) {
console.log({ props, ref });
return (
<ScrollContainer
{...props}
@@ -76,10 +78,21 @@ type ListContainerProps = {
button?: {
onClick: () => void;
};
Scroller?: Components["Scroller"];
} & SxProp;
function ListContainer(props: ListContainerProps) {
const { type, group, items, context, refresh, header, button, compact, sx } =
props;
const {
type,
group,
items,
context,
refresh,
header,
button,
compact,
sx,
Scroller
} = props;
const [focusedGroupIndex, setFocusedGroupIndex] = useState(-1);
@@ -213,7 +226,7 @@ function ListContainer(props: ListContainerProps) {
onBlur={() => setFocusedGroupIndex(-1)}
onKeyDown={(e) => onKeyDown(e.nativeEvent)}
components={{
Scroller: CustomScrollbarsVirtualList,
Scroller: Scroller || CustomScrollbarsVirtualList,
Item: VirtuosoItem,
Header: ListHeader
}}

View File

@@ -21,28 +21,30 @@ import React, { PropsWithChildren, useLayoutEffect } from "react";
import { MacScrollbar, MacScrollbarProps } from "mac-scrollbar";
import "mac-scrollbar/dist/mac-scrollbar.css";
type ScrollContainerProps = {
export type ScrollContainerProps = {
style?: React.CSSProperties;
forwardedRef?: (ref: HTMLDivElement | null) => void;
};
} & MacScrollbarProps;
const ScrollContainer = ({
children,
forwardedRef,
style,
...props
}: PropsWithChildren<ScrollContainerProps>) => {
return (
<MacScrollbar
suppressScrollX
minThumbSize={40}
{...props}
ref={(div) => {
forwardedRef && forwardedRef(div as HTMLDivElement);
}}
style={{
position: "relative",
height: "100%"
height: "100%",
...style
}}
suppressScrollX
minThumbSize={40}
>
{children}
</MacScrollbar>

View File

@@ -0,0 +1,41 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { forwardRef } from "react";
import { ScrollerProps } from "react-virtuoso";
import ScrollContainer from "./scroll-container";
export const SidebarScroller = forwardRef<HTMLDivElement, ScrollerProps>(
function CustomScroller(props, ref) {
return (
<ScrollContainer
{...props}
trackStyle={() => ({
width: 3
})}
thumbStyle={() => ({ width: 3 })}
suppressScrollX={true}
forwardedRef={(sRef) => {
if (typeof ref === "function") ref(sRef);
else if (ref) ref.current = sRef;
}}
/>
);
}
);

View File

@@ -19,7 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useEffect, useImperativeHandle, useRef, useState } from "react";
import { usePersistentState } from "../../hooks/use-persistent-state";
import { ItemProps, Virtuoso, VirtuosoHandle } from "react-virtuoso";
import {
Components,
ItemProps,
Virtuoso,
VirtuosoHandle
} from "react-virtuoso";
import { useKeyboardListNavigation } from "../../hooks/use-keyboard-list-navigation";
import { CustomScrollbarsVirtualList, waitForElement } from "../list-container";
@@ -58,6 +63,8 @@ type TreeViewProps<T> = {
deselectAll?: () => void;
isSelected?: (id: string) => boolean;
style?: React.CSSProperties;
Scroller?: Components["Scroller"];
};
export function VirtualizedTree<T>(props: TreeViewProps<T>) {
const {
@@ -75,7 +82,7 @@ export function VirtualizedTree<T>(props: TreeViewProps<T>) {
deselectAll,
bulkSelect,
testId,
style
Scroller
} = props;
const [nodes, setNodes] = useState<TreeNode<T>[]>([]);
const [expandedIds, setExpandedIds] = usePersistentState<ExpandedIds>(
@@ -205,7 +212,7 @@ export function VirtualizedTree<T>(props: TreeViewProps<T>) {
onMouseUp
}}
components={{
Scroller: CustomScrollbarsVirtualList,
Scroller: (Scroller as any) || CustomScrollbarsVirtualList,
Item: VirtuosoItem,
EmptyPlaceholder: Placeholder
}}

View File

@@ -19,7 +19,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Notebook as NotebookType, VirtualizedGrouping } from "@notesnook/core";
import { Box, Flex, Input, Text } from "@theme-ui/components";
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import {
forwardRef,
useEffect,
useLayoutEffect,
useRef,
useState
} from "react";
import { db } from "../common/db";
import { store, useStore } from "../stores/notebook-store";
import { useStore as useSelectionStore } from "../stores/selection-store";
@@ -33,6 +39,10 @@ import {
import { ListLoader } from "../components/loaders/list-loader";
import { debounce } from "@notesnook/common";
import { strings } from "@notesnook/intl";
import { CustomScrollbarsVirtualList } from "../components/list-container";
import { ScrollerProps } from "react-virtuoso";
import ScrollContainer from "../components/scroll-container";
import { SidebarScroller } from "../components/sidebar-scroller";
export function Notebooks() {
const roots = useStore((store) => store.notebooks);
@@ -81,7 +91,16 @@ export function Notebooks() {
return (
<>
<Box id="notebooks" sx={{ mx: 1, flex: 1 }}>
<Box
id="notebooks"
sx={{
flex: 1,
'[data-viewport-type="element"]': {
px: 1,
width: `calc(100% - ${2 * 6}px) !important`
}
}}
>
<VirtualizedTree
testId="notebooks-list"
rootId={"root"}
@@ -153,6 +172,7 @@ export function Notebooks() {
expand={expand}
/>
)}
Scroller={SidebarScroller}
/>
</Box>
<Input

View File

@@ -23,9 +23,12 @@ import Placeholder from "../components/placeholders";
import { db } from "../common/db";
import { ListLoader } from "../components/loaders/list-loader";
import { Flex, Input } from "@theme-ui/components";
import { useEffect, useState } from "react";
import { forwardRef, useEffect, useState } from "react";
import { debounce } from "@notesnook/common";
import { Tag, VirtualizedGrouping } from "@notesnook/core";
import ScrollContainer from "../components/scroll-container";
import { ScrollerProps } from "react-virtuoso";
import { SidebarScroller } from "../components/sidebar-scroller";
function Tags() {
const tags = useStore((store) => store.tags);
@@ -39,14 +42,24 @@ function Tags() {
if (!items) return <ListLoader />;
return (
<Flex variant="columnFill" id="tags">
<Flex
variant="columnFill"
id="tags"
sx={{
flex: 1,
'[data-viewport-type="element"]': {
px: 1,
width: `calc(100% - ${2 * 6}px) !important`
}
}}
>
<ListContainer
type="tags"
sx={{ mx: 1 }}
refresh={refresh}
items={items}
placeholder={<Placeholder context="tags" />}
header={<></>}
Scroller={SidebarScroller}
/>
<Input
variant="clean"