您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
TOC 左侧固定
- // ==UserScript==
- // @name Notion Sticky TOC (2022 Available)
- // @name:zh-CN Notion 固定左侧 TOC (2022 亲测可用)
- // @namespace https://github.com/soraliu
- // @version 0.6.0
- // @description Set Notion TOC Sticky.
- // @description:zh-cn TOC 左侧固定
- // @author Sora Liu<soraliu.dev@gmail.com>
- // @match https://www.notion.so/*
- // @grant none
- // @license MIT
- // ==/UserScript==
- /* jshint esversion:6 */
- (function() {
- 'use strict';
- // selectors
- const SELECTOR_NOTION_APP = 'notion-app';
- const SELECTOR_NOTION_SCROLLER = '.notion-scroller';
- const SELECTOR_NOTION_TOC = '.notion-table_of_contents-block';
- const SELECTOR_MODAL_PAGE = '.notion-peek-renderer'; // the selector which used to check if the page is in any modal
- // toc config
- const TOC_CONFIG_WIDTH = '168px';
- const TOC_CONFIG_LEFT = '256px';
- /* Helper function to wait for the element ready */
- const waitFor = (...selectors) => new Promise(resolve => {
- const delay = 500;
- const f = () => {
- const elements = selectors.map(selector => document.querySelector(selector));
- if (elements.every(element => element != null)) {
- resolve(elements);
- } else {
- setTimeout(f, delay);
- }
- };
- f();
- });
- // for performance
- const LISTENED_SELECTORS = new WeakMap();
- const addScrollListener = (selectors, fn) => {
- let lastKnownScrollPosition = 0;
- let ticking = false;
- fn(lastKnownScrollPosition); // init once
- selectors.forEach(selector => {
- if (LISTENED_SELECTORS.has(selector)) {
- return;
- }
- // set listened
- LISTENED_SELECTORS.set(selector, true);
- selector.addEventListener('scroll', function(e) {
- lastKnownScrollPosition = window.scrollY;
- if (!ticking) {
- window.requestAnimationFrame(function() {
- fn(lastKnownScrollPosition);
- ticking = false;
- });
- ticking = true;
- }
- }, false);
- });
- };
- const callback = function(mutations) {
- waitFor(SELECTOR_NOTION_TOC).then(([el]) => {
- const toc = document.querySelector(SELECTOR_NOTION_TOC);
- const modal = document.querySelector(SELECTOR_MODAL_PAGE);
- if (!modal && toc) {
- toc.style.position = 'fixed';
- toc.style.top = '50%';
- toc.style.transform= 'translateY(-50%)';
- toc.style.zIndex = 999
- toc.style.maxHeight = 'calc(100vh - 168px)'
- toc.style.overflowY = 'auto'
- const sidebarWidth = window.innerWidth - toc.closest(SELECTOR_NOTION_SCROLLER).clientWidth
- toc.style.left = `${sidebarWidth + 16}px`;
- toc.style.width = `${(toc.closest(SELECTOR_NOTION_SCROLLER).clientWidth - 900) / 2}px`
- }
- });
- };
- const observer = new MutationObserver(callback);
- observer.observe(document.getElementById(SELECTOR_NOTION_APP), { childList: true, subtree: true } );
- })();