├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── README.zh-CN.md ├── babel.config.js ├── commitlint.config.js ├── package-lock.json ├── package.json ├── patches ├── @vue+cli-service+4.5.9.patch └── readme.md ├── public ├── _locales │ ├── en │ │ └── messages.json │ ├── ja-jp │ │ └── messages.json │ ├── ko │ │ └── messages.json │ ├── locales.json │ ├── uk │ │ └── messages.json │ └── zh-cn │ │ └── messages.json ├── browser-extension.html ├── css │ ├── md.css │ └── privacy.css ├── favicon.ico ├── icons │ ├── notionx -128.png │ ├── notionx-white-128.png │ ├── notionx-white.png │ └── notionx.png ├── index.html ├── index.template.html ├── preview │ ├── 1280x800-hover.png │ ├── 1280x800-p1.png │ ├── 1280x800-p2.png │ ├── 1280x800-p3.png │ ├── 1280x800-p4.png │ ├── 1280x800-p5.png │ ├── 1280x800-pinned.png │ ├── 1400x560.png │ ├── 440x280.png │ ├── 640x400.png │ ├── 920x680.png │ ├── v2.0.0 │ │ ├── 1280 800.png │ │ ├── 1280x800-ppt-p1.png │ │ ├── 1280x800-ppt-p2.png │ │ ├── 1400 560.png │ │ ├── 440 280 main.png │ │ ├── 440 280.png │ │ ├── 640 400 2.png │ │ ├── 640 400.png │ │ └── 920 680.png │ └── v2.1.0 │ │ ├── 1280 800.png │ │ ├── 1280x800-ppt-p1.png │ │ ├── 1280x800-ppt-p2-ch.png │ │ ├── 1280x800-ppt-p2.png │ │ ├── 1400 560.png │ │ ├── 440 280 main.png │ │ ├── 440 280.png │ │ ├── 640 400 2.png │ │ ├── 640 400.png │ │ └── 920 680.png └── privacy.html ├── src ├── App.vue ├── assets │ ├── css │ │ ├── font.css │ │ ├── inter-ui-bold.woff │ │ ├── inter-ui-medium.woff │ │ └── inter-ui-regular.woff │ ├── icon │ │ ├── notionx-white.png │ │ └── notionx.png │ └── svg │ │ ├── about.svg │ │ ├── apple.svg │ │ ├── close.svg │ │ ├── collapse.svg │ │ ├── download.svg │ │ ├── error.svg │ │ ├── expand.svg │ │ ├── firefox.svg │ │ ├── github.svg │ │ ├── google.svg │ │ ├── index.js │ │ ├── keyboard.svg │ │ ├── link-w.svg │ │ ├── link.svg │ │ ├── list-all.svg │ │ ├── list-check.svg │ │ ├── list.svg │ │ ├── loading.svg │ │ ├── notion.svg │ │ ├── notionx-svg.svg │ │ ├── notionx-white.svg │ │ ├── notionx.svg │ │ ├── option.svg │ │ ├── pin.svg │ │ ├── reset.svg │ │ ├── right-arrow.svg │ │ ├── setting.svg │ │ ├── toc.svg │ │ ├── top.svg │ │ └── windows.svg ├── background.js ├── components │ ├── Tab.vue │ ├── TabPanel.vue │ └── Toogle.vue ├── content-scripts │ ├── content-script.js │ ├── content.less │ ├── core.js │ └── template.js ├── main.js ├── manifest.json ├── options │ ├── App.vue │ └── main.js ├── popup │ ├── App.vue │ ├── index.scss │ ├── main.js │ └── page │ │ ├── AboutPage.vue │ │ ├── OptionPage.vue │ │ └── ShortcutPage.vue ├── router │ └── index.js ├── standalone │ └── main.js ├── store │ ├── index.js │ └── option.js ├── utils │ ├── Actions.js │ ├── constant.js │ ├── i18n.js │ ├── shortcuts.json │ ├── svg.js │ └── util.js └── views │ ├── About.vue │ └── Home.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | webextensions: true, 6 | }, 7 | extends: [ 8 | 'plugin:vue/essential', 9 | '@vue/standard', 10 | ], 11 | parserOptions: { 12 | parser: 'babel-eslint', 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 17 | 'linebreak-style': 'off', 18 | 'comma-dangle': 'off', 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | # Vue Browser Extension Output 26 | *.pem 27 | *.pub 28 | *.zip 29 | /artifacts 30 | 31 | /.history -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | semi: false 2 | singleQuote: true 3 | printWidth: 80 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | install: 5 | - npm install 6 | script: 7 | - npm run serve -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](./README.zh-CN.md) 2 | 3 | ![NotionX](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121142800.png) 4 | 5 | [[toc]] 6 | 7 | ## v2.1.3 Features (2021.08.01) 8 | 9 | ### [New Feature] Generate index for Header blocks 10 | 11 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803113702.gif) 12 | 13 | ### [New Feature] Enable/Disable button for NotionX 14 | 15 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803110849.gif) 16 | 17 | ### [New Feature] SideBar modules can be closed and restored 18 | 19 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803113704.gif) 20 | 21 | ### [New Feature] Hide Table block's 'New' button 22 | 23 | ### [New Feature] Hide the dark mode button in the upper right corner 24 | 25 | ### [New Feature] Add ukrainian locale 26 | 27 | ### [Fix] Page content statistics: count the number of words instead of the number of characters 28 | 29 | ### [Fix] SideBar content flashing problem 30 | 31 | ### [Improvement] Improve performance 32 | 33 | ### [Improvement] split colored text in one block showing in sidebar 34 | 35 | [issue#13@github](https://github.com/scarsu/NotionX/issues/13) By [fcherman](https://github.com/fcherman) 36 | 37 | ## v2.1.0 Features (2021.03.16) 38 | 39 | ### Set Code Language 40 | 41 | Set language for all code blocks in current Notion page 42 | 43 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316163725.gif) 44 | 45 | ### Page Content statistics 46 | 47 | Count the number of words and blocks in current Notion page 48 | 49 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316164115.png) 50 | 51 | ## v2.0.0 Features (2021.02.01) 52 | 53 | ### Dynamic SideBar 54 | 55 | A shortcut directory is automatically generated in the sidebar of the page based on `Heading Block 1-3`, `Toggle Block`, `Database Block`, `Comments` and `Colored Text` in Notion Page. 56 | 57 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123340.gif) 58 | 59 | ### Low Contrast Dark Mode 60 | 61 | Compared to Notion's official dark mode, the built-in dark mode of the extension has a lower visual contrast, which **takes effect globally**, including all contents such as pictures.(to prevent others from spying on your screen maybe) 62 | 63 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192422.gif) 64 | 65 | ### Notion Shortcuts Quick Reference Manual 66 | 67 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123656.gif) 68 | 69 | ### Support for switching NotionX languages 70 | 71 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123835.gif) 72 | 73 | ### Hide comments at the top of the page 74 | 75 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123938.gif) 76 | 77 | ### Switching Notion dark mode 78 | 79 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124031.gif) 80 | 81 | ### Compact Mode:full width + small text 82 | 83 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124158.gif) 84 | 85 | ### Show line numbers in code blocks 86 | 87 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124238.gif) 88 | 89 | ### Open current page in Notion desktop 90 | 91 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124736.gif) 92 | 93 | ### Add a "scroll to top button" in the bottom right corner of the page 94 | 95 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124828.gif) 96 | 97 | ### Prevent table overflow 98 | 99 | Prevent table overflow caused by too large width 100 | 101 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316165317.gif) 102 | 103 | ### Hide NotionX sidebar 104 | 105 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121125002.gif) 106 | 107 | ## v1.0.0 Features (2020.12.15) 108 | 109 | - Auto Side Bar TOC: The TOC of Notion Page will automatically generate in the sidebar of the page,according to Heading Block 1-3 in Notion Page. 110 | - Dark Mode: Compared with Notion's official dark mode, the built-in dark mode of the extension has a lower visual contrast, which takes effect globally, including all contents such as pictures. 111 | 112 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192422.gif) 113 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192421.gif) 114 | 115 | ## Usage 116 | 117 | - [Google Store](https://chrome.google.com/webstore/detail/notionx/ojnlojnakahpmkbpigmjhcgibccnidpk) 118 | - [FireFox - Mozilla addons](https://addons.mozilla.org/firefox/addon/notionx/) 119 | - [Download the `crx` file](https://scarsu.oss-cn-shanghai.aliyuncs.com/notionx/notionx_for_notion_v2.1.0.crx) 120 | - [Download the `xpi` file](https://scarsu.oss-cn-shanghai.aliyuncs.com/notionx/notionx_for_notion-2.1.0-fx.xpi) 121 | - Clone this repository,`npm run build` to build package, import the entire `./dist` package in Chrome developer mode. 122 | 123 | ## Maintainers 124 | 125 | [@scarsu](https://github.com/scarsu) 126 | 127 | ## Feedback & Contributing 128 | 129 | - If you have questions or suggestions, [please feedback here⚡️](https://github.com/scarsu/NotionX/discussions/4) 130 | - PRs accepted. 131 | - Translations are welcome, the language related JSON files are in the following directory of the current repository:`/public/_locales` 132 | - contact & discuss: 133 | ![NotionX Contact](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316180026.png) 134 | 135 | ## License 136 | 137 | MIT © 2021 scarsu 138 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | 简体中文 | [English](./README.md) 2 | 3 | ![NotionX](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121142800.png) 4 | 5 | [[toc]] 6 | 7 | ## v2.1.3 Features (2021.08.01) 8 | 9 | ### [New Feature] 自动生成 Header Block 序号 10 | 11 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803113702.gif) 12 | 13 | ### [New Feature] 启用/禁用插件按钮 14 | 15 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803110849.gif) 16 | 17 | ### [New Feature] SideBar模块可关闭和恢复 18 | 19 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210803113704.gif) 20 | 21 | ### [New Feature] 隐藏Table的'New'按钮 22 | 23 | ### [New Feature] 隐藏右上角的暗黑模式按钮 24 | 25 | ### [New Feature] Add ukrainian locale 26 | 27 | ### [Fix] 页面内容统计:计算单词数量而不是字符数量 28 | 29 | ### [Fix] SideBar内容闪现问题 30 | 31 | ### [Improvement] 提升SideBar自动生成性能 32 | 33 | [issue#13@github](https://github.com/scarsu/NotionX/issues/13) By [fcherman](https://github.com/fcherman) 34 | 35 | ## v2.1.0 Features (2021.03.16) 36 | 37 | ### 设置代码块语言 38 | 39 | 为当前页面所有代码块设置语言 40 | 41 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316163725.gif) 42 | 43 | ### 页面内容统计 44 | 45 | 统计Notion Page中block数量以及字数 46 | 47 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316164115.png) 48 | 49 | ## v2.0.0 特性 (2021.02.01) 50 | 51 | ### 响应式侧边栏 52 | 53 | 根据Notion Page中的`Heading Block 1-3`标题、`Toggle Block`折叠块、`Database`数据库、`Comments`评论、`Colored Text`标记颜色的文字,在网页侧边栏自动生成快捷目录。 54 | 55 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123340.gif) 56 | 57 | ### 低对比度暗黑模式 58 | 59 | 相比于Notion官方的暗黑模式,插件内置的暗黑模式的视觉对比度较低,在**网页全局**生效,包括图片等所有的内容。(适合 fish touching,防窥屏) 60 | 61 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192422.gif) 62 | 63 | ### Notion快捷键速查手册 64 | 65 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123656.gif) 66 | 67 | ### 支持切换插件语言 68 | 69 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123835.gif) 70 | 71 | ### 隐藏页面顶部的评论 72 | 73 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121123938.gif) 74 | 75 | ### 切换Notion暗黑模式 76 | 77 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124031.gif) 78 | 79 | ### 紧凑模式:full width + small text 80 | 81 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124158.gif) 82 | 83 | ### 显示代码块中的行号 84 | 85 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124238.gif) 86 | 87 | ### 在桌面端中打开当前页面 88 | 89 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124736.gif) 90 | 91 | ### 在页面右下角添加“滚动至顶部按钮” 92 | 93 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124828.gif) 94 | 95 | ### 阻止表格溢出 96 | 97 | 阻止表格因横向宽度过大导致的尺寸溢出 98 | 99 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121124917.gif) 100 | 101 | ### 隐藏NotionX侧边栏 102 | 103 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210121125002.gif) 104 | 105 | ## v1.0.0 特性 (2020.12.15) 106 | 107 | - 侧边栏TOC: 根据Notion Page中的Heading Block 1-3,在网页侧边栏自动生成Notion文章的TOC目录。 108 | - 暗黑模式: 相比于Notion官方的暗黑模式,插件内置的暗黑模式的视觉对比度较低,在网页全局生效,包括图片等所有的内容。 109 | 110 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192422.gif) 111 | ![preview](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20201126192421.gif) 112 | 113 | ## 使用 114 | 115 | - [Google Store](https://chrome.google.com/webstore/detail/notionx/ojnlojnakahpmkbpigmjhcgibccnidpk) 116 | - [FireFox - Mozilla addons](https://addons.mozilla.org/firefox/addon/notionx/) 117 | - [下载 the `crx` file](https://scarsu.oss-cn-shanghai.aliyuncs.com/notionx/notionx_for_notion_v2.1.0.crx) 118 | - [下载 the `xpi` file](https://scarsu.oss-cn-shanghai.aliyuncs.com/notionx/notionx_for_notion-2.1.0-fx.xpi) 119 | - 下载本仓库,`npm run build`打包后,Chrome开发者模式导入整个包使用 120 | 121 | ## 维护者 122 | 123 | [@scarsu](https://github.com/scarsu) 124 | 125 | ## 反馈 & 贡献 126 | 127 | - 如有问题或者建议,[请在此处反馈⚡️](https://github.com/scarsu/NotionX/discussions/4) 128 | - 欢迎翻译,语言相关JSON文件在当前仓库的以下目录:`/public/_locales` 129 | - 联系&交流: 130 | ![NotionX Contact](https://scarsu.oss-cn-shanghai.aliyuncs.com/picgo20210316180026.png) 131 | 132 | ## License 133 | 134 | MIT © 2021 scarsu 135 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // presets: [ 3 | // '@vue/cli-plugin-babel/preset', 4 | // ], 5 | presets: [ 6 | [ 7 | '@babel/preset-env', 8 | { 9 | modules: false, 10 | targets: { 11 | browsers: [ 12 | '> 1%', 13 | 'last 2 versions', 14 | 'not ie <= 8' 15 | ] 16 | } 17 | } 18 | ] 19 | ], 20 | plugins: [ 21 | 'transform-vue-jsx', 22 | 'babel-plugin-syntax-jsx', 23 | '@babel/plugin-transform-runtime', 24 | '@babel/plugin-syntax-dynamic-import', 25 | '@babel/plugin-syntax-import-meta', 26 | '@babel/plugin-proposal-class-properties', 27 | '@babel/plugin-proposal-json-strings', 28 | ['@babel/plugin-proposal-optional-chaining'], // 解析 可选链式语法 29 | [ 30 | '@babel/plugin-proposal-decorators', 31 | { 32 | legacy: true 33 | } 34 | ], 35 | '@babel/plugin-proposal-function-sent', 36 | '@babel/plugin-proposal-export-namespace-from', 37 | '@babel/plugin-proposal-numeric-separator', 38 | '@babel/plugin-proposal-throw-expressions', 39 | '@babel/plugin-proposal-object-rest-spread' 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'type-enum': [2, 'always', [ 5 | 'feat', // new feature 6 | 'fix', // bug fix 7 | 'perf', // performance improvement 8 | 'docs', // documentation 9 | 'style', // format (changes that do not affect code running) 10 | 'refactor', // neither a new feature nor a code change to fix bug 11 | 'test', // changes related to project testing 12 | 'chore', // changes related to the build process or assistive tools 13 | 'ci', // changes to our CI configuration files and scripts(example Travis,Circle,BrowserStack,SauceLabs) 14 | ]] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notionx", 3 | "version": "2.1.3", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service build --mode development --watch", 7 | "buildIndex": "node ./src/standalone/main", 8 | "build": "vue-cli-service build && node ./src/standalone/main", 9 | "lint": "vue-cli-service lint", 10 | "postinstall": "patch-package" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/scarsu/notionx.git" 15 | }, 16 | "keywords": [ 17 | "Notion" 18 | ], 19 | "author": "ScarSu (https://github.com/scarsu)", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/scarsu/notionx/issues" 23 | }, 24 | "homepage": "http://scarsu.cn/notionx/", 25 | "dependencies": { 26 | "@babel/polyfill": "^7.12.1", 27 | "axios": "^0.20.0", 28 | "core-js": "^3.6.5", 29 | "jquery": "^3.5.1", 30 | "lodash": "^4.17.20", 31 | "vue": "^2.6.11", 32 | "vue-router": "^3.2.0", 33 | "vue-server-renderer": "^2.6.12", 34 | "vuex": "^3.4.0" 35 | }, 36 | "devDependencies": { 37 | "@babel/cli": "^7.12.10", 38 | "@babel/core": "^7.12.10", 39 | "@babel/plugin-proposal-class-properties": "^7.0.0", 40 | "@babel/plugin-proposal-decorators": "^7.0.0", 41 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0", 42 | "@babel/plugin-proposal-function-sent": "^7.0.0", 43 | "@babel/plugin-proposal-json-strings": "^7.0.0", 44 | "@babel/plugin-proposal-numeric-separator": "^7.0.0", 45 | "@babel/plugin-proposal-optional-chaining": "^7.12.7", 46 | "@babel/plugin-proposal-throw-expressions": "^7.0.0", 47 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 48 | "@babel/plugin-syntax-import-meta": "^7.0.0", 49 | "@babel/plugin-syntax-jsx": "^7.0.0", 50 | "@babel/plugin-transform-runtime": "^7.0.0", 51 | "@babel/preset-env": "^7.12.11", 52 | "@commitlint/cli": "^9.1.1", 53 | "@commitlint/config-conventional": "^9.1.1", 54 | "@vue/cli-plugin-babel": "~4.5.0", 55 | "@vue/cli-plugin-eslint": "~4.5.0", 56 | "@vue/cli-plugin-router": "~4.5.0", 57 | "@vue/cli-plugin-vuex": "~4.5.0", 58 | "@vue/cli-service": "~4.5.0", 59 | "@vue/eslint-config-standard": "^5.1.2", 60 | "babel-eslint": "^10.1.0", 61 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 62 | "babel-loader": "^8.0.0", 63 | "babel-plugin-syntax-jsx": "^6.18.0", 64 | "babel-plugin-transform-vue-jsx": "^3.5.0", 65 | "chalk": "^4.1.0", 66 | "copy-webpack-plugin": "^6.3.2", 67 | "eslint": "^6.7.2", 68 | "eslint-plugin-import": "^2.20.2", 69 | "eslint-plugin-node": "^11.1.0", 70 | "eslint-plugin-promise": "^4.2.1", 71 | "eslint-plugin-standard": "^5.0.0", 72 | "eslint-plugin-vue": "^6.2.2", 73 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 74 | "husky": "^4.2.5", 75 | "less": "^3.12.2", 76 | "less-loader": "^7.1.0", 77 | "lint-staged": "^10.0.0-1", 78 | "markdown-it": "^12.0.4", 79 | "markdown-it-anchor": "^7.1.0", 80 | "markdown-it-table-of-contents": "^0.5.2", 81 | "mini-css-extract-plugin": "^1.3.1", 82 | "patch-package": "^6.2.2", 83 | "sass": "^1.26.5", 84 | "sass-loader": "^8.0.2", 85 | "svg-sprite-loader": "^5.0.0", 86 | "vue-cli-plugin-browser-extension": "latest", 87 | "vue-template-compiler": "^2.6.11" 88 | }, 89 | "husky": { 90 | "hooks": { 91 | "pre-commit": "lint-staged", 92 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 93 | } 94 | }, 95 | "lint-staged": { 96 | "src/**/*.js": "eslint" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /patches/@vue+cli-service+4.5.9.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/@vue/cli-service/lib/util/validateWebpackConfig.js b/node_modules/@vue/cli-service/lib/util/validateWebpackConfig.js 2 | index dc61dce..8dbf879 100644 3 | --- a/node_modules/@vue/cli-service/lib/util/validateWebpackConfig.js 4 | +++ b/node_modules/@vue/cli-service/lib/util/validateWebpackConfig.js 5 | @@ -29,7 +29,7 @@ module.exports = function validateWebpackConfig ( 6 | } 7 | 8 | if (target === 'app' && singleConfig.output.publicPath !== options.publicPath) { 9 | - throw new Error( 10 | + if(singleConfig.output.publicPath !== './') throw new Error( 11 | `\n\nConfiguration Error: ` + 12 | `Avoid modifying webpack output.publicPath directly. ` + 13 | `Use the "publicPath" option instead.\n` 14 | -------------------------------------------------------------------------------- /patches/readme.md: -------------------------------------------------------------------------------- 1 | # 补丁说明 2 | 3 | ```javascript 4 | 5 | 由于@vue/cli 4.4.6版本创建的多page项目(本项目),配置publicPath为相对路径'./'不生效(https://cli.vuejs.org/zh/config/#publicpath), 6 | 7 | 且不允许直接修改config.output.publicPath(validateWebpackConfig (node_modules\@vue\cli-service\lib\util\validateWebpackConfig.js:34:11)) 8 | 9 | 但是因为本项目特殊需求,希望打包的publicPath均为相对路径,因此更改上述validateWebpackConfig.js文件中的校验,作为@vue+cli-service+4.5.9.patch补丁的内容。 10 | ``` 11 | 12 | - `npm i patch-package --save-dev` 安装`patch-package`工具后,修改依赖文件`validateWebpackConfig.js`,通过运行`npx patch-package @vue/cli-service`创建了当前patch文件:`@vue+cli-service+4.5.9.patch补丁` 13 | 14 | - 后续运行`npm install`或是`yarn install`命令时,会自动为依赖包打上上述生成的补丁。 15 | -------------------------------------------------------------------------------- /public/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "NotionX", 4 | "description": "" 5 | }, 6 | "xx": { 7 | "message": "xx", 8 | "description": "" 9 | }, 10 | "changeLangDesc": { 11 | "message": "Change language of this extension", 12 | "description": "" 13 | }, 14 | "changeLang": { 15 | "message": "Change NotionX Language", 16 | "description": "" 17 | }, 18 | "showScrollToTopDesc": { 19 | "message": "Add a 'scroll to top' button at bottom-right corner", 20 | "description": "" 21 | }, 22 | "showScrollToTop": { 23 | "message": "Scroll to Top Button", 24 | "description": "" 25 | }, 26 | "Options": { 27 | "message": "Options", 28 | "description": "" 29 | }, 30 | "Shortcuts": { 31 | "message": "Shortcuts", 32 | "description": "" 33 | }, 34 | "About": { 35 | "message": "About", 36 | "description": "" 37 | }, 38 | "hideComments": { 39 | "message": "Hide Page Comment", 40 | "description": "" 41 | }, 42 | "hideCommentsDesc": { 43 | "message": "Hide page comments and Properties (not line comments)", 44 | "description": "" 45 | }, 46 | "hideHelpBtn": { 47 | "message": "Hide Help Button", 48 | "description": "" 49 | }, 50 | "hideHelpBtnDesc": { 51 | "message": "Hide Help Button", 52 | "description": "" 53 | }, 54 | "hideAddBtn": { 55 | "message": "Hide 'New' Button", 56 | "description": "" 57 | }, 58 | "hideAddBtnDesc": { 59 | "message": "Hide Table 'New' Button", 60 | "description": "" 61 | }, 62 | "hideNotionXSidebar": { 63 | "message": "Hide NotionX SideBar", 64 | "description": "" 65 | }, 66 | "hideNotionXSidebarDesc": { 67 | "message": "Hide NotionX SideBar", 68 | "description": "" 69 | }, 70 | "hideNotionXDarkMode": { 71 | "message": "Hide NotionX DarkMode", 72 | "description": "" 73 | }, 74 | "hideNotionXDarkModeDesc": { 75 | "message": "Hide NotionX Dark Mode Button at top-right corner", 76 | "description": "" 77 | }, 78 | "toggleDark": { 79 | "message": "Dark Mode", 80 | "description": "" 81 | }, 82 | "toggleDarkDesc": { 83 | "message": "Toggle dark mode", 84 | "description": "" 85 | }, 86 | "openInDesktop": { 87 | "message": "Open in Desktop", 88 | "description": "" 89 | }, 90 | "openInDesktopDesc": { 91 | "message": "Open current page in desktop", 92 | "description": "" 93 | }, 94 | "genHeaderNumber": { 95 | "message": "Generate index for Headers", 96 | "description": "" 97 | }, 98 | "genHeaderNumberDesc": { 99 | "message": "Generate index for Headers like 1.2.1.", 100 | "description": "" 101 | }, 102 | "toggleCompact": { 103 | "message": "Compact Mode", 104 | "description": "" 105 | }, 106 | "toggleCompactDesc": { 107 | "message": "small text & full width", 108 | "description": "" 109 | }, 110 | "toggleCodeLineNum": { 111 | "message": "Show Code Line Num", 112 | "description": "" 113 | }, 114 | "toggleCodeLineNumDesc": { 115 | "message": "Show line number in code block", 116 | "description": "" 117 | }, 118 | "resetOptions": { 119 | "message": "Reset Options", 120 | "description": "" 121 | }, 122 | "resetOptionsDesc": { 123 | "message": "Reset all options above", 124 | "description": "" 125 | }, 126 | "preventTableOverflow": { 127 | "message": "Prevent table overflow", 128 | "description": "" 129 | }, 130 | "preventTableOverflowDesc": { 131 | "message": "Prevent table overflow caused by too large width", 132 | "description": "" 133 | }, 134 | "setCodeLang": { 135 | "message": "Set Code Language", 136 | "description": "" 137 | }, 138 | "setCodeLangDesc": { 139 | "message": "Set language for all code blocks in current page", 140 | "description": "" 141 | }, 142 | "place": { 143 | "message": "place", 144 | "description": "" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /public/_locales/ja-jp/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "NotionX", 4 | "description": "" 5 | }, 6 | "xx": { 7 | "message": "xx", 8 | "description": "" 9 | }, 10 | "changeLangDesc": { 11 | "message": "この拡張機能の言語を変更する", 12 | "description": "" 13 | }, 14 | "changeLang": { 15 | "message": "NotionX言語の変更", 16 | "description": "" 17 | }, 18 | "showScrollToTopDesc": { 19 | "message": "右下に「トップへのスクロール」ボタンを追加", 20 | "description": "" 21 | }, 22 | "showScrollToTop": { 23 | "message": "トップボタンへのスクロール", 24 | "description": "" 25 | }, 26 | "Options": { 27 | "message": "構成", 28 | "description": "" 29 | }, 30 | "Shortcuts": { 31 | "message": "ホットキー", 32 | "description": "" 33 | }, 34 | "About": { 35 | "message": "About", 36 | "description": "" 37 | }, 38 | "hideComments": { 39 | "message": "ページコメントを隠す", 40 | "description": "" 41 | }, 42 | "hideCommentsDesc": { 43 | "message": "ページコメントを非表示にします(行コメントではありません)", 44 | "description": "" 45 | }, 46 | "hideHelpBtn": { 47 | "message": "ヘルプボタンを隠す", 48 | "description": "" 49 | }, 50 | "hideHelpBtnDesc": { 51 | "message": "ヘルプボタンを隠す", 52 | "description": "" 53 | }, 54 | "hideAddBtn": { 55 | "message": "'New'ボタンを非表示", 56 | "description": "" 57 | }, 58 | "hideAddBtnDesc": { 59 | "message": "テーブルを非表示にする 'New'ボタン", 60 | "description": "" 61 | }, 62 | "hideNotionXSidebar": { 63 | "message": "NotionXサイドバーを非表示", 64 | "description": "" 65 | }, 66 | "hideNotionXSidebarDesc": { 67 | "message": "NotionXサイドバーを非表示", 68 | "description": "" 69 | }, 70 | "hideNotionXDarkMode": { 71 | "message": "NotionX ダークモードを隠す", 72 | "description": "" 73 | }, 74 | "hideNotionXDarkModeDesc": { 75 | "message": "右上のNotionXダークモードボタンを非表示にする", 76 | "description": "" 77 | }, 78 | "toggleDark": { 79 | "message": "ダークモード", 80 | "description": "" 81 | }, 82 | "toggleDarkDesc": { 83 | "message": "ダークモードを切り替えます", 84 | "description": "" 85 | }, 86 | "openInDesktop": { 87 | "message": "デスクトップで開く", 88 | "description": "" 89 | }, 90 | "openInDesktopDesc": { 91 | "message": "デスクトップアプリで現在のページを開く", 92 | "description": "" 93 | }, 94 | "genHeaderNumber": { 95 | "message": "「HerderBlock」番号生成", 96 | "description": "" 97 | }, 98 | "genHeaderNumberDesc": { 99 | "message": "「HerderBlock」の1.2.1。のようなシリアル番号を生成します", 100 | "description": "" 101 | }, 102 | "toggleCompact": { 103 | "message": "コンパクトモード", 104 | "description": "" 105 | }, 106 | "toggleCompactDesc": { 107 | "message": "small text & full width", 108 | "description": "" 109 | }, 110 | "toggleCodeLineNum": { 111 | "message": "コード行番号を表示", 112 | "description": "" 113 | }, 114 | "toggleCodeLineNumDesc": { 115 | "message": "コードブロックに行番号を表示する", 116 | "description": "" 117 | }, 118 | "resetOptions": { 119 | "message": "リセットオプション", 120 | "description": "" 121 | }, 122 | "resetOptionsDesc": { 123 | "message": "上記のすべてのオプションをリセットします", 124 | "description": "" 125 | }, 126 | "preventTableOverflow": { 127 | "message": "テーブルのオーバーフローを防ぐ", 128 | "description": "" 129 | }, 130 | "preventTableOverflowDesc": { 131 | "message": "テーブルが水平方向にオーバーフローしないようにします", 132 | "description": "" 133 | }, 134 | "setCodeLang": { 135 | "message": "コード言語の設定", 136 | "description": "" 137 | }, 138 | "setCodeLangDesc": { 139 | "message": "現在のページのすべてのコードブロックの言語を設定する", 140 | "description": "" 141 | }, 142 | "place": { 143 | "message": "place", 144 | "description": "" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /public/_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "NotionX", 4 | "description": "" 5 | }, 6 | "xx": { 7 | "message": "xx", 8 | "description": "" 9 | }, 10 | "changeLangDesc": { 11 | "message": "이 확장의 언어 변경", 12 | "description": "" 13 | }, 14 | "changeLang": { 15 | "message": "NotionX 언어 변경", 16 | "description": "" 17 | }, 18 | "showScrollToTopDesc": { 19 | "message": "오른쪽 하단에 '위로 스크롤'버튼 추가", 20 | "description": "" 21 | }, 22 | "showScrollToTop": { 23 | "message": "맨위로 스크롤 버튼", 24 | "description": "" 25 | }, 26 | "Options": { 27 | "message": "옵션", 28 | "description": "" 29 | }, 30 | "Shortcuts": { 31 | "message": "단축키", 32 | "description": "" 33 | }, 34 | "About": { 35 | "message": "About", 36 | "description": "" 37 | }, 38 | "hideComments": { 39 | "message": "페이지 댓글 숨기기", 40 | "description": "" 41 | }, 42 | "hideCommentsDesc": { 43 | "message": "페이지 댓글 숨기기 (댓글이 아님)", 44 | "description": "" 45 | }, 46 | "hideHelpBtn": { 47 | "message": "도움말 버튼을 숨 깁니다", 48 | "description": "" 49 | }, 50 | "hideHelpBtnDesc": { 51 | "message": "도움말 버튼을 숨 깁니다", 52 | "description": "" 53 | }, 54 | "hideAddBtn": { 55 | "message": "'New' 버튼 숨기기", 56 | "description": "" 57 | }, 58 | "hideAddBtnDesc": { 59 | "message": "테이블 'New' 버튼 숨기기", 60 | "description": "" 61 | }, 62 | "hideNotionXSidebar": { 63 | "message": "NotionX 사이드 바 숨기기", 64 | "description": "" 65 | }, 66 | "hideNotionXSidebarDesc": { 67 | "message": "NotionX 사이드 바 숨기기", 68 | "description": "" 69 | }, 70 | "hideNotionXDarkMode": { 71 | "message": "Notionx 어두운 모드 숨기기", 72 | "description": "" 73 | }, 74 | "hideNotionXDarkModeDesc": { 75 | "message": "오른쪽 상단 모서리에서 Notionx 어두운 모드 버튼 숨기기", 76 | "description": "" 77 | }, 78 | "toggleDark": { 79 | "message": "다크 모드", 80 | "description": "" 81 | }, 82 | "toggleDarkDesc": { 83 | "message": "다크 모드 전환", 84 | "description": "" 85 | }, 86 | "openInDesktop": { 87 | "message": "데스크톱 앱에서 열기", 88 | "description": "" 89 | }, 90 | "openInDesktopDesc": { 91 | "message": "데스크톱 앱에서 현재 페이지 열기", 92 | "description": "" 93 | }, 94 | "genHeaderNumber": { 95 | "message": "'Herder Block' 일련 번호 생성", 96 | "description": "" 97 | }, 98 | "genHeaderNumberDesc": { 99 | "message": "'Herder Block'에 대해 1.2.1.과 같은 일련 번호를 생성합니다.", 100 | "description": "" 101 | }, 102 | "toggleCompact": { 103 | "message": "호환 모드", 104 | "description": "" 105 | }, 106 | "toggleCompactDesc": { 107 | "message": "작은 텍스트 및 전체 너비", 108 | "description": "" 109 | }, 110 | "toggleCodeLineNum": { 111 | "message": "코드 라인 번호 표시", 112 | "description": "" 113 | }, 114 | "toggleCodeLineNumDesc": { 115 | "message": "코드 block에 줄 번호 표시", 116 | "description": "" 117 | }, 118 | "resetOptions": { 119 | "message": "재설정 옵션", 120 | "description": "" 121 | }, 122 | "resetOptionsDesc": { 123 | "message": "위의 모든 옵션 재설정", 124 | "description": "" 125 | }, 126 | "preventTableOverflow": { 127 | "message": "테이블 오버플로 방지", 128 | "description": "" 129 | }, 130 | "preventTableOverflowDesc": { 131 | "message": "테이블이 수평으로 넘치지 않도록 방지", 132 | "description": "" 133 | }, 134 | "setCodeLang": { 135 | "message": "코드 언어 설정", 136 | "description": "" 137 | }, 138 | "setCodeLangDesc": { 139 | "message": "현재 페이지의 모든 코드 블록에 대한 언어 설정", 140 | "description": "" 141 | }, 142 | "place": { 143 | "message": "place", 144 | "description": "" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /public/_locales/locales.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "value": "en", "label": "English" }, 3 | { "value": "zh-cn", "label": "中文" }, 4 | { "value": "ko", "label": "한국어" }, 5 | { "value": "ja-jp", "label": "日本語" }, 6 | { "value": "uk", "label": "Українська"} 7 | ] 8 | -------------------------------------------------------------------------------- /public/_locales/uk/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "NotionX", 4 | "description": "" 5 | }, 6 | "xx": { 7 | "message": "xx", 8 | "description": "" 9 | }, 10 | "changeLangDesc": { 11 | "message": "Змінити мову розширення", 12 | "description": "" 13 | }, 14 | "changeLang": { 15 | "message": "Змінити мову NotionX", 16 | "description": "" 17 | }, 18 | "showScrollToTopDesc": { 19 | "message": "Додати кнопку 'Прокрутити сі догори' у правому нижньому куті", 20 | "description": "" 21 | }, 22 | "showScrollToTop": { 23 | "message": "Прокрутити сі догори", 24 | "description": "" 25 | }, 26 | "Options": { 27 | "message": "Параметри", 28 | "description": "" 29 | }, 30 | "Shortcuts": { 31 | "message": "Комбінації клавіш", 32 | "description": "" 33 | }, 34 | "About": { 35 | "message": "Про нас", 36 | "description": "" 37 | }, 38 | "hideComments": { 39 | "message": "Приховати коментарі сторінки", 40 | "description": "" 41 | }, 42 | "hideCommentsDesc": { 43 | "message": "Приховати коментарі (зверху сторінки)", 44 | "description": "" 45 | }, 46 | "hideHelpBtn": { 47 | "message": "Hide Help Button", 48 | "description": "" 49 | }, 50 | "hideHelpBtnDesc": { 51 | "message": "Hide Help Button", 52 | "description": "" 53 | }, 54 | "hideAddBtn": { 55 | "message": "Hide 'New' Button", 56 | "description": "" 57 | }, 58 | "hideAddBtnDesc": { 59 | "message": "Hide Table 'New' Button", 60 | "description": "" 61 | }, 62 | "hideNotionXSidebar": { 63 | "message": "Приховати панель NotionX", 64 | "description": "" 65 | }, 66 | "hideNotionXSidebarDesc": { 67 | "message": "Приховати панель NotionX", 68 | "description": "" 69 | }, 70 | "hideNotionXDarkMode": { 71 | "message": "Hide NotionX DarkMode", 72 | "description": "" 73 | }, 74 | "hideNotionXDarkModeDesc": { 75 | "message": "Hide NotionX Dark Mode Button at top-right corner", 76 | "description": "" 77 | }, 78 | "toggleDark": { 79 | "message": "Темний режим", 80 | "description": "" 81 | }, 82 | "toggleDarkDesc": { 83 | "message": "Увімкнути темний режим", 84 | "description": "" 85 | }, 86 | "openInDesktop": { 87 | "message": "Відкрити у настільному застосунку", 88 | "description": "" 89 | }, 90 | "openInDesktopDesc": { 91 | "message": "Відкрити сторінку у застосунку", 92 | "description": "" 93 | }, 94 | "genHeaderNumber": { 95 | "message": "Generate index for Headers", 96 | "description": "" 97 | }, 98 | "genHeaderNumberDesc": { 99 | "message": "Generate index for Headers like 1.2.1.", 100 | "description": "" 101 | }, 102 | "toggleCompact": { 103 | "message": "Компактний режим", 104 | "description": "" 105 | }, 106 | "toggleCompactDesc": { 107 | "message": "малий текст і на повну ширину", 108 | "description": "" 109 | }, 110 | "toggleCodeLineNum": { 111 | "message": "Показувати № рядка коду", 112 | "description": "" 113 | }, 114 | "toggleCodeLineNumDesc": { 115 | "message": "Показувати номер рядка в блоках коду", 116 | "description": "" 117 | }, 118 | "resetOptions": { 119 | "message": "Скинути параметри", 120 | "description": "" 121 | }, 122 | "resetOptionsDesc": { 123 | "message": "Скинути усі параметри", 124 | "description": "" 125 | }, 126 | "preventTableOverflow": { 127 | "message": "Запобігти переповненню таблиці", 128 | "description": "" 129 | }, 130 | "preventTableOverflowDesc": { 131 | "message": "Запобігти виходження за рамки надто широкої таблиці", 132 | "description": "" 133 | }, 134 | "setCodeLang": { 135 | "message": "Встановити мову коду", 136 | "description": "" 137 | }, 138 | "setCodeLangDesc": { 139 | "message": "Встановити мову коду для усіх блоків на цій сторінці", 140 | "description": "" 141 | }, 142 | "place": { 143 | "message": "місце", 144 | "description": "" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /public/_locales/zh-cn/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "NotionX", 4 | "description": "" 5 | }, 6 | "xx": { 7 | "message": "xx", 8 | "description": "" 9 | }, 10 | "changeLangDesc": { 11 | "message": "切换此插件内的语言", 12 | "description": "" 13 | }, 14 | "changeLang": { 15 | "message": "切换插件语言", 16 | "description": "" 17 | }, 18 | "Options": { 19 | "message": "配置", 20 | "description": "" 21 | }, 22 | "Shortcuts": { 23 | "message": "快捷键", 24 | "description": "" 25 | }, 26 | "About": { 27 | "message": "关于", 28 | "description": "" 29 | }, 30 | "hideComments": { 31 | "message": "隐藏页面评论", 32 | "description": "" 33 | }, 34 | "hideCommentsDesc": { 35 | "message": "隐藏页面评论和属性(注意是页标题下的评论,而不是行评论)", 36 | "description": "" 37 | }, 38 | "hideHelpBtn": { 39 | "message": "隐藏帮助按钮", 40 | "description": "" 41 | }, 42 | "hideHelpBtnDesc": { 43 | "message": "隐藏帮助按钮", 44 | "description": "" 45 | }, 46 | "hideAddBtn": { 47 | "message": "隐藏'New'按钮", 48 | "description": "" 49 | }, 50 | "hideAddBtnDesc": { 51 | "message": "隐藏table的'New'按钮", 52 | "description": "" 53 | }, 54 | "hideNotionXSidebar": { 55 | "message": "隐藏NotionX侧边栏", 56 | "description": "" 57 | }, 58 | "hideNotionXSidebarDesc": { 59 | "message": "隐藏NotionX侧边栏", 60 | "description": "" 61 | }, 62 | "hideNotionXDarkMode": { 63 | "message": "隐藏NotionX暗黑模式按钮", 64 | "description": "" 65 | }, 66 | "hideNotionXDarkModeDesc": { 67 | "message": "隐藏页面右上角的NotionX暗黑模式按钮", 68 | "description": "" 69 | }, 70 | "toggleDark": { 71 | "message": "暗黑模式", 72 | "description": "" 73 | }, 74 | "toggleDarkDesc": { 75 | "message": "切换暗黑模式", 76 | "description": "" 77 | }, 78 | "openInDesktop": { 79 | "message": "在桌面端打开", 80 | "description": "" 81 | }, 82 | "openInDesktopDesc": { 83 | "message": "在桌面端中打开当前页面", 84 | "description": "" 85 | }, 86 | "genHeaderNumber": { 87 | "message": "生成Headers序号", 88 | "description": "" 89 | }, 90 | "genHeaderNumberDesc": { 91 | "message": "为Header Block生成形如1.2.1.的序号", 92 | "description": "" 93 | }, 94 | "toggleCompact": { 95 | "message": "紧凑模式", 96 | "description": "" 97 | }, 98 | "toggleCompactDesc": { 99 | "message": "small text & full width", 100 | "description": "" 101 | }, 102 | "toggleCodeLineNum": { 103 | "message": "显示代码行号", 104 | "description": "" 105 | }, 106 | "toggleCodeLineNumDesc": { 107 | "message": "显示代码块前的行号", 108 | "description": "" 109 | }, 110 | "resetOptions": { 111 | "message": "还原配置", 112 | "description": "" 113 | }, 114 | "resetOptionsDesc": { 115 | "message": "还原所有配置", 116 | "description": "" 117 | }, 118 | "showScrollToTopDesc": { 119 | "message": "在页面右下角添加一个'滚动至顶部的按钮'", 120 | "description": "" 121 | }, 122 | "showScrollToTop": { 123 | "message": "Scroll to Top 按钮", 124 | "description": "" 125 | }, 126 | "preventTableOverflow": { 127 | "message": "阻止表格溢出", 128 | "description": "" 129 | }, 130 | "preventTableOverflowDesc": { 131 | "message": "阻止表格因横向宽度过大导致的尺寸溢出", 132 | "description": "" 133 | }, 134 | "setCodeLang": { 135 | "message": "设置代码快语言", 136 | "description": "" 137 | }, 138 | "setCodeLangDesc": { 139 | "message": "为当前页面所有代码块设置语言", 140 | "description": "" 141 | }, 142 | "place": { 143 | "message": "place", 144 | "description": "" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /public/browser-extension.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /public/css/md.css: -------------------------------------------------------------------------------- 1 | /* 全局属性 2 | * 页边距 padding: 30px; 3 | * 全文字体 font-family: ptima-Regular; 4 | * 英文换行 word-break: break-all; 5 | */ 6 | #md { 7 | max-width: 768px; 8 | margin: 0 auto; 9 | } 10 | 11 | /* 段落,下方未标注标签参数均同此处 12 | * 上边距 margin-top: 5px; 13 | * 下边距 margin-bottom: 5px; 14 | * 行高 line-height: 26px; 15 | * 词间距 word-spacing: 3px; 16 | * 字间距 letter-spacing: 3px; 17 | * 对齐 text-align: left; 18 | * 颜色 color: #3e3e3e; 19 | * 字体大小 font-size: 16px; 20 | * 首行缩进 text-indent: 2em; 21 | */ 22 | #md p { 23 | } 24 | 25 | /* 一级标题 */ 26 | #md h1 { 27 | text-align: center; 28 | } 29 | 30 | /* 一级标题内容 */ 31 | #md h1 .content { 32 | } 33 | 34 | /* 一级标题前缀 */ 35 | #md h1 .prefix { 36 | } 37 | 38 | /* 一级标题后缀 */ 39 | #md h1 .suffix { 40 | } 41 | 42 | /* 二级标题 */ 43 | #md h2 { 44 | margin-top: 2em; 45 | } 46 | 47 | /* 二级标题内容 */ 48 | #md h2 .content { 49 | } 50 | 51 | /* 二级标题前缀 */ 52 | #md h2 .prefix { 53 | } 54 | 55 | /* 二级标题后缀 */ 56 | #md h2 .suffix { 57 | } 58 | 59 | /* 三级标题 */ 60 | #md h3 { 61 | margin-top: 1em; 62 | border-left: 5px solid #000; 63 | padding-left: 0.5em; 64 | } 65 | 66 | /* 三级标题内容 */ 67 | #md h3 .content { 68 | } 69 | 70 | /* 三级标题前缀 */ 71 | #md h3 .prefix { 72 | } 73 | 74 | /* 三级标题后缀 */ 75 | #md h3 .suffix { 76 | } 77 | 78 | /* 无序列表整体样式 79 | * list-style-type: square|circle|disc; 80 | */ 81 | #md ul { 82 | } 83 | 84 | /* 有序列表整体样式 85 | * list-style-type: upper-roman|lower-greek|lower-alpha; 86 | */ 87 | #md ol { 88 | } 89 | 90 | /* 列表内容,不要设置li 91 | */ 92 | #md li section { 93 | } 94 | 95 | /* 一级引用 96 | * 左边缘颜色 border-left-color: black; 97 | * 背景色 background: gray; 98 | */ 99 | #md .multiquote-1 { 100 | } 101 | 102 | /* 一级引用文字 */ 103 | #md .multiquote-1 p { 104 | } 105 | 106 | /* 二级引用 107 | */ 108 | #md .multiquote-2 { 109 | } 110 | 111 | /* 二级引用文字 */ 112 | #md .multiquote-2 p { 113 | } 114 | 115 | /* 三级引用 116 | */ 117 | #md .multiquote-3 { 118 | } 119 | 120 | /* 三级引用文字 */ 121 | #md .multiquote-3 p { 122 | } 123 | 124 | /* 链接 125 | * border-bottom: 1px solid #009688; 126 | */ 127 | #md a { 128 | } 129 | 130 | /* 加粗 */ 131 | #md strong { 132 | } 133 | 134 | /* 斜体 */ 135 | #md em { 136 | } 137 | 138 | /* 加粗斜体 */ 139 | #md em strong { 140 | } 141 | 142 | /* 删除线 */ 143 | #md del { 144 | } 145 | 146 | /* 分隔线 147 | * 粗细、样式和颜色 148 | * border-top: 1px solid #3e3e3e; 149 | */ 150 | #md hr { 151 | } 152 | 153 | /* 图片 154 | * 宽度 width: 80%; 155 | * 居中 margin: 0 auto; 156 | * 居左 margin: 0 0; 157 | */ 158 | #md img { 159 | max-width: 80%; 160 | margin: 0 auto; 161 | display: block; 162 | } 163 | 164 | /* 图片描述文字 */ 165 | #md figcaption { 166 | } 167 | 168 | /* 行内代码 */ 169 | #md p code, #md li code { 170 | } 171 | 172 | /* 173 | * 代码块不换行 display: -webkit-box !important; 174 | * 代码块换行 display: block; 175 | */ 176 | #md pre code { 177 | } 178 | 179 | /* 180 | * 表格内的单元格 181 | * 字体大小 font-size: 16px; 182 | * 边框 border: 1px solid #ccc; 183 | * 内边距 padding: 5px 10px; 184 | */ 185 | #md table tr th, 186 | #md table tr td { 187 | } 188 | 189 | /* 190 | * 某一列表格列宽控制 191 | * n 可以修改为具体数字,不修改时表示所有列 192 | * 最小列宽 min-width: 85px; 193 | */ 194 | #md table tr th:nth-of-type(n), 195 | #md table tr td:nth-of-type(n){ 196 | } 197 | 198 | /* 脚注文字 */ 199 | #md .footnote-word { 200 | } 201 | 202 | /* 脚注上标 */ 203 | #md .footnote-ref { 204 | } 205 | 206 | /* "参考资料"四个字 207 | * 内容 content: "参考资料"; 208 | */ 209 | #md .footnotes-sep:before { 210 | } 211 | 212 | /* 参考资料编号 */ 213 | #md .footnote-num { 214 | } 215 | 216 | /* 参考资料文字 */ 217 | #md .footnote-item p { 218 | } 219 | 220 | /* 参考资料解释 */ 221 | #md .footnote-item p em { 222 | } 223 | 224 | /* 行间公式 225 | * 最大宽度 max-width: 300% !important; 226 | */ 227 | #md .block-equation svg { 228 | } 229 | 230 | /* 行内公式 231 | */ 232 | #md .inline-equation svg { 233 | } -------------------------------------------------------------------------------- /public/css/privacy.css: -------------------------------------------------------------------------------- 1 | /**************************** 2 | ** Style for all devices ** 3 | ****************************/ 4 | 5 | /* 6 | General 7 | */ 8 | 9 | body{ 10 | font-family: sans-serif; 11 | } 12 | 13 | section { 14 | border-bottom: solid thin rgb(220,220,220); 15 | } 16 | 17 | /* 18 | Page header 19 | */ 20 | 21 | header { 22 | margin: -0.5 -0.5em 0 -0.5em; 23 | text-align: center; 24 | } 25 | 26 | /* 27 | Section headings 28 | */ 29 | 30 | h1, h2, h3, h4, h5, h6, h7 { 31 | font-family: serif; 32 | font-weight: normal; 33 | } 34 | 35 | h1 { 36 | text-align: center; 37 | } 38 | 39 | /* 40 | Navigation 41 | */ 42 | 43 | nav a { 44 | text-decoration: none; 45 | color: black; 46 | } 47 | 48 | nav a:hover { 49 | color: #b91e27; 50 | } 51 | 52 | nav h1 { 53 | font-family: serif; 54 | margin: 0 0 0.5em 0; 55 | } 56 | 57 | 58 | /* 59 | General content elements and styles 60 | */ 61 | 62 | ul, ol { 63 | color: #b91e27; 64 | font-weight: bold; 65 | font-family: serif; 66 | font-size: 1.2em; 67 | } 68 | 69 | ul { 70 | list-style: square outside; 71 | } 72 | 73 | ol span { 74 | color: black; 75 | font-weight: normal; 76 | font-family: sans-serif; 77 | font-size: 0.84em; 78 | } 79 | 80 | ul span { 81 | color: black; 82 | font-weight: normal; 83 | font-family: sans-serif; 84 | font-size: 0.84em; 85 | } 86 | 87 | blockquote { 88 | border-left: solid thick #b91e27; 89 | } 90 | 91 | em { 92 | font-style: italic; 93 | } 94 | 95 | strong { 96 | font-weight: bold; 97 | color: #b91e27; 98 | } 99 | 100 | /* Nav to-top elements */ 101 | 102 | nav.to-top { 103 | display: block; 104 | padding: 2.5em 0.5em 0.5em 2.5em; 105 | margin: 0; 106 | width: auto; 107 | position: absolute; 108 | right: 2em; 109 | left: auto; 110 | border-style: none; 111 | background-color: transparent; 112 | } 113 | 114 | nav.to-top a { 115 | margin: 0; border: 0; 116 | text-decoration: none; 117 | color: royalblue; 118 | font-size: 0.8em; 119 | font-weight: bold; 120 | font-family: sans-serif; 121 | } 122 | 123 | nav.to-top a:hover { 124 | text-decoration: underline; 125 | } 126 | 127 | 128 | /******************************************** 129 | ** Style for devices with small displays ** 130 | ********************************************/ 131 | @media (max-width: 46.9em){ 132 | 133 | /* 134 | General 135 | */ 136 | 137 | section { 138 | margin: 0 -0.5em 1em -0.5em; 139 | padding: 0 0.5em 1em 0.5em; 140 | } 141 | 142 | /* 143 | Page header 144 | */ 145 | 146 | header h1 { 147 | padding: 0.5em 0 0 0; 148 | font-size: 2em; 149 | } 150 | 151 | /* 152 | Section headings 153 | */ 154 | 155 | h2, h3, h4, h5, h6, h7 { 156 | margin: 0.2em 0 0 1em; 157 | padding: 0.1em; 158 | } 159 | 160 | h1 { 161 | font-size: 1.5em; 162 | /* margin: 0 0 1em 0;*/ 163 | } 164 | 165 | h2 { 166 | font-size: 1.2em; 167 | } 168 | 169 | h3 { 170 | font-size: 1.13em; 171 | } 172 | 173 | h4 { 174 | font-size: 1.07em; 175 | } 176 | 177 | 178 | /* 179 | Navigation 180 | */ 181 | 182 | /* Nav bar */ 183 | 184 | nav { 185 | margin: 1em 10% 1em 10%; 186 | padding: 1em 0 0 0; 187 | width: 22em; 188 | border: solid thin rgb(240,240,240); 189 | } 190 | 191 | nav ul { 192 | margin: 0; 193 | list-style: square outside; 194 | } 195 | 196 | nav a { 197 | font-family: serif; 198 | } 199 | 200 | nav a:hover { 201 | font-weight: bold; 202 | } 203 | 204 | } 205 | 206 | 207 | /******************************************** 208 | ** Style for devices with large displays ** 209 | ********************************************/ 210 | @media (min-width: 47em) { 211 | 212 | 213 | /* 214 | General 215 | */ 216 | 217 | section { 218 | margin: 0 -0.5em 1em -0.5em; 219 | padding: 2em 8% 2em 8%; 220 | } 221 | 222 | 223 | /* 224 | Page header 225 | */ 226 | 227 | header { 228 | margin: 0 -0.5em 0 -0.5em; 229 | } 230 | 231 | header h1 { 232 | padding: 0.5em 0 0 0; 233 | font-size: 2em; 234 | } 235 | 236 | 237 | /* 238 | Section headings 239 | */ 240 | 241 | h2, h3, h4, h5, h6, h7 { 242 | margin: 0.8em 0 0 7%; 243 | padding: 0.2em; 244 | } 245 | 246 | h1 { 247 | font-size: 2em; 248 | text-align: center; 249 | margin: 0 0 1em 0; 250 | } 251 | 252 | h2 { 253 | font-size: 1.65em; 254 | } 255 | 256 | h3 { 257 | font-size: 1.4em; 258 | } 259 | 260 | h4 { 261 | font-size: 1.15em; 262 | } 263 | 264 | 265 | /* 266 | Other content elements 267 | */ 268 | 269 | blockquote { 270 | padding: 0 0 0 1.2em; 271 | margin: 0 6em 0 4em; 272 | } 273 | 274 | ul, ol{ 275 | padding: 0 6em 0 6em; 276 | } 277 | 278 | 279 | /* 280 | Navigation 281 | */ 282 | 283 | /* Nav bar */ 284 | 285 | nav { 286 | padding: 0 0 3.5em 0; 287 | margin: 0 0 0 0; 288 | } 289 | 290 | nav h1 { 291 | visibility: hidden; 292 | height: 0; 293 | } 294 | 295 | nav ul { 296 | margin: 0 0 0 -22.5em; 297 | padding: 0; 298 | float: left; 299 | position: absolute; 300 | width: 55em; 301 | left: 50%; 302 | border: solid thin rgb(240,240,240); 303 | list-style: none outside; 304 | } 305 | 306 | nav li { 307 | float: left; 308 | margin: 1em; 309 | } 310 | 311 | nav li ul { 312 | display: none; 313 | } 314 | 315 | nav a { 316 | font-size: 1.1em; 317 | font-weight: bold; 318 | font-family: sans-serif; 319 | } 320 | 321 | } 322 | 323 | 324 | /************************** 325 | ** Style for printouts ** 326 | **************************/ 327 | @media print { 328 | 329 | nav.to-top { 330 | display: none; 331 | } 332 | 333 | } 334 | 335 | 336 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/favicon.ico -------------------------------------------------------------------------------- /public/icons/notionx -128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/icons/notionx -128.png -------------------------------------------------------------------------------- /public/icons/notionx-white-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/icons/notionx-white-128.png -------------------------------------------------------------------------------- /public/icons/notionx-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/icons/notionx-white.png -------------------------------------------------------------------------------- /public/icons/notionx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/icons/notionx.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | <%= htmlWebpackPlugin.options.title %> 23 | 24 | 25 | 32 | 33 | 34 | 35 | 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /public/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | NotionX - A browser that enhances Notion Experience 26 | 27 | 32 | 33 | 34 |
35 | 简体中文 | English 36 |
37 |
38 | 39 |
40 | 47 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /public/preview/1280x800-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-hover.png -------------------------------------------------------------------------------- /public/preview/1280x800-p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-p1.png -------------------------------------------------------------------------------- /public/preview/1280x800-p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-p2.png -------------------------------------------------------------------------------- /public/preview/1280x800-p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-p3.png -------------------------------------------------------------------------------- /public/preview/1280x800-p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-p4.png -------------------------------------------------------------------------------- /public/preview/1280x800-p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-p5.png -------------------------------------------------------------------------------- /public/preview/1280x800-pinned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1280x800-pinned.png -------------------------------------------------------------------------------- /public/preview/1400x560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/1400x560.png -------------------------------------------------------------------------------- /public/preview/440x280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/440x280.png -------------------------------------------------------------------------------- /public/preview/640x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/640x400.png -------------------------------------------------------------------------------- /public/preview/920x680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/920x680.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/1280 800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/1280 800.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/1280x800-ppt-p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/1280x800-ppt-p1.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/1280x800-ppt-p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/1280x800-ppt-p2.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/1400 560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/1400 560.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/440 280 main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/440 280 main.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/440 280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/440 280.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/640 400 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/640 400 2.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/640 400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/640 400.png -------------------------------------------------------------------------------- /public/preview/v2.0.0/920 680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.0.0/920 680.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/1280 800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/1280 800.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/1280x800-ppt-p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/1280x800-ppt-p1.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/1280x800-ppt-p2-ch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/1280x800-ppt-p2-ch.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/1280x800-ppt-p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/1280x800-ppt-p2.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/1400 560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/1400 560.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/440 280 main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/440 280 main.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/440 280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/440 280.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/640 400 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/640 400 2.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/640 400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/640 400.png -------------------------------------------------------------------------------- /public/preview/v2.1.0/920 680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/public/preview/v2.1.0/920 680.png -------------------------------------------------------------------------------- /public/privacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Privacy Policy - NotionX 7 | 8 | 9 | 10 | 11 |
12 |

NotionX Privacy Policy / 隐私权政策

13 |
14 | 15 | 61 | 62 |
63 | 64 | 65 |
66 |

Instruction - 说明

67 | 68 |

69 | As the individual developer of NotionX (hereinafter referred to as 70 | "we"), we value the maintenance and protection of our users' personal 71 | information. When you use NotionX, we may collect and use your 72 | personal information. The purpose of this Privacy Policy is to explain 73 | to you how we collect, store, use, or share your personal information. 74 | We hope that you will read this Privacy Policy carefully so that you 75 | can make the appropriate choices if needed. 76 |

77 | 78 |

79 | By using or continuing to use our products or services, you consent to 80 | our collection, storage, use and sharing of your personal information 81 | in accordance with this Privacy Policy. 82 |

83 | 84 |

85 | 作为NotionX的个人开发者(以下简称“我们”),我们重视维护和保护用户的个人信息。您在使用NotionX时,我们可能会收集和使用您的个人信息。本《隐私权政策》旨在向您说明我们如何收集、储存、使用或分享您的个人信息。希望您仔细阅读本《隐私权政策》,以便在需要的时候,能让您作出合适的选择。 86 |

87 | 88 |

89 | 您使用或继续使用我们的产品或服务,即意味着您同意我们按照本《隐私权政策》收集、储存、使用和分享您的个人信息。 90 |

91 |
92 | 93 | 94 | 95 |
96 |

How we collect info - 我们如何收集您的信息

97 | 98 |

99 | In order to better implement NotionX's services, the information you 100 | provide through your use of NotionX contains the content of the web 101 | page you are currently visiting on the notion.so host. 102 |

103 | 104 |

105 | Your personal information may contain sensitive information, such as 106 | your race, religious beliefs, personal health status, gender 107 | orientation, etc. You may upload or post such sensitive information in 108 | public channels when you use our products or services. Please handle 109 | such sensitive information with care. By voluntarily providing your 110 | sensitive personal information, you consent to our processing of your 111 | sensitive personal information for the purposes described in this 112 | policy. 113 |

114 | 115 |

116 | 为了更好的实现NotionX的相关服务,您通过使用NotionX的过程中提供的信息包含您当前正在访问的 117 | notion.so 主机下的网页的内容。 118 |

119 | 120 |

121 | 您的个人信息中可能含有敏感信息,例如您的种族、宗教信仰、个人健康状况、性别取向等,您在使用我们产品或服务时,您可能会在公开渠道上传或发布这类敏感信息。请您谨慎地处理这类敏感信息。若您主动提供您的个人敏感信息,即表示您同意我们按照本政策所述目的来处理您的个人敏感信息。 122 |

123 |
124 | 125 | 126 | 127 |
128 |

How we use your info- 如何使用您的信息

129 | 130 |

131 | The personal information we collect from you may be used by us to 132 | fulfill the following purposes: 133 |

134 |
  • Services for you.
  • 135 |
  • 136 | Help us design new products or services and improve our existing 137 | products or services. 138 |
  • 139 | 140 |

    我们收集到的您的个人信息将可能被我们用于实现如下目的:

    141 |
  • 向您提供服务。
  • 142 |
  • 帮助我们设计新产品或新服务,改善我们现有的产品或服务。
  • 143 |
    144 | 145 | 146 | 147 |
    148 |

    When we share your info - 如何分享您的信息

    149 | 150 |

    151 | We will not disclose your personal information to third parties, 152 | except in the following circumstances: 153 |

    154 |
  • With your consent.
  • 155 |
  • 156 | In order to achieve the goal of "How may we use your personal 157 | information? To share your personal information with our authorized 158 | product or service providers for the purposes described in this 159 | section. 160 |
  • 161 |
  • 162 | We may engage other third parties to provide services to you on our 163 | behalf, and we may disclose some of your personal information to our 164 | affiliates or third-party partners. We strictly prohibit our 165 | affiliates or partners from using the shared information for other 166 | purposes. 167 |
  • 168 |
  • 169 | In this case, your personal information and services will be 170 | transferred along with the business. 171 |
  • 172 | 173 |

    我们不会向第三方披露您的个人信息,但以下情况除外:

    174 |
  • 在得到您同意的情况下。
  • 175 |
  • 176 | 为实现“我们可能如何使用您的个人信息?”章节中的目的而向我们授权的产品或服务提供商分享您的个人信息。 177 |
  • 178 |
  • 179 | 我们可能委托其他第三方代表我们向您提供服务,我们可能向关联公司或第三方合作方披露您的部分个人信息。我们会严格禁止关联公司或合作方将共享的信息用于其他目的。 180 |
  • 181 |
  • 182 | 今后我们的业务可能发生合并、收购、转让等新情况,在此情况下,您的个人信息及服务等,将随着业务一并转移。 183 |
  • 184 |
    185 | 186 |

    187 | Your personal information may be subject to mandatory disclosure: 1) 188 | as required by law or regulation; 2) as required by a judicial 189 | decision or legal process; 3) as required by a decision of a 190 | governmental agency or other authorized organization; 4) to protect 191 | our legitimate rights and interests or those of our affiliates or 192 | other customers (e.g., to settle overdue accounts), etc. In such 193 | cases, we will record the content, timing, reason, and purpose of the 194 | disclosure. In the above cases, we will record the content, time, 195 | reason, and object of the disclosure. 196 |

    197 | 198 |

    199 | 您的个人信息在如下情况下可能会被强制要求披露:1)根据法律法规的规定;2)根据司法机关裁决或法律程序要求;3)根据政府部门的决定或其他有权组织的要求;4)为保护我们或我们的关联公司、其他客户的合法权益(例如清偿逾期账款)等。在上述情况下,我们将记录信息披露的内容、时间、原因及对象。 200 |

    201 |
    202 | 203 | 204 | 205 |
    206 |

    How we store your info - 如何存储您的信息

    207 | 208 |

    209 | We will not store your personal information in locations other than 210 | your local machine. 211 |

    212 | 213 |

    我们将不会在您本机之外的其他位置存储您的个人信息。

    214 |
    215 | 216 | 217 | 218 |
    219 |

    About - 关于

    220 | 221 |

    Your choices - 您的权限

    222 | 223 |

    224 | If you refuse to allow us to use any of your information, you should 225 | stop using our services and products. 226 |

    227 | 228 |

    229 | Depending on the laws of your geographic location, some of the 230 | provisions of this Privacy Policy may not apply to you. This Privacy 231 | Policy does not exclude or limit any of your rights under local law. 232 |

    233 | 234 |

    如果您拒绝我们使用您的任何信息,请您停止使用我们的服务和产品。

    235 | 236 |

    237 | 根据您所处的地域的法律规定,本《隐私权政策》的某些条款可能并不适用于您。本《隐私权政策》不排除或限制您根据本地法律规定所享有的任何权利。 238 |

    239 | 240 |

    Changes - 变更

    241 | 242 |

    243 | We may revise the terms of this Privacy Policy from time to time, and 244 | such revisions are made a part of this Privacy Policy. If such 245 | revisions result in a material diminution of your rights under this 246 | Privacy Policy, we will notify you by means of a prominent notice on 247 | our home page or by sending you an email or other means prior to the 248 | effective date of the revisions. In such cases, your continued use of 249 | our Services constitutes your agreement to be bound by this Privacy 250 | Policy, as amended. 251 |

    252 | 253 |

    254 | 我们可能适时修订本《隐私权政策》的条款,该等修订构成本《隐私权政策》的一部分。如该等修订造成您在本《隐私权政策》下权利的实质减少,我们将在修订生效前通过在主页上显著位置提示或向您发送电子邮件或以其他方式通知您。在该种情况下,若您继续使用我们的服务,即表示同意受经修订的本《隐私权政策》的约束。 255 |

    256 | 257 |

    Promise - 承诺

    258 | 259 |

    260 | We appreciate the opportunity to provide you with products and 261 | services. We are committed to respecting and protecting the privacy 262 | and personal information you provide to us, and we want you to be 263 | aware of our Privacy Policy, including how your personal information 264 | is collected, used, and disclosed. 265 |

    266 | 267 |

    268 | 我们非常感谢能有机会为您提供产品和服务。我们承诺尊重及保护您提供的隐私及个人信息,也希望您能了解我们的隐私保护政策,包括如何采集、使用及披露您的个人信息。 269 |

    270 |
    271 |
    272 | 273 | 274 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /src/assets/css/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "inter"; 3 | src: url(./inter-ui-regular.woff) format("woff"); 4 | font-style: normal; 5 | font-weight: 400; 6 | } 7 | 8 | @font-face { 9 | font-family: "inter"; 10 | src: url(./inter-ui-medium.woff) format("woff"); 11 | font-style: normal; 12 | font-weight: 500; 13 | } 14 | 15 | @font-face { 16 | font-family: "inter"; 17 | src: url(./inter-ui-bold.woff) format("woff"); 18 | font-style: normal; 19 | font-weight: 700; 20 | } -------------------------------------------------------------------------------- /src/assets/css/inter-ui-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/src/assets/css/inter-ui-bold.woff -------------------------------------------------------------------------------- /src/assets/css/inter-ui-medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/src/assets/css/inter-ui-medium.woff -------------------------------------------------------------------------------- /src/assets/css/inter-ui-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/src/assets/css/inter-ui-regular.woff -------------------------------------------------------------------------------- /src/assets/icon/notionx-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/src/assets/icon/notionx-white.png -------------------------------------------------------------------------------- /src/assets/icon/notionx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scarsu/NotionX/66f3407ca285f1102ca6cb4479a437171cf984c2/src/assets/icon/notionx.png -------------------------------------------------------------------------------- /src/assets/svg/about.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/apple.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/collapse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/error.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/svg/firefox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/google.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/index.js: -------------------------------------------------------------------------------- 1 | const requireAll = (requireContext) => requireContext.keys().map(requireContext) 2 | // 指定svg文件 3 | const r = require.context('./', false, /.svg$/) 4 | requireAll(r) 5 | 6 | // 在src/main.js中引入此文件 7 | // import '@/assets/icon' 8 | -------------------------------------------------------------------------------- /src/assets/svg/keyboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/link-w.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/list-all.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/list-check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/svg/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/notion.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/notionx-svg.svg: -------------------------------------------------------------------------------- 1 | 2 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/assets/svg/notionx-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 168 | 169 | -------------------------------------------------------------------------------- /src/assets/svg/option.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/pin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/reset.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/right-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/svg/setting.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/svg/toc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/svg/windows.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import { EXTENSION_STORAGE_OPTION_KEY, CONTENT_DETECT } from '@/utils/constant' 3 | import { ORIGIN_OPTIONS } from '@/store/option' 4 | 5 | /** 6 | * background接收content消息 7 | * 1. 客户端侦测 8 | * 2. 客户端变更 9 | */ 10 | let contentTabId = null 11 | const platform = chrome || browser 12 | platform.runtime.onMessage.addListener(function (request, sender, sendResponse) { 13 | if (request.type === CONTENT_DETECT) { // 初始化:侦测到content后,根据local配置初始化 14 | if (process.env.NODE_ENV !== 'production') { 15 | console.log('NotionX: CONTENT_DETECT') 16 | } 17 | contentTabId = sender.tab.id 18 | effectLocal() 19 | } else if (request.type === 'DARK_MODE') { // 侦测到客户端配置变更后,更新插件存储 20 | if (process.env.NODE_ENV !== 'production') { 21 | console.log('NotionX: DARK_MODE_CHANGE_DETECT') 22 | } 23 | let localOptions = window.localStorage.getItem(EXTENSION_STORAGE_OPTION_KEY) 24 | if (localOptions === null) { 25 | localOptions = ORIGIN_OPTIONS 26 | } else { 27 | localOptions = JSON.parse(localOptions) 28 | } 29 | localOptions.forEach(i => { 30 | if (i.action === 'toggleDark') { 31 | i.value = request.value 32 | } 33 | }) 34 | window.localStorage.setItem(EXTENSION_STORAGE_OPTION_KEY, JSON.stringify(localOptions)) 35 | } 36 | return true 37 | }) 38 | 39 | /** 40 | * background发送消息至content 41 | * 获取background localStorage中的配置,发送至content执行 42 | */ 43 | function effectLocal () { 44 | let localOptions = window.localStorage.getItem(EXTENSION_STORAGE_OPTION_KEY) 45 | if (!localOptions) return 46 | localOptions = JSON.parse(localOptions).filter(i => i.scope === 'content') 47 | 48 | if (contentTabId) { 49 | platform.tabs.sendMessage(contentTabId, { 50 | type: 'actions', 51 | data: localOptions 52 | }) 53 | } else { 54 | console.warn('NotionX - background: ', '连接失败') 55 | } 56 | } 57 | 58 | // newUserVersionDetect 59 | function newUserVersionDetect () { 60 | if (window.localStorage.getItem(EXTENSION_STORAGE_OPTION_KEY) === null) { 61 | window.localStorage.setItem(EXTENSION_STORAGE_OPTION_KEY, {}) 62 | window.open('http://www.scarsu.cn/notionx/index.html') 63 | } 64 | } 65 | newUserVersionDetect() 66 | -------------------------------------------------------------------------------- /src/components/Tab.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/components/TabPanel.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | 33 | -------------------------------------------------------------------------------- /src/components/Toogle.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 33 | 73 | -------------------------------------------------------------------------------- /src/content-scripts/content-script.js: -------------------------------------------------------------------------------- 1 | import NotionX from './core' 2 | import '@/assets/svg' 3 | import './content.less' 4 | import { waitNotionPageReady, domObserver } from '@/utils/util' 5 | import Actions from '@/utils/Actions' 6 | import { 7 | NOTION_TOPBAR_SELECTOR, 8 | CONTENT_DETECT, 9 | } from '../utils/constant' 10 | 11 | const platform = chrome || browser 12 | 13 | // content发送消息至background,客户端侦测消息 14 | platform.runtime.sendMessage({ type: CONTENT_DETECT }) 15 | if (process.env.NODE_ENV !== 'production') { 16 | console.log('NotionX: CONTENT_DETECT') 17 | } 18 | 19 | // content接收background消息,执行命令 20 | platform.runtime.onMessage.addListener(function (request, sender, sendResponse) { 21 | // console.log(sender.tab ? 'from a content script:' + sender.tab.url : 'from the extension') 22 | if (request.type === 'action') { 23 | try { 24 | if (process.env.NODE_ENV !== 'production') { 25 | console.log('NotionX: action,data:', request.data) 26 | } 27 | Actions[request.data.action].call(window, request.data) 28 | } catch (e) { 29 | console.error(`NotionX - content: 执行命令${request.data.action}失败`) 30 | console.error(e) 31 | } 32 | } 33 | if (request.type === 'actions') { 34 | if (process.env.NODE_ENV !== 'production') { 35 | console.log('NotionX: actions,data:', request.data) 36 | } 37 | request.data.forEach(a => { 38 | if (a.scope === 'content') { 39 | waitNotionPageReady(a.pageCheckSelector || undefined).then(() => { 40 | try { 41 | Actions[a.action].call(window, a) 42 | } catch (e) { 43 | console.error(`NotionX - content: 执行命令${a.action}失败`) 44 | console.error(e) 45 | } 46 | }) 47 | } 48 | }) 49 | } 50 | return true 51 | }) 52 | 53 | // 监控dark mode+compact mode 客户端变更,发送消息至background 54 | waitNotionPageReady(NOTION_TOPBAR_SELECTOR).then(() => { 55 | if (!window.notionx) window.notionx = new NotionX() 56 | 57 | domObserver('.notion-body', mutationList => { 58 | const value = mutationList[0]?.target?.classList.contains('dark') 59 | if (value === undefined) return 60 | platform.runtime.sendMessage({ type: 'DARK_MODE', value }) 61 | }, { 62 | attributes: true, 63 | attributeFilter: ['class'], 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /src/content-scripts/template.js: -------------------------------------------------------------------------------- 1 | const template = { 2 | notionx: ` 3 |
    4 | 77 |
    78 | `, 79 | sideBarBtn: ` 80 |
    81 |
    82 |
    83 |
    84 | 87 |
    88 |
    89 |
    90 |
    91 | 94 |
    95 |
    96 |
    97 |
    98 | `, 99 | darkBtn: ` 100 |
    101 | 102 | 103 |
    104 | `, 105 | } 106 | // 转换图片资源路径 107 | function _adapterImg (obj) { 108 | // for (const key in obj) { 109 | // const str = obj[key] 110 | // str.replace(/ h(App), 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "NotionX ( for Notion )", 4 | "homepage_url": "http://scarsu.cn/notionx/", 5 | "description": "A Browser Extension that enhances Notion experience.", 6 | "default_locale": "en", 7 | "permissions": [ 8 | "https://*.notion.so/*" 9 | ], 10 | "icons": { 11 | "16": "icons/notionx-white.png", 12 | "48": "icons/notionx-white.png", 13 | "128": "icons/notionx-white.png" 14 | }, 15 | "background": { 16 | "persistent": false, 17 | "scripts": ["js/background.js"] 18 | }, 19 | "content_scripts": 20 | [ 21 | { 22 | "matches": ["https://*.notion.so/*"], 23 | "js": ["js/content-script.js"], 24 | "css": ["css/content-script.css"], 25 | "run_at": "document_idle" 26 | } 27 | ], 28 | "browser_action": { 29 | "default_popup": "popup.html", 30 | "default_title": "NotionX ( for Notion )", 31 | "default_icon": { 32 | "19": "icons/notionx-white.png", 33 | "38": "icons/notionx-white.png" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/options/App.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | 23 | 28 | -------------------------------------------------------------------------------- /src/options/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | /* eslint-disable no-new */ 5 | new Vue({ 6 | el: '#app', 7 | render: (h) => h(App), 8 | }) 9 | -------------------------------------------------------------------------------- /src/popup/App.vue: -------------------------------------------------------------------------------- 1 | 89 | 90 | 141 | 142 | 327 | -------------------------------------------------------------------------------- /src/popup/index.scss: -------------------------------------------------------------------------------- 1 | /* ==================== 基建 start */ 2 | *{ 3 | box-sizing: border-box; 4 | } 5 | html{ 6 | font-size: 1px; 7 | padding: 0; 8 | margin: 0; 9 | } 10 | body{ 11 | --bodyWidth: 400px; 12 | --bodyHeight: 460px; 13 | --fontColor: rgba(25, 25, 25, 0.7); 14 | --fontColorDark: rgba(25, 25, 25, 1); 15 | --fontColorLight: rgba(25, 25, 25, 0.6); 16 | --borderColor: rgba(0,0,0,0.1); 17 | --bgColor: #3e3e63; 18 | --bgColorLight: rgb(124 133 193); 19 | --gray: rgba(77, 35, 35, 0.2); 20 | --lightGray: rgba(0,0,0,0.05); 21 | --navHeight: 30px; 22 | --tabHeight: 360px; 23 | --tabWidth: 360px; 24 | --contentHeight: 390px; 25 | padding: 0; 26 | margin: 0; 27 | font-size: 12rem; 28 | color: var(--fontColor); 29 | } 30 | a{ 31 | color: var(--fontColor); 32 | &:hover{ 33 | color: var(--fontColorDark); 34 | } 35 | } 36 | ::-webkit-scrollbar { 37 | width: 8px; 38 | height: 8px; 39 | } 40 | ::-webkit-scrollbar { 41 | background: transparent; 42 | } 43 | ::-webkit-scrollbar-thumb { 44 | background: var(--gray); 45 | } 46 | ::-webkit-scrollbar-track { 47 | background: var(--lightGray); 48 | } 49 | *::selection { 50 | background: rgba(45,170,219,0.3); 51 | } 52 | /* ==================== 基建 end */ -------------------------------------------------------------------------------- /src/popup/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import store from '@/store' 4 | import i18n from '@/utils/i18n' 5 | 6 | /* eslint-disable no-new */ 7 | const app = new Vue({ 8 | store, 9 | render: (h) => h(App), 10 | }) 11 | 12 | Vue.use(i18n, { app }) 13 | 14 | app.$mount('#app') 15 | export default app 16 | -------------------------------------------------------------------------------- /src/popup/page/AboutPage.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 18 | 30 | -------------------------------------------------------------------------------- /src/popup/page/OptionPage.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 116 | 224 | -------------------------------------------------------------------------------- /src/popup/page/ShortcutPage.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 119 | 223 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'Home', 11 | component: Home, 12 | }, 13 | { 14 | path: '/about', 15 | name: 'About', 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 17 | }, 18 | ] 19 | 20 | const router = new VueRouter({ 21 | routes, 22 | }) 23 | 24 | export default router 25 | -------------------------------------------------------------------------------- /src/standalone/main.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue' 2 | // import App from './App.vue' 3 | // /* eslint-disable no-new */ 4 | // new Vue({ 5 | // el: '#app', 6 | // render: (h) => h(App) 7 | // }) 8 | 9 | const path = require('path') 10 | const fs = require('fs') 11 | 12 | let mdContent = fs.readFileSync(path.resolve('./README.md'), 'utf-8') 13 | let mdContentCn = fs.readFileSync(path.resolve('./README.zh-CN.md'), 'utf-8') 14 | mdContent = mdContent.replace('English | [简体中文](./README.zh-CN.md)', '') 15 | mdContentCn = mdContentCn.replace('简体中文 | [English](./README.md)', '') 16 | 17 | const md = require('markdown-it')() 18 | .use(require('markdown-it-table-of-contents'), { 19 | includeLevel: [2, 3] 20 | }) 21 | .use(require('markdown-it-anchor')) 22 | let _html = md.render(mdContent) 23 | let _htmlCn = md.render(mdContentCn) 24 | const template = fs.readFileSync(path.resolve('./public/index.template.html'), 'utf8') 25 | _html = template.replace('', _html) 26 | _htmlCn = template.replace('', _htmlCn) 27 | fs.writeFileSync(path.resolve('./dist/index.html'), _html, { 28 | encoding: 'utf8', 29 | mode: 0o666, 30 | flags: 'w', 31 | }) 32 | fs.writeFileSync(path.resolve('./dist/index_cn.html'), _htmlCn, { 33 | encoding: 'utf8', 34 | mode: 0o666, 35 | flags: 'w', 36 | }) 37 | console.log(require('chalk').bgGreen(' Done ') + ' index.html generated from README.md successfully.') 38 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import option from './option' 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | locale: 'en' 10 | }, 11 | mutations: { 12 | setLang (state, locale) { 13 | state.locale = locale 14 | } 15 | }, 16 | modules: { 17 | option: option 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /src/store/option.js: -------------------------------------------------------------------------------- 1 | import { 2 | EXTENSION_STORAGE_OPTION_KEY, 3 | LANGS 4 | } from '@/utils/constant' 5 | import Actions from '@/utils/Actions' 6 | import locales from '@public/_locales/locales.json' 7 | 8 | export const ORIGIN_OPTIONS = [ 9 | { 10 | action: 'changeLang', 11 | name: 'changeLang', 12 | desc: 'changeLangDesc', 13 | value: 'en', 14 | type: 'select', 15 | options: locales, 16 | hide: false, 17 | scope: 'popup', 18 | }, 19 | { 20 | action: 'hideComments', // 命令名称/处理函数 21 | type: 'switch', // 配置类型 22 | name: 'hideComments', // 配置项名称 23 | desc: 'hideCommentsDesc', // 配置项描述 24 | value: false, // 值 25 | hide: false, // 不再显示此配置项 26 | scope: 'content', // 作用域 27 | pageCheckSelector: '.notion-page-content', // 页面初始化时需要等到此dom加载后再执行命令 28 | }, 29 | { 30 | action: 'disableNotionX', 31 | type: 'switch', 32 | name: 'disableNotionX', 33 | desc: 'disableNotionXDesc', 34 | value: false, 35 | hide: true, 36 | scope: 'content', 37 | pageCheckSelector: '.notion-page-content', 38 | }, 39 | { 40 | action: 'showScrollToTop', 41 | name: 'showScrollToTop', 42 | desc: 'showScrollToTopDesc', 43 | value: false, 44 | type: 'switch', 45 | hide: false, 46 | scope: 'content', 47 | }, 48 | { 49 | action: 'hideHelpBtn', 50 | type: 'switch', 51 | name: 'hideHelpBtn', 52 | desc: 'hideHelpBtnDesc', 53 | value: false, 54 | hide: false, 55 | scope: 'content', 56 | pageCheckSelector: '.notion-page-content', 57 | }, 58 | { 59 | action: 'hideAddBtn', 60 | type: 'switch', 61 | name: 'hideAddBtn', 62 | desc: 'hideAddBtnDesc', 63 | value: false, 64 | hide: false, 65 | scope: 'content', 66 | pageCheckSelector: '.notion-page-content', 67 | }, 68 | { 69 | action: 'toggleDark', 70 | name: 'toggleDark', 71 | desc: 'toggleDarkDesc', 72 | value: false, 73 | type: 'switch', 74 | hide: false, 75 | scope: 'content', 76 | }, 77 | { 78 | action: 'toggleCompact', 79 | name: 'toggleCompact', 80 | desc: 'toggleCompactDesc', 81 | value: false, 82 | type: 'switch', 83 | hide: false, 84 | scope: 'content', 85 | }, 86 | { 87 | action: 'toggleCodeLineNum', 88 | name: 'toggleCodeLineNum', 89 | desc: 'toggleCodeLineNumDesc', 90 | value: false, 91 | type: 'switch', 92 | hide: false, 93 | scope: 'content', 94 | }, 95 | { 96 | action: 'openInDesktop', 97 | name: 'openInDesktop', 98 | desc: 'openInDesktopDesc', 99 | value: null, 100 | type: 'button', 101 | hide: false, 102 | scope: 'content', 103 | needLoading: 2000 104 | }, 105 | { 106 | action: 'genHeaderNumber', 107 | name: 'genHeaderNumber', 108 | desc: 'genHeaderNumberDesc', 109 | value: null, 110 | type: 'button', 111 | hide: false, 112 | scope: 'content', 113 | needLoading: 1000 114 | }, 115 | { 116 | action: 'setCodeLang', 117 | name: 'setCodeLang', 118 | desc: 'setCodeLangDesc', 119 | value: 'en', 120 | type: 'select', 121 | options: LANGS, 122 | hide: false, 123 | scope: 'content', 124 | needLoading: 2000 125 | }, 126 | { 127 | action: 'preventTableOverflow', 128 | name: 'preventTableOverflow', 129 | desc: 'preventTableOverflowDesc', 130 | value: false, 131 | type: 'switch', 132 | hide: false, 133 | scope: 'content', 134 | }, 135 | { 136 | action: 'hideNotionXSidebar', 137 | name: 'hideNotionXSidebar', 138 | desc: 'hideNotionXSidebarDesc', 139 | value: false, 140 | type: 'switch', 141 | hide: false, 142 | scope: 'content', 143 | }, 144 | { 145 | action: 'hideNotionXDarkMode', 146 | name: 'hideNotionXDarkMode', 147 | desc: 'hideNotionXDarkModeDesc', 148 | value: false, 149 | type: 'switch', 150 | hide: false, 151 | scope: 'content', 152 | }, 153 | { 154 | action: 'resetOptions', 155 | name: 'resetOptions', 156 | desc: 'resetOptionsDesc', 157 | value: null, 158 | type: 'button', 159 | hide: false, 160 | scope: 'all', 161 | }, 162 | // { 163 | // action: 'copyToken', 164 | // name: 'copyToken', 165 | // desc: 'copyTokenDesc', 166 | // value: null, 167 | // type: 'button', 168 | // hide: false, 169 | // scope: 'content', 170 | // }, 171 | ] 172 | 173 | // 深拷贝 174 | const options = ORIGIN_OPTIONS.map(e => { 175 | return { ...e } 176 | }) 177 | 178 | // types: switch select slider input color-picker 179 | export default { 180 | state: () => ({ 181 | items: options 182 | }), 183 | mutations: { 184 | updateOption (state, { option, needEffect = false }) { 185 | const i = state.items.findIndex(o => o.action === option.action) 186 | if (i > -1) { 187 | // 只允许变更部分字段 188 | state.items[i].value = option.value 189 | state.items[i].hide = option.hide 190 | } 191 | 192 | window.localStorage.setItem(EXTENSION_STORAGE_OPTION_KEY, JSON.stringify(state.items)) 193 | 194 | if (needEffect) { 195 | handleOption.call(this, state.items[i]) 196 | } 197 | }, 198 | updateOptions (state, { options, needEffect = false, scope = '' }) { 199 | options.forEach(e => { 200 | const i = state.items.findIndex(o => o.action === e.action) 201 | if (i > -1) { 202 | // 只允许变更部分字段 203 | state.items[i].value = e.value 204 | state.items[i].hide = e.hide 205 | } 206 | }) 207 | 208 | window.localStorage.setItem(EXTENSION_STORAGE_OPTION_KEY, JSON.stringify(state.items)) 209 | 210 | if (needEffect) { 211 | state.items 212 | .filter(i => !scope || scope === i.scope) 213 | .forEach(item => handleOption.call(this, item)) 214 | } 215 | } 216 | }, 217 | getters: { 218 | // 插件启用状态 219 | active: state => { 220 | const option = state.items.find(o => o.action === 'disableNotionX') 221 | return !option.value 222 | } 223 | } 224 | } 225 | 226 | /** 227 | * 单个配置处理 228 | * @param {*} option 配置项 229 | * @param {*} event 触发事件 230 | */ 231 | export function handleOption (option, event) { 232 | // 更新option值 233 | if (event) { 234 | if (option.type === 'switch') { 235 | option.value = !option.value 236 | } else if (option.type === 'select') { 237 | option.value = event.currentTarget.value 238 | } 239 | this.$store.commit('updateOption', { option }) 240 | } 241 | 242 | // 执行命令,传递event 243 | const para = { 244 | ...option, 245 | event 246 | } 247 | if (option.scope === 'content') { 248 | contentAction(para) 249 | } else if (option.scope === 'popup') { 250 | Actions[option.action].call(this, para) 251 | } else if (option.scope === 'all') { 252 | Actions[option.action].call(this, para) 253 | } 254 | } 255 | 256 | /** 257 | * 向content传递消息(当前active的tab 258 | * @param {*} option 需要客户端处理的配置项 259 | */ 260 | export function contentAction (option) { 261 | const cb = function (tabs) { 262 | const contentTabId = tabs[0].id 263 | const inCb = function (response) { 264 | if (response && response.success) { 265 | if (process.env.NODE_ENV !== 'production') { 266 | console.log(response.message) 267 | } 268 | } else { 269 | console.warn('NotionX - popup : ', '连接失败') 270 | } 271 | } 272 | option.event = !!option.event // 不可直接传event对象 273 | if (chrome) { 274 | chrome.tabs.sendMessage(contentTabId, { 275 | type: 'action', 276 | data: option 277 | }, inCb) 278 | } else { 279 | browser.tabs.sendMessage(contentTabId, { 280 | type: 'action', 281 | data: option 282 | }).then(inCb) 283 | } 284 | } 285 | if (chrome) { 286 | chrome.tabs.query({ active: true, currentWindow: true }, cb) 287 | } else { 288 | browser.tabs.query({ active: true, currentWindow: true }).then(cb) 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/utils/Actions.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import { domObserver, mutateKeys, getLocalNotionXState, mask } from '../utils/util' 3 | import { NOTION_APP_SELECTOR } from '../utils/constant' 4 | import { ORIGIN_OPTIONS } from '../store/option' 5 | /** 6 | * 定义所有用户网页行为 7 | */ 8 | const Actions = { 9 | // content 隐藏页首评论 10 | hideComments: function (data) { 11 | const $dom = document.querySelector('.notion-page-view-discussion') 12 | if (!$dom) return 13 | if (data.value) { 14 | $dom.parentElement.style.display = 'none' 15 | } else { 16 | $dom.parentElement.style.display = '' 17 | } 18 | }, 19 | // content 隐藏帮助按钮 20 | hideHelpBtn: function (data) { 21 | const $dom = document.querySelector('.notion-help-button') 22 | if (!$dom) return 23 | if (data.value) { 24 | $dom.style.display = 'none' 25 | } else { 26 | $dom.style.display = 'flex' 27 | } 28 | }, 29 | // content 隐藏table的New按钮 30 | hideAddBtn: function (data) { 31 | const $notion = document.querySelector('.notion-body') 32 | const currentCompact = $notion.classList.contains('notionx-hide-table-new') 33 | if (data.value && !currentCompact) { 34 | $notion.classList.add('notionx-hide-table-new') 35 | } else if (!data.value && currentCompact) { 36 | $notion.classList.remove('notionx-hide-table-new') 37 | } 38 | }, 39 | // content 禁用插件 40 | disableNotionX: function (data) { 41 | Actions.hideNotionXSidebar(data) 42 | }, 43 | // content 隐藏NotionX的侧边栏 44 | hideNotionXSidebar: function (data) { 45 | const $dom = document.querySelector('#notionx') 46 | if (!$dom) return 47 | 48 | if (data.value) { 49 | document.querySelector('#notionx').style.display = 'none' 50 | document.querySelector('#notionx-sidebar-btn').style.display = 'none' 51 | if (window.notionx) window.notionx.__ob__.stop() 52 | } else { 53 | document.querySelector('#notionx').style.display = '' 54 | document.querySelector('#notionx-sidebar-btn').style.display = '' 55 | const state = getLocalNotionXState()?.fsmState 56 | if (state === 'hide') { 57 | if (window.notionx && window.notionx.__ob__) window.notionx.__ob__.stop() 58 | } else { 59 | if (window.notionx && window.notionx.__ob__) window.notionx.__ob__.start() 60 | } 61 | } 62 | }, 63 | // content 隐藏NotionX的暗黑模式按钮 64 | hideNotionXDarkMode: function (data) { 65 | const $dom = document.querySelector('#notionx-dark-btn') 66 | if (!$dom) return 67 | 68 | if (data.value) { 69 | document.querySelector('#notionx-dark-btn').style.display = 'none' 70 | } else { 71 | document.querySelector('#notionx-dark-btn').style.display = 'flex' 72 | } 73 | }, 74 | // popup 切换语言 75 | changeLang: function (data) { 76 | const $store = this.$store || this 77 | const commit = $store.commit 78 | commit('setLang', data.value || 'en') 79 | }, 80 | // content 在桌面端中打开当前页面 81 | openInDesktop: function (data) { 82 | if (data.event) { 83 | var iframe = document.createElement('iframe') 84 | var body = document.body 85 | iframe.style.display = 'none' 86 | body.appendChild(iframe) 87 | iframe.src = 'notion:' + location.pathname 88 | } 89 | }, 90 | // content 生成标题序号 91 | genHeaderNumber: function (data) { 92 | if (data.event) { 93 | // 获取所有的header 94 | var $headers = [...document.querySelectorAll(`.notion-header-block, 95 | .notion-sub_header-block, 96 | .notion-sub_sub_header-block`)] 97 | // 遍历生成序号,固定格式: 98 | // level1 x. 99 | // level2 x.x. 100 | // level3 x.x.x. 101 | let outermostLevel = 0 // 最外层的level 102 | let lastPrefix = '' // 上一项的前缀 103 | let lastLevel = 0 // 上一项的level 104 | for (let i = 0; i < $headers.length; i++) { 105 | const $header = $headers[i] 106 | const level = $header.classList.contains('notion-header-block') 107 | ? 1 : $header.classList.contains('notion-sub_header-block') 108 | ? 2 : 3 109 | let curPrefix = '' 110 | if (i === 0) { 111 | outermostLevel = level 112 | curPrefix = '1.' 113 | } else { 114 | if (level < outermostLevel) { 115 | // 不规范格式,直接停止转换 116 | break 117 | } 118 | if (level === lastLevel) { 119 | // 同一层级 120 | curPrefix = leftMoveAndAddSeq(lastPrefix, 0) 121 | } 122 | if (level > lastLevel) { 123 | // 下一层级 124 | curPrefix = lastPrefix + 1 + '.' 125 | } 126 | if (level < lastLevel) { 127 | // 外层 128 | if (lastLevel - level === 1) { 129 | if (lastPrefix.length < 4) break 130 | curPrefix = leftMoveAndAddSeq(lastPrefix, 1) 131 | } else if (lastLevel - level === 2) { 132 | if (lastPrefix.length < 6) break 133 | curPrefix = leftMoveAndAddSeq(lastPrefix, 2) 134 | } 135 | } 136 | } 137 | 138 | // 删除之前生成的prefix 139 | const originContent = removeOldPrefix($header.textContent) 140 | // 更改dom 141 | const $edit = $header.querySelector('[data-content-editable-leaf][contenteditable]') 142 | $edit.textContent = curPrefix + ' ' + originContent 143 | // 手动触发input event 以触发notion进行远程更新 144 | $edit.dispatchEvent(new Event('input', { 145 | bubbles: true, 146 | cancelable: true, 147 | })) 148 | setTimeout(() => { 149 | $edit.dispatchEvent(new Event('input', { 150 | bubbles: true, 151 | cancelable: true, 152 | })) 153 | }, 0) 154 | // 更新变量 155 | lastPrefix = curPrefix 156 | lastLevel = level 157 | } 158 | } 159 | }, 160 | // content 切换暗黑模式 161 | toggleDark: function (data) { 162 | const $notion = document.querySelector('.notion-body') 163 | const currentDark = $notion.classList.contains('dark') 164 | if ( 165 | (data.value && !currentDark) || 166 | (!data.value && currentDark) 167 | ) { 168 | mutateKeys(true, true, 'L', 76) 169 | } 170 | }, 171 | // content 紧凑模式 172 | toggleCompact: function (data) { 173 | const $notion = document.querySelector('.notion-body') 174 | const currentCompact = $notion.classList.contains('notionx-compact') 175 | if (data.value && !currentCompact) { 176 | $notion.classList.add('notionx-compact') 177 | } else if (!data.value && currentCompact) { 178 | $notion.classList.remove('notionx-compact') 179 | } 180 | }, 181 | // content 显示行号 182 | toggleCodeLineNum: function (data) { 183 | // 函数: 显示/更新行号 184 | const lineNumShow = () => { 185 | const $codeBlocks = document.querySelectorAll('.line-numbers.notion-code-block') 186 | if (!$codeBlocks) return 187 | $codeBlocks.forEach($codeBlock => { 188 | // 计算最新行数 189 | const $code = $codeBlock.querySelector('[contenteditable]') 190 | if (!$code) return 191 | const realH = $code.offsetHeight - 192 | parseFloat(getComputedStyle($code).getPropertyValue('border-top-width')) - 193 | parseFloat(getComputedStyle($code).getPropertyValue('border-bottom-width')) - 194 | parseFloat(getComputedStyle($code).getPropertyValue('padding-top')) - 195 | parseFloat(getComputedStyle($code).getPropertyValue('padding-bottom')) 196 | const lineH = parseFloat(getComputedStyle($code).getPropertyValue('line-height')) 197 | const font = getComputedStyle($code).getPropertyValue('font-family') 198 | const lineCount = Math.ceil(realH / lineH) // 计算行数 199 | let _inner = '' 200 | for (let i = 0; i < lineCount; i++) { 201 | _inner += `
    ${i + 1}
    ` 202 | } 203 | 204 | // 先判断是否已经存在行号 205 | let $lineNum = [...$codeBlock.children].find(i => i.classList.contains('notionx-code-lineNum')) 206 | // 存在则更新显示 207 | if ($lineNum) { 208 | $lineNum.style.display = 'block' 209 | $lineNum.style.lineHeight = lineH + 'px' 210 | $lineNum.style.fontFamily = font 211 | $lineNum.innerHTML = _inner 212 | } else { 213 | // 不存在则创建 214 | $lineNum = document.createElement('div') 215 | $lineNum.classList.add('notionx-code-lineNum') 216 | $lineNum.style.lineHeight = lineH + 'px' 217 | $lineNum.style.fontFamily = font 218 | 219 | $lineNum.innerHTML = _inner 220 | $codeBlock.prepend($lineNum) // 插入DOM 221 | } 222 | }) 223 | } 224 | // 函数: 隐藏行号 225 | const lineNumHide = () => { 226 | [...document.querySelectorAll('.notionx-code-lineNum')].forEach(e => { 227 | e.style.display = 'none' 228 | }) 229 | } 230 | 231 | // 通过mutationObserver动态更新,用节流函数限制更新次数 232 | if (data.value) { 233 | lineNumShow() 234 | const capacity = document.querySelectorAll('.line-numbers.notion-code-block').length 235 | let interval = 5000 236 | if (capacity === 0) { 237 | interval = 5000 238 | } else if (capacity <= 20) { 239 | interval = 500 240 | } else if (capacity <= 100) { 241 | interval = 1000 242 | } else if (capacity <= 200) { 243 | interval = 2000 244 | } 245 | window.lineNumOb = domObserver(NOTION_APP_SELECTOR, _.debounce(lineNumShow, interval, { leading: true, trailing: true, maxWait: interval })) 246 | } else { 247 | if (window.lineNumOb) { 248 | window.lineNumOb.disconnect() 249 | window.lineNumOb = null 250 | lineNumHide() 251 | } 252 | } 253 | }, 254 | // content 复制token 255 | copyToken: function (data) { 256 | if (data.event) { 257 | 258 | } 259 | }, 260 | // all 还原全部设置 261 | resetOptions: function (data) { 262 | if (data.event) { 263 | const $store = this.$store || this 264 | const commit = $store.commit 265 | commit('updateOptions', { options: ORIGIN_OPTIONS, needEffect: true }) 266 | } 267 | }, 268 | // content 显示totop按钮 269 | showScrollToTop: function (data) { 270 | const $top = document.querySelector('.notionx-totop') 271 | const exist = !!$top 272 | const show = !!$top && $top.classList.contains('show') 273 | if (data.value && !exist) { 274 | const $sibling = document.querySelector('.notion-help-button') || 275 | document.querySelector('#notionx') 276 | if (!$sibling) return false 277 | const $p = $sibling.parentElement 278 | const $totop = document.createElement('div') 279 | $totop.innerHTML = '⭡' 280 | $totop.classList.add('notionx-totop') 281 | $totop.classList.add('show') 282 | $p.insertBefore($totop, $sibling) 283 | $totop.addEventListener('click', function () { 284 | document.querySelector('.notion-scroller.vertical.horizontal').style.scrollBehavior = 'smooth' 285 | document.querySelector('.notion-scroller.vertical.horizontal').scrollTop = 0 286 | }) 287 | } else if (data.value && !show) { 288 | $top.classList.add('show') 289 | } else if (!data.value && show) { 290 | $top.classList.remove('show') 291 | } 292 | }, 293 | // content 阻止表格溢出 294 | preventTableOverflow: function (data) { 295 | const $notion = document.querySelector('.notion-body') 296 | const prevented = $notion.classList.contains('notionx-prevent-table-overflow') 297 | if (data.value && !prevented) { 298 | $notion.classList.add('notionx-prevent-table-overflow') 299 | } else if (!data.value && prevented) { 300 | $notion.classList.remove('notionx-prevent-table-overflow') 301 | } 302 | }, 303 | // content 设置当前页面所有代码块的语言 304 | setCodeLang: function (data) { 305 | if (data.event) { 306 | const lang = data.value 307 | if (!lang) return 308 | mask().show() 309 | const codeLangTriggers = [...document.querySelectorAll('.notion-code-block>div>div>div>div[role=button]')] 310 | codeLangTriggers.forEach((e) => { 311 | e.click() 312 | }) 313 | setTimeout(() => { 314 | const langSelectors = [...document.querySelectorAll('.notion-scroller.vertical>div>div>div[role=button][tabindex="0"]>div>div>div')] 315 | if (langSelectors.length === 0) { 316 | const langSelectors = [...document.querySelectorAll('.notion-scroller.vertical>div>div>div[role=button][tabindex="0"]>div>div>div')] 317 | langSelectors.filter((e) => e.textContent.toLowerCase() === lang.toLowerCase()).forEach((e) => { 318 | e.click() 319 | }) 320 | } 321 | langSelectors.filter((e) => e.textContent.toLowerCase() === lang.toLowerCase()).forEach((e) => { 322 | e.click() 323 | }) 324 | }, 200) 325 | setTimeout(() => { 326 | mask().hide() 327 | }, 200) 328 | } 329 | } 330 | } 331 | export default Actions 332 | 333 | // 删除最后gap个数字后seq+1 334 | function leftMoveAndAddSeq (str, gap) { 335 | const lastNumIndex = str.length - (gap + 1) * 2 336 | const lastNum = str[lastNumIndex] * 1 337 | return str.substr(0, lastNumIndex) + (lastNum + 1) + '.' 338 | } 339 | 340 | // 删除过去生成的序号 341 | function removeOldPrefix (content) { 342 | return content.replace(/^(\d\.\d\.\d\.\s)/, '').replace(/^(\d\.\d\.\s)/, '').replace(/^(\d\.\s)/, '') 343 | } 344 | -------------------------------------------------------------------------------- /src/utils/constant.js: -------------------------------------------------------------------------------- 1 | export const NOTION_APP_SELECTOR = '#notion-app' 2 | export const NOTION_CONTENT_SELECTOR = '.notion-page-content' 3 | export const NOTION_TOPBAR_SELECTOR = '.notion-topbar>div' 4 | export const NOTION_SCROLLER_SELECTOR = '.notion-scroller' 5 | export const NOTION_WRAPPER_SELECTOR = '.notion-cursor-listener' 6 | 7 | export const NOTIONX_STORE_KEY = 'notionx_2.1.3' 8 | 9 | export const DEFAULT_OPTS = { 10 | showDark: true, 11 | dark: false, 12 | hotKeys: '⌘+⇧+x', 13 | width: 220, 14 | viewKey: 'toc', 15 | fsmState: 'hide', 16 | expandStatus: null, 17 | genFlagList: null, 18 | } 19 | 20 | export const DEFAULT_VIEW_KEY = 'toc' 21 | export const MAX_WIDTH = 480 22 | export const MIN_WIDTH = 190 23 | export const EXTENSION_STORAGE_OPTION_KEY = 'notionx_options_2.1.3' 24 | export const CONTENT_DETECT = 'CONTENT_DETECT' 25 | export const COMMENT_STYLE = 'background:rgba(255,212,0,0.14);border-bottom:2px solid rgb(255, 212, 0);padding-bottom:2px' 26 | export const COLORS = [ 27 | { 28 | value: 'rgb(155, 154, 151)', 29 | name: 'font-gray', 30 | theme: 'light', 31 | type: 'font' 32 | }, 33 | { 34 | value: 'rgb(100, 71, 58)', 35 | name: 'font-brown', 36 | theme: 'light', 37 | type: 'font' 38 | }, 39 | { 40 | value: 'rgb(217, 115, 13)', 41 | name: 'font-orange', 42 | theme: 'light', 43 | type: 'font' 44 | }, 45 | { 46 | value: 'rgb(223, 171, 1)', 47 | name: 'font-yellow', 48 | theme: 'light', 49 | type: 'font' 50 | }, 51 | { 52 | value: 'rgb(15, 123, 108)', 53 | name: 'font-green', 54 | theme: 'light', 55 | type: 'font' 56 | }, 57 | { 58 | value: 'rgb(11, 110, 153)', 59 | name: 'font-blue', 60 | theme: 'light', 61 | type: 'font' 62 | }, 63 | { 64 | value: 'rgb(105, 64, 165)', 65 | name: 'font-purple', 66 | theme: 'light', 67 | type: 'font' 68 | }, 69 | { 70 | value: 'rgb(173, 26, 114)', 71 | name: 'font-pink', 72 | theme: 'light', 73 | type: 'font' 74 | }, 75 | { 76 | value: 'rgb(224, 62, 62)', 77 | name: 'font-red', 78 | theme: 'light', 79 | type: 'font' 80 | }, 81 | { 82 | value: 'rgb(235, 236, 237)', 83 | name: 'background-gray', 84 | theme: 'light', 85 | type: 'background' 86 | }, 87 | { 88 | value: 'rgb(233, 229, 227)', 89 | name: 'background-brown', 90 | theme: 'light', 91 | type: 'background' 92 | }, 93 | { 94 | value: 'rgb(250, 235, 221)', 95 | name: 'background-orange', 96 | theme: 'light', 97 | type: 'background' 98 | }, 99 | { 100 | value: 'rgb(251, 243, 219)', 101 | name: 'background-yellow', 102 | theme: 'light', 103 | type: 'background' 104 | }, 105 | { 106 | value: 'rgb(221, 237, 234)', 107 | name: 'background-green', 108 | theme: 'light', 109 | type: 'background' 110 | }, 111 | { 112 | value: 'rgb(221, 235, 241)', 113 | name: 'background-blue', 114 | theme: 'light', 115 | type: 'background' 116 | }, 117 | { 118 | value: 'rgb(234, 228, 242)', 119 | name: 'background-purple', 120 | theme: 'light', 121 | type: 'background' 122 | }, 123 | { 124 | value: 'rgb(244, 223, 235)', 125 | name: 'background-pink', 126 | theme: 'light', 127 | type: 'background' 128 | }, 129 | { 130 | value: 'rgb(251, 228, 228)', 131 | name: 'background-red', 132 | theme: 'light', 133 | type: 'background' 134 | }, 135 | { 136 | value: 'rgba(151, 154, 155, 0.95)', 137 | name: 'font-gray', 138 | theme: 'dark', 139 | type: 'font' 140 | }, 141 | { 142 | value: 'rgb(147, 114, 100)', 143 | name: 'font-brown', 144 | theme: 'dark', 145 | type: 'font' 146 | }, 147 | { 148 | value: 'rgb(255, 163, 68)', 149 | name: 'font-orange', 150 | theme: 'dark', 151 | type: 'font' 152 | }, 153 | { 154 | value: 'rgb(255, 220, 73)', 155 | name: 'font-yellow', 156 | theme: 'dark', 157 | type: 'font' 158 | }, 159 | { 160 | value: 'rgb(77, 171, 154)', 161 | name: 'font-green', 162 | theme: 'dark', 163 | type: 'font' 164 | }, 165 | { 166 | value: 'rgb(82, 156, 202)', 167 | name: 'font-blue', 168 | theme: 'dark', 169 | type: 'font' 170 | }, 171 | { 172 | value: 'rgb(154, 109, 215)', 173 | name: 'font-purple', 174 | theme: 'dark', 175 | type: 'font' 176 | }, 177 | { 178 | value: 'rgb(226, 85, 161)', 179 | name: 'font-pink', 180 | theme: 'dark', 181 | type: 'font' 182 | }, 183 | { 184 | value: 'rgb(255, 115, 105)', 185 | name: 'font-red', 186 | theme: 'dark', 187 | type: 'font' 188 | }, 189 | { 190 | value: 'rgb(69, 75, 78)', 191 | name: 'background-gray', 192 | theme: 'dark', 193 | type: 'background' 194 | }, 195 | { 196 | value: 'rgb(67, 64, 64)', 197 | name: 'background-brown', 198 | theme: 'dark', 199 | type: 'background' 200 | }, 201 | { 202 | value: 'rgb(89, 74, 58)', 203 | name: 'background-orange', 204 | theme: 'dark', 205 | type: 'background' 206 | }, 207 | { 208 | value: 'rgb(89, 86, 59)', 209 | name: 'background-yellow', 210 | theme: 'dark', 211 | type: 'background' 212 | }, 213 | { 214 | value: 'rgb(53, 76, 75)', 215 | name: 'background-green', 216 | theme: 'dark', 217 | type: 'background' 218 | }, 219 | { 220 | value: 'rgb(54, 73, 84)', 221 | name: 'background-blue', 222 | theme: 'dark', 223 | type: 'background' 224 | }, 225 | { 226 | value: 'rgb(68, 63, 87)', 227 | name: 'background-purple', 228 | theme: 'dark', 229 | type: 'background' 230 | }, 231 | { 232 | value: 'rgb(83, 59, 76)', 233 | name: 'background-pink', 234 | theme: 'dark', 235 | type: 'background' 236 | }, 237 | { 238 | value: 'rgb(89, 65, 65)', 239 | name: 'background-red', 240 | theme: 'dark', 241 | type: 'background' 242 | }, 243 | ] 244 | export const LANGS = [ 245 | { value: 'ABAP', label: 'ABAP' }, 246 | { value: 'Arduino', label: 'Arduino' }, 247 | { value: 'Bash', label: 'Bash' }, 248 | { value: 'BASIC', label: 'BASIC' }, 249 | { value: 'C', label: 'C' }, 250 | { value: 'Clojure', label: 'Clojure' }, 251 | { value: 'CoffeeScript', label: 'CoffeeScript' }, 252 | { value: 'C++', label: 'C++' }, 253 | { value: 'C#', label: 'C#' }, 254 | { value: 'CSS', label: 'CSS' }, 255 | { value: 'Dart', label: 'Dart' }, 256 | { value: 'Diff', label: 'Diff' }, 257 | { value: 'Docker', label: 'Docker' }, 258 | { value: 'Elixir', label: 'Elixir' }, 259 | { value: 'Elm', label: 'Elm' }, 260 | { value: 'Erlang', label: 'Erlang' }, 261 | { value: 'Flow', label: 'Flow' }, 262 | { value: 'Fortran', label: 'Fortran' }, 263 | { value: 'F#', label: 'F#' }, 264 | { value: 'Gherkin', label: 'Gherkin' }, 265 | { value: 'GLSL', label: 'GLSL' }, 266 | { value: 'Go', label: 'Go' }, 267 | { value: 'GraphQL', label: 'GraphQL' }, 268 | { value: 'Groovy', label: 'Groovy' }, 269 | { value: 'Haskell', label: 'Haskell' }, 270 | { value: 'HTML', label: 'HTML' }, 271 | { value: 'Java', label: 'Java' }, 272 | { value: 'JavaScript', label: 'JavaScript' }, 273 | { value: 'JSON', label: 'JSON' }, 274 | { value: 'Kotlin', label: 'Kotlin' }, 275 | { value: 'LaTeX', label: 'LaTeX' }, 276 | { value: 'Less', label: 'Less' }, 277 | { value: 'Lisp', label: 'Lisp' }, 278 | { value: 'LiveScript', label: 'LiveScript' }, 279 | { value: 'Lua', label: 'Lua' }, 280 | { value: 'Makefile', label: 'Makefile' }, 281 | { value: 'Markdown', label: 'Markdown' }, 282 | { value: 'Markup', label: 'Markup' }, 283 | { value: 'MATLAB', label: 'MATLAB' }, 284 | { value: 'Mermaid', label: 'Mermaid' }, 285 | { value: 'Nix', label: 'Nix' }, 286 | { value: 'Objective-C', label: 'Objective-C' }, 287 | { value: 'OCaml', label: 'OCaml' }, 288 | { value: 'Pascal', label: 'Pascal' }, 289 | { value: 'Perl', label: 'Perl' }, 290 | { value: 'PHP', label: 'PHP' }, 291 | { value: 'Plain Text', label: 'Plain Text' }, 292 | { value: 'PowerShell', label: 'PowerShell' }, 293 | { value: 'Prolog', label: 'Prolog' }, 294 | { value: 'Python', label: 'Python' }, 295 | { value: 'R', label: 'R' }, 296 | { value: 'Reason', label: 'Reason' }, 297 | { value: 'Ruby', label: 'Ruby' }, 298 | { value: 'Rust', label: 'Rust' }, 299 | { value: 'Sass', label: 'Sass' }, 300 | { value: 'Scala', label: 'Scala' }, 301 | { value: 'Scheme', label: 'Scheme' }, 302 | { value: 'Scss', label: 'Scss' }, 303 | { value: 'Shell', label: 'Shell' }, 304 | { value: 'SQL', label: 'SQL' }, 305 | { value: 'Swift', label: 'Swift' }, 306 | { value: 'TypeScript', label: 'TypeScript' }, 307 | { value: 'VB.Net', label: 'VB.Net' }, 308 | { value: 'Verilog', label: 'Verilog' }, 309 | { value: 'VHDL', label: 'VHDL' }, 310 | { value: 'Visual Basic', label: 'Visual Basic' }, 311 | { value: 'WebAssembly', label: 'WebAssembly' }, 312 | { value: 'XML', label: 'XML' }, 313 | { value: 'YAML', label: 'YAML' } 314 | ] 315 | -------------------------------------------------------------------------------- /src/utils/i18n.js: -------------------------------------------------------------------------------- 1 | import EN from '@public/_locales/en/messages.json' 2 | import ZH_CN from '@public/_locales/zh-cn/messages.json' 3 | import KO from '@public/_locales/ko/messages.json' 4 | import JA_JP from '@public/_locales/ja-jp/messages.json' 5 | import UK from '@public/_locales/uk/messages.json' 6 | 7 | const locales = { 8 | en: EN, 9 | 'zh-cn': ZH_CN, 10 | ko: KO, 11 | 'ja-jp': JA_JP, 12 | uk: UK, 13 | } 14 | 15 | export default { 16 | install: function (Vue, { app }) { 17 | Vue.prototype.$t = function (key) { 18 | const locale = app.$store.state.locale 19 | const JSON = locales[locale] 20 | const JSON_FALLBACK = locales.en 21 | return JSON[key] ? JSON[key].message : JSON_FALLBACK[key] || key 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/svg.js: -------------------------------------------------------------------------------- 1 | const requireAll = (requireContext) => requireContext.keys().map(requireContext) 2 | const req = require.context('../assets/svg', true, /\.svg$/) 3 | requireAll(req) 4 | -------------------------------------------------------------------------------- /src/utils/util.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | import { 3 | NOTION_SCROLLER_SELECTOR, 4 | NOTIONX_STORE_KEY, 5 | // COLORS 6 | } from './constant' 7 | 8 | /** 9 | * DOM Observer 10 | * @param {string} selector The selector of the observed DOM 11 | * @param {function} cb Callback function executed when the DOM changes 12 | * @param {array} args arguments for callback 13 | */ 14 | export function domObserver (selector, cb, config) { 15 | const observer = new MutationObserver((arg) => { 16 | cb(arg) 17 | }) 18 | const el = document.querySelector(selector) 19 | config = config || { 20 | childList: true, 21 | subtree: true, 22 | characterData: true, 23 | } 24 | observer.observe(el, config) 25 | return observer 26 | } 27 | 28 | // notion page滚动到顶部 29 | export function scrollToTop () { 30 | $(NOTION_SCROLLER_SELECTOR).animate( 31 | { 32 | scrollTop: 0 33 | }, 34 | 200, 35 | null 36 | ) 37 | } 38 | 39 | // notion sidebar 滚动到顶部 40 | export function sideBarScrollToTop () { 41 | const e = document.querySelector('#notionx .notionx-views') 42 | if (e && e.nodeType) { 43 | e.style.scrollBehavior = 'smooth' 44 | e.scrollTop = 0 45 | } 46 | } 47 | 48 | /** 49 | * @param {string} selector :for judging the loading status of notion app 50 | */ 51 | export const waitNotionPageReady = (selector = '.notion-topbar>div') => new Promise((resolve) => { 52 | const max = 100 53 | let i = 0 54 | const delay = 500 55 | const f = () => { 56 | i++ 57 | const element = document.querySelectorAll(selector) 58 | if (i > max || (element.length > 0)) { 59 | resolve(element) 60 | } else { 61 | setTimeout(f, delay) 62 | } 63 | } 64 | f() 65 | }) 66 | 67 | // 设置cookie 68 | function setCookie (cName, cvalue, exdays) { 69 | var d = new Date() 70 | d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)) 71 | var expires = 'expires=' + d.toUTCString() 72 | document.cookie = cName + '=' + JSON.stringify(cvalue) + '; ' + expires + ';path=/' 73 | } 74 | 75 | // 获取cookie 76 | function getCookie (cName) { 77 | var name = cName + '=' 78 | var cookieOBJ = document.cookie.split(';') 79 | for (var i = 0; i < cookieOBJ.length; i++) { 80 | var item = cookieOBJ[i] 81 | while (item.charAt(0) === ' ') item = item.substring(1) 82 | if (item.indexOf(name) !== -1) return JSON.parse(item.substring(name.length, item.length)) 83 | } 84 | return '' 85 | } 86 | 87 | // 删除cookie 88 | function clearCookie (name) { 89 | setCookie(name, '', '-1') 90 | } 91 | 92 | export const cookie = { 93 | set: setCookie, 94 | get: getCookie, 95 | clear: clearCookie 96 | } 97 | 98 | // 模拟按键 99 | export function mutateKeys (ctrlKey = false, shiftKey = false, key) { 100 | key = key?.toUpperCase() 101 | const keyCode = key.charCodeAt() 102 | var e = new KeyboardEvent( 103 | 'keydown', 104 | { 105 | bubbles: true, 106 | cancelable: true, 107 | key: key, 108 | char: key, 109 | keyCode: keyCode, 110 | ctrlKey: ctrlKey, 111 | shiftKey: shiftKey 112 | }) 113 | return document.body.dispatchEvent(e) 114 | } 115 | 116 | // 更新notionx本地存储 117 | export function setLocalNotionXState (data) { 118 | localStorage.setItem( 119 | NOTIONX_STORE_KEY, 120 | JSON.stringify(data) 121 | ) 122 | } 123 | export function getLocalNotionXState () { 124 | return JSON.parse(localStorage.getItem(NOTIONX_STORE_KEY) || '{}') 125 | } 126 | 127 | // adapt to various page situations and find our button's container 128 | // 找到notion页面header节点 129 | export function adapterNotionHeader () { 130 | const siblings = [ 131 | '.notion-topbar-share-menu', 132 | '.notion-topbar-more-button', 133 | ] 134 | for (let i = 0; i < siblings.length; i++) { 135 | const selector = siblings[i] 136 | const node = document.querySelector(selector) 137 | const p = node?.parentElement || node?.parentNode 138 | if (p && p.nodeType) { 139 | return p 140 | } 141 | } 142 | const node = document.querySelector('.notionLogo') 143 | const p = node?.parentElement?.parentElement || node?.parentNode?.parentNode 144 | if (p && p.nodeType) { 145 | return p 146 | } 147 | return '.notion-topbar>div' 148 | } 149 | 150 | // 根据blockId获取DOM 151 | export function getBlockNode (id) { 152 | return document.querySelector(`[data-block-id="${id}"]`) 153 | } 154 | 155 | // 滚动至block 156 | export function scrollToBlock (id) { 157 | const node = getBlockNode(id) 158 | document.body.click() 159 | node && setTimeout(() => { 160 | node.scrollIntoView({ 161 | behavior: 'smooth', 162 | block: 'start', 163 | }) 164 | }, 0) 165 | } 166 | 167 | // 全屏遮罩 168 | export function mask () { 169 | let $mask = $('.notionx-mask') 170 | if ($mask.length === 0) { 171 | $mask = $(` 172 | 177 | `) 178 | document.body.appendChild($mask[0]) 179 | } 180 | return { 181 | show () { 182 | $mask.show() 183 | }, 184 | hide () { 185 | $mask.hide() 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resolve = (dir) => path.join(__dirname, '.', dir) 4 | 5 | module.exports = { 6 | pages: { 7 | popup: { 8 | template: 'public/browser-extension.html', 9 | entry: './src/popup/main.js', 10 | title: 'Popup', 11 | }, 12 | }, 13 | pluginOptions: { 14 | browserExtension: { 15 | componentOptions: { 16 | contentScripts: { 17 | entries: { 18 | 'content-script': [ 19 | 'src/content-scripts/content-script.js', 20 | ], 21 | }, 22 | }, 23 | background: { 24 | entry: 'src/background.js', 25 | }, 26 | }, 27 | }, 28 | }, 29 | configureWebpack: config => { 30 | config.output.publicPath = './' 31 | }, 32 | filenameHashing: false, 33 | css: { 34 | extract: true, 35 | }, 36 | chainWebpack: (config) => { 37 | config.resolve.alias.set('@public', resolve('public')) 38 | // svg 39 | config.module 40 | .rule('svg') 41 | .exclude.add(resolve('src/assets/svg')) 42 | .end() 43 | config.module 44 | .rule('icon') 45 | .test(/\.svg$/) 46 | .include.add(resolve('src/assets/svg')) 47 | .end() 48 | .use('svg-sprite-loader') 49 | .loader('svg-sprite-loader') 50 | .options({ 51 | symbolId: 'icon-[name]', 52 | }) 53 | .end() 54 | }, 55 | } 56 | --------------------------------------------------------------------------------