mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 11:06:23 +00:00
refactor: 调整滚动条样式,删除OverlayScrollbar组件及其样式
This commit is contained in:
@ -134,15 +134,15 @@ html, body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 4px; /* 垂直滚动条宽度 */
|
width: 2px; /* 垂直滚动条宽度 */
|
||||||
height: 4px; /* 水平滚动条高度 */
|
height: 2px; /* 水平滚动条高度 */
|
||||||
background: transparent; /* 滚动条轨道背景 */
|
background: transparent; /* 滚动条轨道背景 */
|
||||||
position: absolute; /* 实际不会影响内容布局 */
|
position: absolute; /* 实际不会影响内容布局 */
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: rgba(0,0,0,0.15); /* 滚动条滑块颜色 */
|
background: rgba(0,0,0,0.15); /* 滚动条滑块颜色 */
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
@ -19,6 +19,7 @@ import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/s
|
|||||||
import { Menu } from "lucide-react"
|
import { Menu } from "lucide-react"
|
||||||
import { ThemeModeToggle } from "../common/theme-toggle"
|
import { ThemeModeToggle } from "../common/theme-toggle"
|
||||||
import { AvatarWithDropdownMenu } from "./avatar-with-dropdown-menu"
|
import { AvatarWithDropdownMenu } from "./avatar-with-dropdown-menu"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const navbarMenuComponents = [
|
const navbarMenuComponents = [
|
||||||
{
|
{
|
||||||
@ -70,14 +71,14 @@ function NavMenuCenter() {
|
|||||||
{navbarMenuComponents.map((item) => (
|
{navbarMenuComponents.map((item) => (
|
||||||
<NavigationMenuItem key={item.title}>
|
<NavigationMenuItem key={item.title}>
|
||||||
{item.href ? (
|
{item.href ? (
|
||||||
<NavigationMenuLink asChild className={navigationMenuTriggerStyle()}>
|
<NavigationMenuLink asChild className={cn(navigationMenuTriggerStyle(), "bg-transparent")}>
|
||||||
<Link href={item.href} className="flex items-center gap-1 font-extrabold">
|
<Link href={item.href} className="flex items-center gap-1 font-extrabold">
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
) : item.children ? (
|
) : item.children ? (
|
||||||
<>
|
<>
|
||||||
<NavigationMenuTrigger className="flex items-center gap-1 font-extrabold">
|
<NavigationMenuTrigger className="flex items-center gap-1 font-extrabold bg-transparent">
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
</NavigationMenuTrigger>
|
</NavigationMenuTrigger>
|
||||||
<NavigationMenuContent>
|
<NavigationMenuContent>
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import styles from "./overlay-scrollbar.module.css";
|
|
||||||
|
|
||||||
export default function OverlayScrollbar({
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
style,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
style?: React.CSSProperties;
|
|
||||||
}) {
|
|
||||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const thumbRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const [thumbHeight, setThumbHeight] = useState(0);
|
|
||||||
const [thumbTop, setThumbTop] = useState(0);
|
|
||||||
const dragging = useRef(false);
|
|
||||||
const startY = useRef(0);
|
|
||||||
const startScrollTop = useRef(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const el = scrollRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
const update = () => {
|
|
||||||
const visible = el.clientHeight;
|
|
||||||
const total = el.scrollHeight;
|
|
||||||
const ratio = visible / Math.max(total, 1);
|
|
||||||
const h = Math.max(ratio * visible, 24);
|
|
||||||
const top = total > visible ? (el.scrollTop / (total - visible)) * (visible - h) : 0;
|
|
||||||
setThumbHeight(h);
|
|
||||||
setThumbTop(isFinite(top) ? top : 0);
|
|
||||||
|
|
||||||
if (thumbRef.current) {
|
|
||||||
const percent = total > visible ? Math.round((el.scrollTop / (total - visible)) * 100) : 0;
|
|
||||||
thumbRef.current.setAttribute("aria-valuenow", String(percent));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
update();
|
|
||||||
el.addEventListener("scroll", update, { passive: true });
|
|
||||||
window.addEventListener("resize", update);
|
|
||||||
const obs = new MutationObserver(update);
|
|
||||||
obs.observe(el, { childList: true, subtree: true });
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
el.removeEventListener("scroll", update);
|
|
||||||
window.removeEventListener("resize", update);
|
|
||||||
obs.disconnect();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const onMove = (e: MouseEvent) => {
|
|
||||||
if (!dragging.current || !scrollRef.current) return;
|
|
||||||
const el = scrollRef.current;
|
|
||||||
const visible = el.clientHeight;
|
|
||||||
const total = el.scrollHeight;
|
|
||||||
const h = thumbHeight;
|
|
||||||
const delta = e.clientY - startY.current;
|
|
||||||
const proportion = delta / Math.max(visible - h, 1);
|
|
||||||
el.scrollTop = Math.min(Math.max(startScrollTop.current + proportion * (total - visible), 0), total - visible);
|
|
||||||
};
|
|
||||||
const onUp = () => {
|
|
||||||
dragging.current = false;
|
|
||||||
document.body.style.userSelect = "";
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("mousemove", onMove);
|
|
||||||
window.addEventListener("mouseup", onUp);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("mousemove", onMove);
|
|
||||||
window.removeEventListener("mouseup", onUp);
|
|
||||||
};
|
|
||||||
}, [thumbHeight]);
|
|
||||||
|
|
||||||
const onThumbMouseDown = (e: React.MouseEvent) => {
|
|
||||||
dragging.current = true;
|
|
||||||
startY.current = e.clientY;
|
|
||||||
if (scrollRef.current) startScrollTop.current = scrollRef.current.scrollTop;
|
|
||||||
document.body.style.userSelect = "none";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`${styles.container} ${className || ""}`} style={{ position: "relative", ...style }}>
|
|
||||||
<div ref={scrollRef} className={styles.content} tabIndex={0}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.track} aria-hidden={false}>
|
|
||||||
<div
|
|
||||||
ref={thumbRef}
|
|
||||||
role="scrollbar"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-valuemin={0}
|
|
||||||
aria-valuemax={100}
|
|
||||||
className={styles.thumb}
|
|
||||||
style={{ height: thumbHeight, transform: `translateY(${thumbTop}px)` }}
|
|
||||||
onMouseDown={onThumbMouseDown}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
.container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 100%;
|
|
||||||
/* hide native scrollbars but keep scrolling */
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
.content::-webkit-scrollbar {
|
|
||||||
display: none; /* Chrome/Safari */
|
|
||||||
}
|
|
||||||
.track {
|
|
||||||
pointer-events: none; /* track itself not interactive */
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.thumb {
|
|
||||||
pointer-events: auto; /* thumb is interactive */
|
|
||||||
width: 8px;
|
|
||||||
margin-top: 4px;
|
|
||||||
background: rgba(0, 0, 0, 0.32);
|
|
||||||
border-radius: 9999px;
|
|
||||||
transition: background 0.12s ease;
|
|
||||||
}
|
|
||||||
.thumb:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
Reference in New Issue
Block a user