11// https://vitepress.dev/guide/custom-theme
2- import { render , h } from "vue" ;
2+ import { render , h , onMounted } from "vue" ;
33import type { Theme } from "vitepress" ;
44import DefaultTheme from "vitepress/theme" ;
55import BackToTop from "../../../components/internal/BackToTop.vue" ;
@@ -24,6 +24,10 @@ import "@nolebase/vitepress-plugin-inline-link-preview/client/style.css";
2424import "@nolebase/vitepress-plugin-highlight-targeted-heading/client/style.css" ;
2525import "@nolebase/vitepress-plugin-enhanced-mark/client/style.css" ;
2626
27+ import { OverlayScrollbars } from "overlayscrollbars" ;
28+ import "overlayscrollbars/overlayscrollbars.css" ;
29+ import "./overlayscrollbars.css" ;
30+
2731function addBackTotop ( ) {
2832 render (
2933 h ( BackToTop , {
@@ -33,6 +37,78 @@ function addBackTotop() {
3337 ) ;
3438}
3539
40+ function initCustomScrollbar ( ) {
41+ const bodyElement = document . querySelector ( "body" ) ;
42+ if ( ! bodyElement ) return ;
43+
44+ OverlayScrollbars (
45+ { target : bodyElement , cancel : { nativeScrollbarsOverlaid : true } } ,
46+ {
47+ scrollbars : {
48+ theme : "os-theme-dark" ,
49+ autoHide : "move" ,
50+ autoHideDelay : 500 ,
51+ autoHideSuspend : false ,
52+ } ,
53+ } ,
54+ ) ;
55+
56+ const markInitialized = ( el : HTMLElement ) =>
57+ el . setAttribute ( "data-scrollbar-initialized" , "true" ) ;
58+ const isInitialized = ( el : Element ) =>
59+ ( el as HTMLElement ) . hasAttribute ( "data-scrollbar-initialized" ) ;
60+
61+ const initOnElement = ( el : HTMLElement ) => {
62+ if ( isInitialized ( el ) ) return ;
63+
64+ if ( el . classList . contains ( "VPSidebar" ) ) {
65+ OverlayScrollbars (
66+ { target : el , cancel : { nativeScrollbarsOverlaid : true } } ,
67+ {
68+ scrollbars : {
69+ theme : "os-theme-dark" ,
70+ autoHide : "leave" ,
71+ autoHideDelay : 500 ,
72+ autoHideSuspend : false ,
73+ } ,
74+ } ,
75+ ) ;
76+ markInitialized ( el ) ;
77+ }
78+ } ;
79+
80+ const observer = new IntersectionObserver (
81+ ( entries , obs ) => {
82+ entries . forEach ( ( entry ) => {
83+ if ( entry . isIntersecting ) {
84+ initOnElement ( entry . target as HTMLElement ) ;
85+ obs . unobserve ( entry . target ) ;
86+ }
87+ } ) ;
88+ } ,
89+ { root : null , rootMargin : "100px" , threshold : 0.1 } ,
90+ ) ;
91+
92+ document
93+ . querySelectorAll < HTMLElement > ( ".VPSidebar" )
94+ . forEach ( ( el ) => observer . observe ( el ) ) ;
95+
96+ const mo = new MutationObserver ( ( mutations ) => {
97+ for ( const m of mutations ) {
98+ m . addedNodes . forEach ( ( n ) => {
99+ if ( ! ( n instanceof HTMLElement ) ) return ;
100+ if ( n . matches ( ".VPSidebar" ) && ! isInitialized ( n ) ) {
101+ observer . observe ( n ) ;
102+ }
103+ n . querySelectorAll < HTMLElement > ( ".VPSidebar" ) . forEach ( ( el ) => {
104+ if ( ! isInitialized ( el ) ) observer . observe ( el ) ;
105+ } ) ;
106+ } ) ;
107+ }
108+ } ) ;
109+ mo . observe ( document . documentElement , { childList : true , subtree : true } ) ;
110+ }
111+
36112function addDetailsAnimation ( ) {
37113 document
38114 . querySelectorAll ( "details" )
@@ -53,6 +129,8 @@ export default {
53129 } ,
54130 enhanceApp ( { app, router, siteData } ) {
55131 if ( typeof window !== "undefined" ) {
132+ initCustomScrollbar ( ) ;
133+
56134 window . addEventListener ( "load" , ( ) => {
57135 addBackTotop ( ) ;
58136 } ) ;
0 commit comments