├── .readme.assets ├── bs.gif ├── dagang.gif ├── html-1730953102113-3.gif ├── html.gif ├── image-20240805221400275.png ├── image-20240805221515120.png ├── image-20240805221953206.png ├── image-20240805222137381.png ├── image-20240805222339944.png ├── image-20240805223213943.png ├── image-20240805232704516.png ├── image-20241105112239154.png ├── image-20241105112257596.png ├── image-20241105112318058.png ├── image-20241107123200610.png ├── image-20241107123228009.png ├── image-20250225203211079.png ├── image-20250225203337558.png ├── image-20250225203344730.png ├── image-20250225203428732.png ├── image-20250301193027925.png ├── image-20250301205630800.png ├── image-20250301205720584.png ├── image-20250301205743126.png ├── image-20250301210251693.png ├── image-20250301210311890.png ├── image-20250301210334232.png ├── image-20250301210427777.png ├── image-20250301210613354.png ├── image-20250301210636083.png ├── image-20250301210652187.png ├── image-20250301210716264.png ├── image-20250301210842142.png ├── image-20250301210925456.png ├── image-20250301211330837.png ├── image-20250301211350357.png ├── image-20250301211818031.png ├── image-20250309185208391.png ├── image-20250309185232078.png ├── image-20250401144300786.png ├── image-20250401144332484.png ├── image-20250401144528653.png ├── image-20250401144553788.png ├── image-20250402111933803.png ├── nt.gif ├── sb.gif ├── titile.gif ├── title.gif ├── wenjian.gif ├── 大纲栏.gif ├── 思维导图.gif ├── 文件栏.gif ├── 标题-1740828423301-1.gif └── 标题.gif ├── LICENSE ├── css ├── drake-ayu.css ├── drake-black.css ├── drake-dark.css ├── drake-google.css ├── drake-jb.css ├── drake-juejin.css ├── drake-light.css ├── drake-material.css ├── drake-purple.css ├── drake-vue.css ├── drake-vue3.css ├── drake.css ├── drake │ ├── JetBrainsMono-Bold.woff2 │ ├── JetBrainsMono-BoldItalic.woff2 │ ├── JetBrainsMono-Italic.woff2 │ ├── JetBrainsMono-Regular.woff2 │ └── font.css ├── typora-mid-d.css ├── typora-mid-d2.css └── typora-mid-l.css ├── font.zip ├── readme.md ├── resources ├── plugin │ ├── article_uploader │ │ ├── Plugin2UploadBridge.js │ │ ├── README.md │ │ ├── controller │ │ │ └── UploadController.js │ │ ├── index.js │ │ ├── uploader │ │ │ ├── BaseUploaderInterface.js │ │ │ ├── CnBlogUploader.js │ │ │ ├── CsdnUploader.js │ │ │ └── WordpressUploader.js │ │ └── utils │ │ │ ├── axios.min.js │ │ │ ├── crypto-js │ │ │ ├── core.js │ │ │ ├── enc-base64.js │ │ │ ├── hmac-sha256.js │ │ │ ├── hmac.js │ │ │ └── sha256.js │ │ │ ├── customNotification.js │ │ │ └── uploadUtils.js │ ├── auto_number.js │ ├── bin │ │ ├── install.c │ │ ├── install.go │ │ ├── install_linux.sh │ │ ├── install_linux_amd_x64 │ │ ├── install_windows.ps1 │ │ ├── install_windows_amd_x64.exe │ │ ├── uninstall_linux.sh │ │ ├── uninstall_windows.ps1 │ │ └── version.json │ ├── blur.js │ ├── cipher │ │ ├── aes_ecb.min.js │ │ └── index.js │ ├── collapse_list.js │ ├── collapse_paragraph.js │ ├── collapse_table.js │ ├── commander.js │ ├── custom │ │ ├── README.md │ │ ├── index.js │ │ └── plugins │ │ │ ├── abc │ │ │ ├── abcjs-basic-min.js │ │ │ └── index.js │ │ │ ├── blockSideBySide.js │ │ │ ├── calendar │ │ │ ├── index.js │ │ │ ├── toastui-calendar.min.css │ │ │ └── toastui-calendar.min.js │ │ │ ├── callouts.js │ │ │ ├── chart │ │ │ ├── chart.min.js │ │ │ └── index.js │ │ │ ├── chat.js │ │ │ ├── chineseSymbolAutoPairer.js │ │ │ ├── drawIO │ │ │ └── index.js │ │ │ ├── echarts │ │ │ ├── echarts.min.js │ │ │ └── index.js │ │ │ ├── imageReviewer.js │ │ │ ├── kanban.js │ │ │ ├── markdownLint │ │ │ ├── MD101.js │ │ │ ├── index.js │ │ │ ├── linter-worker.js │ │ │ └── markdownlint.min.js │ │ │ ├── marp │ │ │ ├── index.js │ │ │ └── marp.min.js │ │ │ ├── quickButton.js │ │ │ ├── redirectLocalRootUrl.js │ │ │ ├── reopenClosedFiles │ │ │ ├── index.js │ │ │ └── remain.json │ │ │ ├── resourceOperation.js │ │ │ ├── scrollBookmarker │ │ │ ├── bookmark.json │ │ │ └── index.js │ │ │ ├── templater.js │ │ │ ├── timeline.js │ │ │ ├── toc.js │ │ │ └── wavedrom │ │ │ ├── index.js │ │ │ └── wavedrom.min.js │ ├── dark.js │ ├── datatables │ │ ├── index.js │ │ └── resource │ │ │ ├── dataTables.min.css │ │ │ ├── dataTables.min.js │ │ │ ├── sort_asc.png │ │ │ ├── sort_asc_disabled.png │ │ │ ├── sort_both.png │ │ │ ├── sort_desc.png │ │ │ └── sort_desc_disabled.png │ ├── easy_modify.js │ ├── editor_width_slider.js │ ├── export_enhance.js │ ├── fence_enhance │ │ ├── index.js │ │ └── resource │ │ │ ├── brace-fold.js │ │ │ ├── comment-fold.js │ │ │ ├── foldcode.js │ │ │ ├── foldgutter.css │ │ │ ├── foldgutter.js │ │ │ ├── indent-fold.js │ │ │ ├── markdown-fold.js │ │ │ └── xml-fold.js │ ├── file_counter.js │ ├── global │ │ ├── core │ │ │ ├── i18n.js │ │ │ ├── index.js │ │ │ ├── plugin.js │ │ │ └── utils │ │ │ │ ├── common │ │ │ │ ├── jszip │ │ │ │ │ └── jszip.min.js │ │ │ │ ├── markdown-it │ │ │ │ │ └── index.js │ │ │ │ ├── node-fetch │ │ │ │ │ ├── https-proxy-agent.js │ │ │ │ │ └── node-fetch.js │ │ │ │ ├── toml │ │ │ │ │ ├── compiler.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── parser.js │ │ │ │ │ └── stringify.js │ │ │ │ └── yaml │ │ │ │ │ └── index.js │ │ │ │ ├── env.js │ │ │ │ ├── index.js │ │ │ │ └── mixin │ │ │ │ ├── contextMenu.js │ │ │ │ ├── diagramParser.js │ │ │ │ ├── dialog.js │ │ │ │ ├── entities.js │ │ │ │ ├── eventHub.js │ │ │ │ ├── exportHelper.js │ │ │ │ ├── extra.js │ │ │ │ ├── hotkeyHub.js │ │ │ │ ├── htmlTemplater.js │ │ │ │ ├── index.js │ │ │ │ ├── migrate.js │ │ │ │ ├── notification.js │ │ │ │ ├── polyfill.js │ │ │ │ ├── progressBar.js │ │ │ │ ├── runtime.js │ │ │ │ ├── searchStringParser.js │ │ │ │ ├── stateRecorder.js │ │ │ │ ├── styleTemplater.js │ │ │ │ └── thirdPartyDiagramParser.js │ │ ├── locales │ │ │ ├── en.json │ │ │ ├── zh-CN.json │ │ │ └── zh-TW.json │ │ ├── settings │ │ │ ├── README.md │ │ │ ├── custom_plugin.default.toml │ │ │ ├── custom_plugin.user.toml │ │ │ ├── settings.default.toml │ │ │ └── settings.user.toml │ │ ├── styles │ │ │ ├── blockSideBySide.css │ │ │ ├── callouts.css │ │ │ ├── chat.css │ │ │ ├── collapse_list.css │ │ │ ├── collapse_paragraph.css │ │ │ ├── collapse_table.css │ │ │ ├── commander.css │ │ │ ├── customize.css │ │ │ ├── dark.css │ │ │ ├── datatables.css │ │ │ ├── drawIO.css │ │ │ ├── fence_enhance.css │ │ │ ├── file_counter.css │ │ │ ├── imageReviewer.css │ │ │ ├── kanban.css │ │ │ ├── markdownLint.css │ │ │ ├── markmap.css │ │ │ ├── marp.css │ │ │ ├── no_image.css │ │ │ ├── pie_menu.css │ │ │ ├── plugin-common-menu.css │ │ │ ├── plugin-common-modal.css │ │ │ ├── plugin-common-notification.css │ │ │ ├── plugin-common-progress-bar.css │ │ │ ├── plugin-common.css │ │ │ ├── plugin-diagram-parser.css │ │ │ ├── quickButton.css │ │ │ ├── read_only.css │ │ │ ├── resize_table.css │ │ │ ├── resourceOperation.css │ │ │ ├── right_click_menu.css │ │ │ ├── ripgrep.css │ │ │ ├── scrollBookmarker.css │ │ │ ├── search_multi.css │ │ │ ├── slash_commands.css │ │ │ ├── text_stylize.css │ │ │ ├── timeline.css │ │ │ ├── toc.css │ │ │ ├── toolbar.css │ │ │ └── window_tab.css │ │ └── user_styles │ │ │ ├── README.md │ │ │ ├── customize.css │ │ │ └── 请读我.md │ ├── go_top.js │ ├── help.js │ ├── hotkeys.js │ ├── index.js │ ├── json_rpc │ │ ├── README.md │ │ ├── index.js │ │ └── node-json-rpc.js │ ├── markmap │ │ ├── index.js │ │ └── resource │ │ │ ├── default.min.css │ │ │ ├── fonts │ │ │ ├── KaTeX_AMS-Regular.woff2 │ │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ │ ├── KaTeX_Main-Bold.woff2 │ │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ │ ├── KaTeX_Main-Italic.woff2 │ │ │ ├── KaTeX_Main-Regular.woff2 │ │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ │ ├── KaTeX_Math-Italic.woff2 │ │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ │ ├── KaTeX_Script-Regular.woff2 │ │ │ ├── KaTeX_Size1-Regular.woff2 │ │ │ ├── KaTeX_Size2-Regular.woff2 │ │ │ ├── KaTeX_Size3-Regular.woff2 │ │ │ ├── KaTeX_Size4-Regular.woff2 │ │ │ └── KaTeX_Typewriter-Regular.woff2 │ │ │ ├── katex.min.css │ │ │ ├── markmap-lib.js │ │ │ ├── markmap-view.js │ │ │ ├── markmap-view.jse │ │ │ └── webfontloader.js │ ├── md_padding │ │ ├── index.js │ │ └── md-padding.min.js │ ├── no_image.js │ ├── pie_menu.js │ ├── preferences.js │ ├── read_only.js │ ├── resize_image.js │ ├── resize_table.js │ ├── right_click_menu.js │ ├── ripgrep.js │ ├── search_multi.js │ ├── slash_commands.js │ ├── test.js │ ├── text_stylize.js │ ├── toolbar.js │ ├── truncate_text.js │ ├── updater.js │ └── window_tab │ │ └── index.js ├── style │ ├── font-awesome-4.7.0 │ │ ├── HELP-US-OUT.txt │ │ ├── css │ │ │ ├── font-awesome.css │ │ │ └── font-awesome.min.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── less │ │ │ ├── animated.less │ │ │ ├── bordered-pulled.less │ │ │ ├── core.less │ │ │ ├── fixed-width.less │ │ │ ├── font-awesome.less │ │ │ ├── icons.less │ │ │ ├── larger.less │ │ │ ├── list.less │ │ │ ├── mixins.less │ │ │ ├── path.less │ │ │ ├── rotated-flipped.less │ │ │ ├── screen-reader.less │ │ │ ├── stacked.less │ │ │ └── variables.less │ │ └── scss │ │ │ ├── _animated.scss │ │ │ ├── _bordered-pulled.scss │ │ │ ├── _core.scss │ │ │ ├── _fixed-width.scss │ │ │ ├── _icons.scss │ │ │ ├── _larger.scss │ │ │ ├── _list.scss │ │ │ ├── _mixins.scss │ │ │ ├── _path.scss │ │ │ ├── _rotated-flipped.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _stacked.scss │ │ │ ├── _variables.scss │ │ │ └── font-awesome.scss │ └── window.css └── window.html └── themes.zip /.readme.assets/bs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/bs.gif -------------------------------------------------------------------------------- /.readme.assets/dagang.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/dagang.gif -------------------------------------------------------------------------------- /.readme.assets/html-1730953102113-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/html-1730953102113-3.gif -------------------------------------------------------------------------------- /.readme.assets/html.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/html.gif -------------------------------------------------------------------------------- /.readme.assets/image-20240805221400275.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805221400275.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805221515120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805221515120.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805221953206.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805221953206.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805222137381.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805222137381.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805222339944.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805222339944.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805223213943.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805223213943.png -------------------------------------------------------------------------------- /.readme.assets/image-20240805232704516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20240805232704516.png -------------------------------------------------------------------------------- /.readme.assets/image-20241105112239154.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20241105112239154.png -------------------------------------------------------------------------------- /.readme.assets/image-20241105112257596.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20241105112257596.png -------------------------------------------------------------------------------- /.readme.assets/image-20241105112318058.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20241105112318058.png -------------------------------------------------------------------------------- /.readme.assets/image-20241107123200610.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20241107123200610.png -------------------------------------------------------------------------------- /.readme.assets/image-20241107123228009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20241107123228009.png -------------------------------------------------------------------------------- /.readme.assets/image-20250225203211079.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250225203211079.png -------------------------------------------------------------------------------- /.readme.assets/image-20250225203337558.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250225203337558.png -------------------------------------------------------------------------------- /.readme.assets/image-20250225203344730.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250225203344730.png -------------------------------------------------------------------------------- /.readme.assets/image-20250225203428732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250225203428732.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301193027925.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301193027925.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301205630800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301205630800.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301205720584.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301205720584.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301205743126.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301205743126.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210251693.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210251693.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210311890.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210311890.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210334232.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210334232.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210427777.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210427777.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210613354.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210613354.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210636083.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210636083.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210652187.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210652187.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210716264.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210716264.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210842142.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210842142.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301210925456.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301210925456.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301211330837.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301211330837.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301211350357.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301211350357.png -------------------------------------------------------------------------------- /.readme.assets/image-20250301211818031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250301211818031.png -------------------------------------------------------------------------------- /.readme.assets/image-20250309185208391.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250309185208391.png -------------------------------------------------------------------------------- /.readme.assets/image-20250309185232078.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250309185232078.png -------------------------------------------------------------------------------- /.readme.assets/image-20250401144300786.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250401144300786.png -------------------------------------------------------------------------------- /.readme.assets/image-20250401144332484.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250401144332484.png -------------------------------------------------------------------------------- /.readme.assets/image-20250401144528653.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250401144528653.png -------------------------------------------------------------------------------- /.readme.assets/image-20250401144553788.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250401144553788.png -------------------------------------------------------------------------------- /.readme.assets/image-20250402111933803.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/image-20250402111933803.png -------------------------------------------------------------------------------- /.readme.assets/nt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/nt.gif -------------------------------------------------------------------------------- /.readme.assets/sb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/sb.gif -------------------------------------------------------------------------------- /.readme.assets/titile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/titile.gif -------------------------------------------------------------------------------- /.readme.assets/title.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/title.gif -------------------------------------------------------------------------------- /.readme.assets/wenjian.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/wenjian.gif -------------------------------------------------------------------------------- /.readme.assets/大纲栏.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/大纲栏.gif -------------------------------------------------------------------------------- /.readme.assets/思维导图.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/思维导图.gif -------------------------------------------------------------------------------- /.readme.assets/文件栏.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/文件栏.gif -------------------------------------------------------------------------------- /.readme.assets/标题-1740828423301-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/标题-1740828423301-1.gif -------------------------------------------------------------------------------- /.readme.assets/标题.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/.readme.assets/标题.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2025 xyz349925756 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /css/drake/JetBrainsMono-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/css/drake/JetBrainsMono-Bold.woff2 -------------------------------------------------------------------------------- /css/drake/JetBrainsMono-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/css/drake/JetBrainsMono-BoldItalic.woff2 -------------------------------------------------------------------------------- /css/drake/JetBrainsMono-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/css/drake/JetBrainsMono-Italic.woff2 -------------------------------------------------------------------------------- /css/drake/JetBrainsMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/css/drake/JetBrainsMono-Regular.woff2 -------------------------------------------------------------------------------- /css/drake/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'JetBrains Mono'; 3 | src: local('JetBrains Mono'), 4 | url('./JetBrainsMono-Regular.woff2') format('woff2'); 5 | font-display: swap; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | @font-face { 10 | font-family: 'JetBrains Mono'; 11 | src: local('JetBrains Mono'), 12 | url('./JetBrainsMono-Italic.woff2') format('woff2'); 13 | font-display: swap; 14 | font-weight: normal; 15 | font-style: italic; 16 | } 17 | @font-face { 18 | font-family: 'JetBrains Mono'; 19 | src: local('JetBrains Mono'), 20 | url('./JetBrainsMono-Bold.woff2') format('woff2'); 21 | font-display: swap; 22 | font-weight: bold; 23 | font-style: normal; 24 | } 25 | @font-face { 26 | font-family: 'JetBrains Mono'; 27 | src: local('JetBrains Mono'), 28 | url('./JetBrainsMono-BoldItalic.woff2') format('woff2'); 29 | font-display: swap; 30 | font-weight: bold; 31 | font-style: italic; 32 | } 33 | 34 | /*快速自定义配置*/ 35 | :root { 36 | --monospace: "Iosevka Curly", "JetBrains Mono", "Fira Code", "Cascadia Code", Menlo, "Ubuntu Mono", Consolas, HYZhengYuan; /*代码字体*/ 37 | --text-font: var(--monospace); /*正文字体*/ 38 | --title-font: var(--monospace); /*标题字体*/ 39 | --latex-font: var(--monospace); /*LaTeX字体(不含英语)*/ 40 | --text-line-height: 1.6; /*正文行间距*/ 41 | --code-line-height: 1.6; /*代码块行间距*/ 42 | --p-spacing: 0.8rem; /*段间距*/ 43 | --file-tree-text-size: 1.1rem; /*文件树大小*/ 44 | --toc-text-size: 1rem; /*大纲大小*/ 45 | --text-size: 14px; /*字体大小 推荐配置: 应用设置-外观-字体大小*/ 46 | } -------------------------------------------------------------------------------- /font.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/font.zip -------------------------------------------------------------------------------- /resources/plugin/article_uploader/Plugin2UploadBridge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 桥接插件和上传工具。用于转发请求给控制器,消息统计,提示功能 3 | */ 4 | class Plugin2UploadBridge { 5 | constructor(plugin) { 6 | this.plugin = plugin; 7 | this.config = plugin.config; 8 | this.sites = ["cnblog", "csdn", "wordpress"]; 9 | this.utils = null; 10 | this.uploadController = null; 11 | this.notification = null; 12 | } 13 | 14 | lazyLoad = () => { 15 | if (!this.utils) { 16 | const Utils = require('./utils/uploadUtils'); 17 | this.utils = new Utils(this.plugin); 18 | } 19 | 20 | if (!this.uploadController) { 21 | const UploadController = require('./controller/UploadController'); 22 | this.uploadController = new UploadController(this); 23 | this.sites.forEach(site => this.uploadController.register(site)); 24 | } 25 | 26 | if (!this.notification) { 27 | const Notification = require('./utils/customNotification.js').plugin; 28 | this.notification = new Notification(); 29 | } 30 | } 31 | 32 | uploadProxy = async (filePath, type = "all") => { 33 | if (this.config.upload.reconfirm) { 34 | const message = "你确定要上传文章吗"; 35 | const op = { type: "info", title: "上传提示", buttons: ["确定", "取消"], message }; 36 | const { response } = await this.plugin.utils.showMessageBox(op); 37 | if (response === 1) { 38 | return; 39 | } 40 | } 41 | 42 | this.lazyLoad(); 43 | this.notification.showNotification('开始上传,请不要关闭软件', 'info'); 44 | const startTime = new Date(); 45 | 46 | if (type === "all") { 47 | await this.uploadController.uploadToAllPlatforms(filePath); 48 | } else { 49 | await this.uploadController.upload(type, filePath); 50 | } 51 | 52 | const endTime = new Date(); 53 | const duration = ((endTime - startTime) / 1000).toFixed(1); 54 | this.notification.showNotification(`上传成功,耗时${duration}秒`, 'success'); 55 | } 56 | } 57 | 58 | module.exports = Plugin2UploadBridge; 59 | -------------------------------------------------------------------------------- /resources/plugin/article_uploader/controller/UploadController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 控制器,转发请求,注册插件,设置配置 3 | */ 4 | class UploadController { 5 | constructor(bridge) { 6 | this.bridge = bridge; 7 | this.config = bridge.config; 8 | this.utils = bridge.utils; 9 | this.uploaders = new Map(); 10 | this.options = null; 11 | this.pathMap = { 12 | cnblog: "../uploader/CnBlogUploader", 13 | csdn: "../uploader/CsdnUploader", 14 | wordpress: "../uploader/WordpressUploader", 15 | } 16 | 17 | this.init(); 18 | } 19 | 20 | init = () => { 21 | if (!this.options) { 22 | const chrome = require('selenium-webdriver/chrome'); 23 | this.options = new chrome.Options(); 24 | this.options.addArguments( 25 | '--disable-blink-features=AutomationControlled', 26 | '--disable-infobars', 27 | '--disable-extensions', 28 | '--disable-gpu', 29 | '--no-sandbox', 30 | '--disable-dev-shm-usage', 31 | '--disable-javascript' 32 | ); 33 | } 34 | 35 | if (this.config.upload.selenium.headless) { 36 | this.options.addArguments("--headless"); 37 | } 38 | } 39 | 40 | register = (site) => { 41 | const path = this.pathMap[site]; 42 | if (path) { 43 | const uploader = require(path); 44 | const instance = new uploader(this); 45 | const name = instance.getName(); 46 | this.uploaders.set(name, instance); 47 | } 48 | } 49 | 50 | unregister = (name) => this.uploaders.delete(name); 51 | 52 | // 这里对结果不做捕捉,后续根据需求优化 53 | upload = async (platform, filePath) => { 54 | const uploader = this.uploaders.get(platform); 55 | const { title, content, extraData } = this.utils.readAndSplitFile(filePath); 56 | if (uploader) { 57 | await uploader.upload(title, content, extraData, this.options); 58 | } 59 | } 60 | 61 | uploadToAllPlatforms = async (filePath) => { 62 | const { title, content, extraData } = this.utils.readAndSplitFile(filePath); 63 | for (let [name, uploader] of this.uploaders) { 64 | // 上传全部的时候不上传哪些平台,属于脱裤子放屁的需求 65 | const c = this.config.upload[name]; 66 | if (c && c.enabled) { 67 | await uploader.upload(title, content, extraData, this.options); 68 | } 69 | } 70 | } 71 | } 72 | 73 | module.exports = UploadController; 74 | -------------------------------------------------------------------------------- /resources/plugin/article_uploader/index.js: -------------------------------------------------------------------------------- 1 | class ArticleUploaderPlugin extends BasePlugin { 2 | init = () => { 3 | this.staticActions = this.i18n.fillActions([ 4 | { act_value: "upload_to_csdn" }, 5 | { act_value: "upload_to_wordpress" }, 6 | { act_value: "upload_to_cn_blog" }, 7 | { act_value: "upload_to_all_site" }, 8 | ]) 9 | } 10 | 11 | hotkey = () => [ 12 | { hotkey: this.config.UPLOAD_CSDN_HOTKEY, callback: () => this.call("upload_to_csdn") }, 13 | { hotkey: this.config.UPLOAD_CNBLOG_HOTKEY, callback: () => this.call("upload_to_cn_blog") }, 14 | { hotkey: this.config.UPLOAD_WORDPRESS_HOTKEY, callback: () => this.call("upload_to_wordpress") }, 15 | { hotkey: this.config.UPLOAD_ALL_HOTKEY, callback: () => this.call("upload_to_all_site") }, 16 | ] 17 | 18 | call = async action => { 19 | const map = { 20 | upload_to_csdn: "csdn", 21 | upload_to_wordpress: "wordpress", 22 | upload_to_cn_blog: "cnblog", 23 | upload_to_all_site: "all" 24 | } 25 | const act = map[action] 26 | if (act) { 27 | await this.upload(act) 28 | } 29 | } 30 | 31 | upload = async action => { 32 | const uploader = require("./Plugin2UploadBridge"); 33 | this.uploader = new uploader(this); 34 | const filePath = this.utils.getFilePath(); 35 | await this.uploader.uploadProxy(filePath, action); 36 | } 37 | } 38 | 39 | module.exports = { 40 | plugin: ArticleUploaderPlugin 41 | } 42 | -------------------------------------------------------------------------------- /resources/plugin/article_uploader/uploader/BaseUploaderInterface.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 上传到各大平台的接口基类 3 | */ 4 | class BaseUploaderInterface { 5 | constructor(controller) { 6 | this.utils = controller.utils; 7 | this.config = controller.config; 8 | } 9 | 10 | getName() { 11 | throw new Error("应该被子类实现getName方法"); 12 | } 13 | 14 | async upload(title, content, extraData, options) { 15 | throw new Error("应该被子类实现upload方法"); 16 | } 17 | } 18 | 19 | module.exports = BaseUploaderInterface; 20 | -------------------------------------------------------------------------------- /resources/plugin/article_uploader/uploader/WordpressUploader.js: -------------------------------------------------------------------------------- 1 | const BaseUploaderInterface = require("./BaseUploaderInterface"); 2 | 3 | /** 4 | * 上传到wordpress的插件实现 5 | */ 6 | class WordpressUploader extends BaseUploaderInterface { 7 | getName() { 8 | return "wordpress"; 9 | } 10 | 11 | async upload(title, content, extraData, options) { 12 | const { Builder, By, Key, until } = require('selenium-webdriver'); 13 | const chrome = require('selenium-webdriver/chrome'); 14 | require('chromedriver'); 15 | const Notification = require('../utils/customNotification.js').plugin; 16 | const notification = new Notification(); 17 | const { marked } = require('marked'); 18 | 19 | const SELENIUM_WAIT_FIX_TIME_LEVEL1 = 2000; 20 | const SELENIUM_EXPLICIT_WAIT_TIME = 10000; 21 | 22 | let driver = await new Builder().forBrowser('chrome').setChromeOptions(options).build(); 23 | try { 24 | await driver.manage().window().maximize(); 25 | await driver.get(this.config.upload.wordpress.loginUrl); 26 | 27 | await driver.sleep(SELENIUM_WAIT_FIX_TIME_LEVEL1); 28 | let userInput = await driver.wait(until.elementLocated(By.id('user_login')), SELENIUM_EXPLICIT_WAIT_TIME); 29 | await driver.wait(until.elementIsVisible(userInput), SELENIUM_EXPLICIT_WAIT_TIME); 30 | await userInput.sendKeys(this.config.upload.wordpress.username); 31 | let passInput = await driver.wait(until.elementLocated(By.id('user_pass')), SELENIUM_EXPLICIT_WAIT_TIME); 32 | await driver.wait(until.elementIsVisible(passInput), SELENIUM_EXPLICIT_WAIT_TIME); 33 | await passInput.sendKeys(this.config.upload.wordpress.password, Key.RETURN); 34 | await driver.get(`${this.config.upload.wordpress.hostname}/wp-admin/post-new.php`); 35 | 36 | await driver.wait(until.elementLocated(By.name('post_title')), SELENIUM_EXPLICIT_WAIT_TIME); 37 | let titleField = await driver.findElement(By.name('post_title')); 38 | await titleField.sendKeys(title); 39 | 40 | await driver.wait(until.elementLocated(By.id('content_ifr')), SELENIUM_EXPLICIT_WAIT_TIME); 41 | let editorFrame = await driver.findElement(By.id('content_ifr')); 42 | await driver.switchTo().frame(editorFrame); 43 | 44 | let body = await driver.findElement(By.id('tinymce')); 45 | await driver.executeScript("arguments[0].innerHTML = arguments[1]", body, marked(content)); 46 | 47 | await driver.switchTo().defaultContent(); 48 | 49 | await driver.sleep(SELENIUM_WAIT_FIX_TIME_LEVEL1); 50 | 51 | await driver.wait(until.elementLocated(By.id('publish')), SELENIUM_EXPLICIT_WAIT_TIME); 52 | let publishButton = await driver.findElement(By.id('publish')); 53 | await publishButton.click(); 54 | console.log("wordpress博客发布流程已完毕"); 55 | notification.showNotification("WordPress博客发布流程已完毕", "success"); 56 | } catch (error) { 57 | console.log(error); 58 | notification.showNotification('WordPress博客发布失败', 'error'); 59 | } finally { 60 | await driver.quit(); 61 | } 62 | } 63 | } 64 | 65 | module.exports = WordpressUploader; 66 | -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/crypto-js/core.js: -------------------------------------------------------------------------------- 1 | (function(e,r){"object"==typeof exports?module.exports=exports=r():"function"==typeof define&&define.amd?define([],r):e.CryptoJS=r()})(this,function(){var e=e||function(e,r){var t={},i=t.lib={},n=i.Base=function(){function e(){}return{extend:function(r){e.prototype=this;var t=new e;return r&&t.mixIn(r),t.hasOwnProperty("init")||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var r in e)e.hasOwnProperty(r)&&(this[r]=e[r]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),o=i.WordArray=n.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=t!=r?t:4*e.length},toString:function(e){return(e||s).stringify(this)},concat:function(e){var r=this.words,t=e.words,i=this.sigBytes,n=e.sigBytes;if(this.clamp(),i%4)for(var o=0;n>o;o++){var c=255&t[o>>>2]>>>24-8*(o%4);r[i+o>>>2]|=c<<24-8*((i+o)%4)}else if(t.length>65535)for(var o=0;n>o;o+=4)r[i+o>>>2]=t[o>>>2];else r.push.apply(r,t);return this.sigBytes+=n,this},clamp:function(){var r=this.words,t=this.sigBytes;r[t>>>2]&=4294967295<<32-8*(t%4),r.length=e.ceil(t/4)},clone:function(){var e=n.clone.call(this);return e.words=this.words.slice(0),e},random:function(r){for(var t=[],i=0;r>i;i+=4)t.push(0|4294967296*e.random());return new o.init(t,r)}}),c=t.enc={},s=c.Hex={stringify:function(e){for(var r=e.words,t=e.sigBytes,i=[],n=0;t>n;n++){var o=255&r[n>>>2]>>>24-8*(n%4);i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(e){for(var r=e.length,t=[],i=0;r>i;i+=2)t[i>>>3]|=parseInt(e.substr(i,2),16)<<24-4*(i%8);return new o.init(t,r/2)}},u=c.Latin1={stringify:function(e){for(var r=e.words,t=e.sigBytes,i=[],n=0;t>n;n++){var o=255&r[n>>>2]>>>24-8*(n%4);i.push(String.fromCharCode(o))}return i.join("")},parse:function(e){for(var r=e.length,t=[],i=0;r>i;i++)t[i>>>2]|=(255&e.charCodeAt(i))<<24-8*(i%4);return new o.init(t,r)}},f=c.Utf8={stringify:function(e){try{return decodeURIComponent(escape(u.stringify(e)))}catch(r){throw Error("Malformed UTF-8 data")}},parse:function(e){return u.parse(unescape(encodeURIComponent(e)))}},a=i.BufferedBlockAlgorithm=n.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=f.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(r){var t=this._data,i=t.words,n=t.sigBytes,c=this.blockSize,s=4*c,u=n/s;u=r?e.ceil(u):e.max((0|u)-this._minBufferSize,0);var f=u*c,a=e.min(4*f,n);if(f){for(var p=0;f>p;p+=c)this._doProcessBlock(i,p);var d=i.splice(0,f);t.sigBytes-=a}return new o.init(d,a)},clone:function(){var e=n.clone.call(this);return e._data=this._data.clone(),e},_minBufferSize:0});i.Hasher=a.extend({cfg:n.extend(),init:function(e){this.cfg=this.cfg.extend(e),this.reset()},reset:function(){a.reset.call(this),this._doReset()},update:function(e){return this._append(e),this._process(),this},finalize:function(e){e&&this._append(e);var r=this._doFinalize();return r},blockSize:16,_createHelper:function(e){return function(r,t){return new e.init(t).finalize(r)}},_createHmacHelper:function(e){return function(r,t){return new p.HMAC.init(e,t).finalize(r)}}});var p=t.algo={};return t}(Math);return e}); -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/crypto-js/enc-base64.js: -------------------------------------------------------------------------------- 1 | (function(e,r){"object"==typeof exports?module.exports=exports=r(require("./core")):"function"==typeof define&&define.amd?define(["./core"],r):r(e.CryptoJS)})(this,function(e){return function(){var r=e,t=r.lib,n=t.WordArray,i=r.enc;i.Base64={stringify:function(e){var r=e.words,t=e.sigBytes,n=this._map;e.clamp();for(var i=[],o=0; t>o; o+=3)for(var c=255&r[o>>>2]>>>24-8*(o%4),f=255&r[o+1>>>2]>>>24-8*((o+1)%4),s=255&r[o+2>>>2]>>>24-8*((o+2)%4),a=c<<16|f<<8|s,u=0; 4>u&&t>o+.75*u; u++)i.push(n.charAt(63&a>>>6*(3-u)));var p=n.charAt(64);if(p)for(; i.length%4;)i.push(p);return i.join("")},parse:function(e){var r=e.length,t=this._map,i=t.charAt(64);if(i){var o=e.indexOf(i);-1!=o&&(r=o)}for(var c=[],f=0,s=0; r>s; s++)if(s%4){var a=t.indexOf(e.charAt(s-1))<<2*(s%4),u=t.indexOf(e.charAt(s))>>>6-2*(s%4);c[f>>>2]|=(a|u)<<24-8*(f%4),f++}return n.create(c,f)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}(),e.enc.Base64}); -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/crypto-js/hmac-sha256.js: -------------------------------------------------------------------------------- 1 | (function(e,r){"object"==typeof exports?module.exports=exports=r(require("./core"),require("./sha256"),require("./hmac")):"function"==typeof define&&define.amd?define(["./core","./sha256","./hmac"],r):r(e.CryptoJS)})(this,function(e){return e.HmacSHA256}); -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/crypto-js/hmac.js: -------------------------------------------------------------------------------- 1 | (function(e,r){"object"==typeof exports?module.exports=exports=r(require("./core")):"function"==typeof define&&define.amd?define(["./core"],r):r(e.CryptoJS)})(this,function(e){(function(){var r=e,t=r.lib,n=t.Base,i=r.enc,o=i.Utf8,a=r.algo;a.HMAC=n.extend({init:function(e, r){e=this._hasher=new e.init,"string"==typeof r&&(r=o.parse(r));var t=e.blockSize,n=4*t;r.sigBytes>n&&(r=e.finalize(r)),r.clamp();for(var i=this._oKey=r.clone(),a=this._iKey=r.clone(),s=i.words,c=a.words,f=0; t>f; f++)s[f]^=1549556828,c[f]^=909522486;i.sigBytes=a.sigBytes=n,this.reset()},reset:function(){var e=this._hasher;e.reset(),e.update(this._iKey)},update:function(e){return this._hasher.update(e),this},finalize:function(e){var r=this._hasher,t=r.finalize(e);r.reset();var n=r.finalize(this._oKey.clone().concat(t));return n}})})()}); -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/crypto-js/sha256.js: -------------------------------------------------------------------------------- 1 | (function(e,r){"object"==typeof exports?module.exports=exports=r(require("./core")):"function"==typeof define&&define.amd?define(["./core"],r):r(e.CryptoJS)})(this,function(e){return function(r){var t=e,n=t.lib,i=n.WordArray,o=n.Hasher,s=t.algo,c=[],a=[];(function(){function e(e){for(var t=r.sqrt(e),n=2; t>=n; n++)if(!(e%n))return!1;return!0}function t(e){return 0|4294967296*(e-(0|e))}for(var n=2,i=0; 64>i;)e(n)&&(8>i&&(c[i]=t(r.pow(n,.5))),a[i]=t(r.pow(n,1/3)),i++),n++})();var f=[],u=s.SHA256=o.extend({_doReset:function(){this._hash=new i.init(c.slice(0))},_doProcessBlock:function(e, r){for(var t=this._hash.words,n=t[0],i=t[1],o=t[2],s=t[3],c=t[4],u=t[5],d=t[6],p=t[7],h=0; 64>h; h++){if(16>h)f[h]=0|e[r+h];else{var y=f[h-15],l=(y<<25|y>>>7)^(y<<14|y>>>18)^y>>>3,m=f[h-2],x=(m<<15|m>>>17)^(m<<13|m>>>19)^m>>>10;f[h]=l+f[h-7]+x+f[h-16]}var v=c&u^~c&d,q=n&i^n&o^i&o,g=(n<<30|n>>>2)^(n<<19|n>>>13)^(n<<10|n>>>22),_=(c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25),b=p+_+v+a[h]+f[h],S=g+q;p=d,d=u,u=c,c=0|s+b,s=o,o=i,i=n,n=0|b+S}t[0]=0|t[0]+n,t[1]=0|t[1]+i,t[2]=0|t[2]+o,t[3]=0|t[3]+s,t[4]=0|t[4]+c,t[5]=0|t[5]+u,t[6]=0|t[6]+d,t[7]=0|t[7]+p},_doFinalize:function(){var e=this._data,t=e.words,n=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[(i+64>>>9<<4)+14]=r.floor(n/4294967296),t[(i+64>>>9<<4)+15]=n,e.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var e=o.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=o._createHelper(u),t.HmacSHA256=o._createHmacHelper(u)}(Math),e.SHA256}); -------------------------------------------------------------------------------- /resources/plugin/article_uploader/utils/uploadUtils.js: -------------------------------------------------------------------------------- 1 | class UploadUtils { 2 | constructor(plugin) { 3 | this.plugin = plugin; 4 | this.CryptoJS = null; 5 | this.yaml = null; 6 | } 7 | 8 | // 懒加载 CryptoJS 模块 9 | lazyLoadCryptoJS = () => { 10 | if (!this.CryptoJS) { 11 | this.CryptoJS = require('./crypto-js/core'); 12 | require('./crypto-js/hmac'); 13 | require('./crypto-js/sha256'); 14 | require('./crypto-js/enc-base64'); 15 | } 16 | } 17 | 18 | // 生成UUID 19 | generateUUID() { 20 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 21 | var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); 22 | return v.toString(16); 23 | }); 24 | } 25 | 26 | // 处理文件 27 | readAndSplitFile = (filePath) => { 28 | const Notification = require('../utils/customNotification.js').plugin; 29 | const notification = new Notification(); 30 | try { 31 | const fs = this.plugin.utils.Package.Fs; 32 | const data = fs.readFileSync(filePath, 'utf-8'); 33 | const lines = data.split('\n'); 34 | const title = lines[0].trim().replace(/#/g, '').trim(); 35 | const content = lines.slice(1).join('\n').trim(); 36 | if (title === "" || content === '') { 37 | throw new Error("内容为空"); 38 | } 39 | const extraData = ""; // TODO: 取出标签,分类,封面图等 40 | return { title, content, extraData }; 41 | } catch (error) { 42 | notification.showNotification('文件格式读取失败', "error"); 43 | console.error('Error reading file:', error); 44 | return null; 45 | } 46 | } 47 | 48 | // 获取签名 49 | getSign = (uuid, url) => { 50 | this.lazyLoadCryptoJS(); 51 | const parsedUrl = new URL(url); 52 | const _url = parsedUrl.pathname; 53 | 54 | const ekey = "9znpamsyl2c7cdrr9sas0le9vbc3r6ba"; 55 | const xCaKey = "203803574"; 56 | const toEnc = `POST\napplication/json, text/plain, */*\n\napplication/json;\n\nx-ca-key:${xCaKey}\nx-ca-nonce:${uuid}\n${_url}`; 57 | const hmac = this.CryptoJS.HmacSHA256(toEnc, ekey); 58 | return this.CryptoJS.enc.Base64.stringify(hmac); 59 | } 60 | } 61 | 62 | module.exports = UploadUtils; 63 | -------------------------------------------------------------------------------- /resources/plugin/bin/install.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | ) 11 | 12 | type Installer struct { 13 | root string 14 | insertFile string 15 | insertContent string 16 | oldMatch string 17 | newMatch string 18 | } 19 | 20 | func newInstaller() (*Installer, error) { 21 | fmt.Println("[1/4] new installer") 22 | curDir, err := os.Getwd() 23 | if err != nil { 24 | return nil, err 25 | } 26 | return &Installer{ 27 | root: filepath.Dir(filepath.Dir(curDir)), 28 | insertFile: "window.html", 29 | insertContent: ``, 30 | oldMatch: ``, 31 | newMatch: ``, 32 | }, nil 33 | } 34 | 35 | func (i *Installer) prepare() (err error) { 36 | fmt.Println("[2/4] prepare") 37 | if err = checkExist(i.root, i.insertFile); err != nil { 38 | return err 39 | } 40 | return nil 41 | } 42 | 43 | func (i *Installer) backupFile() (err error) { 44 | fmt.Println("[3/4] backup window.html") 45 | filePath := filepath.Join(i.root, i.insertFile) 46 | backupFilePath := filePath + ".bak" 47 | if err = copyFile(filePath, backupFilePath); err != nil { 48 | return err 49 | } 50 | return nil 51 | } 52 | 53 | func (i *Installer) run() (err error) { 54 | fmt.Println("[4/4] update window.html") 55 | filePath := filepath.Join(i.root, i.insertFile) 56 | file, err := ioutil.ReadFile(filePath) 57 | if err != nil { 58 | return err 59 | } 60 | if bytes.Contains(file, []byte(i.insertContent)) { 61 | return 62 | } 63 | 64 | match := "" 65 | if bytes.Contains(file, []byte(i.oldMatch)) { 66 | match = i.oldMatch 67 | } else if bytes.Contains(file, []byte(i.newMatch)) { 68 | match = i.newMatch 69 | } 70 | if match == "" { 71 | return fmt.Errorf("has not match") 72 | } 73 | 74 | result := bytes.Replace(file, []byte(match), []byte(match+i.insertContent), 1) 75 | err = ioutil.WriteFile(filePath, result, 0644) 76 | if err != nil { 77 | return err 78 | } 79 | return nil 80 | } 81 | 82 | func copyFile(src, dst string) (err error) { 83 | var srcFd *os.File 84 | var dstFd *os.File 85 | var srcInfo os.FileInfo 86 | 87 | if srcFd, err = os.Open(src); err != nil { 88 | return err 89 | } 90 | defer srcFd.Close() 91 | 92 | if dstFd, err = os.Create(dst); err != nil { 93 | return err 94 | } 95 | defer dstFd.Close() 96 | 97 | if _, err = io.Copy(dstFd, srcFd); err != nil { 98 | return err 99 | } 100 | if srcInfo, err = os.Stat(src); err != nil { 101 | return err 102 | } 103 | if err = os.Chmod(dst, srcInfo.Mode()); err != nil { 104 | return err 105 | } 106 | return nil 107 | } 108 | 109 | func checkExist(root, sub string) error { 110 | if sub != "" { 111 | root = filepath.Join(root, sub) 112 | } 113 | exist, err := pathExists(root) 114 | if !exist { 115 | err = fmt.Errorf("%s is not exist", root) 116 | } 117 | return err 118 | } 119 | 120 | func pathExists(path string) (bool, error) { 121 | _, err := os.Stat(path) 122 | if err == nil { 123 | return true, nil 124 | } 125 | if os.IsNotExist(err) { 126 | return false, err 127 | } 128 | return false, err 129 | } 130 | 131 | func wait() { 132 | fmt.Printf("Press Enter to exit ...") 133 | endKey := make([]byte, 1) 134 | os.Stdin.Read(endKey) 135 | } 136 | 137 | func install() (err error) { 138 | installer, err := newInstaller() 139 | if err != nil { 140 | return err 141 | } 142 | if err = installer.prepare(); err != nil { 143 | return err 144 | } 145 | if err = installer.backupFile(); err != nil { 146 | return err 147 | } 148 | if err = installer.run(); err != nil { 149 | return err 150 | } 151 | fmt.Println("plugin install successfully") 152 | wait() 153 | return nil 154 | } 155 | 156 | func main() { 157 | if err := install(); err != nil { 158 | fmt.Println() 159 | panic(err) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /resources/plugin/bin/install_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rootDir=$(dirname "$(dirname "$PWD")") 4 | pluginDir="$rootDir/plugin" 5 | appPath="$rootDir/app" 6 | appsrcPath="$rootDir/appsrc" 7 | windowHTMLPath="$rootDir/window.html" 8 | windowHTMLBakPath="$rootDir/window.html.bak" 9 | pluginScript='' 10 | newFrameScript='' 11 | oldFrameScript='' 12 | frameScript="" 13 | 14 | panic() { 15 | echo -e "\033[0;31m ERROR: $1 \033[0m" 16 | exit 1 17 | } 18 | 19 | escape() { 20 | sed -E 's/[]\/$*.^|[]/\\&/g' <<<"$1" 21 | } 22 | 23 | echo "[1/9] check command" 24 | for cmd in echo cp cat chmod sed; do 25 | command -v "$cmd" &>/dev/null || panic "cannot find command $cmd, please install it." 26 | done 27 | 28 | echo "[2/9] check sudo" 29 | if [ "$EUID" -ne 0 ]; then 30 | panic "please run this script as root." 31 | fi 32 | 33 | echo "[3/9] check plugin exists" 34 | if ! [ -d "$pluginDir" ]; then 35 | panic "dir plugin does not exist in $rootDir" 36 | fi 37 | 38 | echo "[4/9] check whether window.html exists" 39 | if ! [ -f "$windowHTMLPath" ]; then 40 | panic "window.html does not exist in $rootDir" 41 | fi 42 | 43 | echo "[5/8] check whether app/appsrc exists" 44 | if [ -d "$appsrcPath" ]; then 45 | frameScript=$newFrameScript 46 | elif [ -d "$appPath" ]; then 47 | frameScript=$oldFrameScript 48 | else 49 | panic "appsrc/app does not exist in $rootDir" 50 | fi 51 | 52 | echo "[6/9] check window.html content" 53 | content=$(cat "$windowHTMLPath") 54 | if ! [[ $content == *"$frameScript"* ]]; then 55 | panic "window.html does not contains $frameScript" 56 | fi 57 | if [[ $content == *"$pluginScript"* ]]; then 58 | echo "plugin has already been installed" 59 | exit 60 | fi 61 | 62 | echo "[7/9] backup window.html" 63 | cp "$windowHTMLPath" "$windowHTMLBakPath" 64 | 65 | echo "[8/9] chmod plugin dir" 66 | chmod 0777 "$pluginDir" 67 | 68 | echo "[9/9] update window.html" 69 | escapedFrameScript=$(escape "$frameScript") 70 | escapedPluginScript=$(escape "$pluginScript") 71 | replacement="$escapedFrameScript$escapedPluginScript" 72 | newContent=$(echo -n "$content" | sed "s|$escapedFrameScript|$replacement|") 73 | echo "$newContent" >"$windowHTMLPath" 74 | echo "plugin install successfully" 75 | -------------------------------------------------------------------------------- /resources/plugin/bin/install_linux_amd_x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/bin/install_linux_amd_x64 -------------------------------------------------------------------------------- /resources/plugin/bin/install_windows.ps1: -------------------------------------------------------------------------------- 1 | $rootDir = (Get-Location).Path | Split-Path -Parent | Split-Path -Parent 2 | $appPath = Join-Path -Path $rootDir -ChildPath "app" 3 | $appsrcPath = Join-Path -Path $rootDir -ChildPath "appsrc" 4 | $windowHTMLPath = Join-Path -Path $rootDir -ChildPath "window.html" 5 | $windowHTMLBakPath = Join-Path -Path $rootDir -ChildPath "window.html.bak" 6 | $pluginScript = "" 7 | $oldFrameScript = "" 8 | $newFrameScript = "" 9 | $frameScript = "" 10 | $banner = @" 11 | ____________________________________________________________________ 12 | ______ __ _ 13 | /_ __/_ ______ ____ _________ _ ____ / /_ ______ _(_)___ 14 | / / / / / / __ \/ __ \/ ___/ __ ``/ / __ \/ / / / / __ ``/ / __ \ 15 | / / / /_/ / /_/ / /_/ / / / /_/ / / /_/ / / /_/ / /_/ / / / / / 16 | /_/ \__, / .___/\____/_/ \__,_/ / .___/_/\__,_/\__, /_/_/ /_/ 17 | /____/_/ /_/ /____/ 18 | Designed by obgnail 19 | https://github.com/obgnail/typora_plugin 20 | ____________________________________________________________________ 21 | "@ 22 | 23 | function finish {[CmdletBinding()]param ($msg) Write-Host $msg; PAUSE; Exit} 24 | function panic {[CmdletBinding()]param ($msg) Write-Error $msg; PAUSE; Exit} 25 | 26 | Write-Host $banner 27 | Write-Host "" 28 | Write-Host "[1/5] check whether file window.html exists in $rootDir" 29 | if (!(Test-Path -Path $windowHTMLPath)) { 30 | panic "window.html does not exist in $rootDir" 31 | } 32 | 33 | Write-Host "[2/5] check whether folder app/appsrc exists in $rootDir" 34 | if (Test-Path -Path $appsrcPath) { 35 | $frameScript = $newFrameScript 36 | } elseif (Test-Path -Path $appPath) { 37 | $frameScript = $oldFrameScript 38 | } else { 39 | panic "appsrc/app does not exist in $rootDir" 40 | } 41 | 42 | $fileContent = Get-Content -Path $windowHTMLPath -Encoding UTF8 -Raw 43 | $replacement = -Join($frameScript, $pluginScript) 44 | 45 | Write-Host "[3/5] check window.html content" 46 | if (!$fileContent.Contains($frameScript)) { 47 | panic "window.html does not contains $frameScript" 48 | } 49 | if ($fileContent.Contains($pluginScript)) { 50 | finish "plugin has already been installed" 51 | } 52 | 53 | Write-Host "[4/5] backup window.html" 54 | Copy-Item -Path $windowHTMLPath -Destination $windowHTMLBakPath 55 | 56 | Write-Host "[5/5] update window.html" 57 | $newFileContent = $fileContent -Replace [Regex]::Escape($frameScript), $replacement 58 | Set-Content -Path $windowHTMLPath -Value $newFileContent -Encoding UTF8 59 | finish "plugin install successfully" 60 | -------------------------------------------------------------------------------- /resources/plugin/bin/install_windows_amd_x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/bin/install_windows_amd_x64.exe -------------------------------------------------------------------------------- /resources/plugin/bin/uninstall_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rootDir=$(dirname "$(dirname "$PWD")") 4 | pluginDir="$rootDir/plugin" 5 | appPath="$rootDir/app" 6 | appsrcPath="$rootDir/appsrc" 7 | windowHTMLPath="$rootDir/window.html" 8 | windowHTMLBakPath="$rootDir/window.html.bak" 9 | pluginScript='' 10 | newFrameScript='' 11 | oldFrameScript='' 12 | frameScript="" 13 | 14 | panic() { 15 | echo -e "\033[0;31m ERROR: $1 \033[0m" 16 | exit 1 17 | } 18 | 19 | escape() { 20 | sed -E 's/[]\/$*.^|[]/\\&/g' <<<"$1" 21 | } 22 | 23 | echo "[1/8] check command" 24 | for cmd in echo cp cat sed; do 25 | command -v "$cmd" &>/dev/null || panic "cannot find command $cmd, please install it." 26 | done 27 | 28 | echo "[2/8] check sudo" 29 | if [ "$EUID" -ne 0 ]; then 30 | panic "please run this script as root." 31 | fi 32 | 33 | echo "[3/8] check plugin exists" 34 | if ! [ -d "$pluginDir" ]; then 35 | panic "dir plugin does not exist in $rootDir" 36 | fi 37 | 38 | echo "[4/8] check whether window.html exists" 39 | if ! [ -f "$windowHTMLPath" ]; then 40 | panic "window.html does not exist in $rootDir" 41 | fi 42 | 43 | echo "[5/8] check whether app/appsrc exists" 44 | if [ -d "$appsrcPath" ]; then 45 | frameScript=$newFrameScript 46 | elif [ -d "$appPath" ]; then 47 | frameScript=$oldFrameScript 48 | else 49 | panic "appsrc/app does not exist in $rootDir" 50 | fi 51 | 52 | echo "[6/8] check window.html content" 53 | content=$(cat "$windowHTMLPath") 54 | if ! [[ $content == *"$frameScript"* ]]; then 55 | panic "window.html does not contains $frameScript" 56 | fi 57 | if ! [[ $content == *"$pluginScript"* ]]; then 58 | echo "plugin has already been uninstalled" 59 | exit 60 | fi 61 | 62 | echo "[7/8] delete window.html.bak" 63 | rm -f "$windowHTMLBakPath" 64 | 65 | echo "[8/8] update window.html" 66 | escapedPluginScript=$(escape "$pluginScript") 67 | replacement="" 68 | newContent=$(echo -n "$content" | sed "s|$escapedPluginScript|$replacement|") 69 | echo "$newContent" >"$windowHTMLPath" 70 | echo "plugin uninstall successfully" 71 | -------------------------------------------------------------------------------- /resources/plugin/bin/uninstall_windows.ps1: -------------------------------------------------------------------------------- 1 | $rootDir = (Get-Location).Path | Split-Path -Parent | Split-Path -Parent 2 | $appPath = Join-Path -Path $rootDir -ChildPath "app" 3 | $appsrcPath = Join-Path -Path $rootDir -ChildPath "appsrc" 4 | $windowHTMLPath = Join-Path -Path $rootDir -ChildPath "window.html" 5 | $windowHTMLBakPath = Join-Path -Path $rootDir -ChildPath "window.html.bak" 6 | $pluginScript = "" 7 | $oldFrameScript = "" 8 | $newFrameScript = "" 9 | $frameScript = "" 10 | $banner = @" 11 | ____________________________________________________________________ 12 | ______ __ _ 13 | /_ __/_ ______ ____ _________ _ ____ / /_ ______ _(_)___ 14 | / / / / / / __ \/ __ \/ ___/ __ ``/ / __ \/ / / / / __ ``/ / __ \ 15 | / / / /_/ / /_/ / /_/ / / / /_/ / / /_/ / / /_/ / /_/ / / / / / 16 | /_/ \__, / .___/\____/_/ \__,_/ / .___/_/\__,_/\__, /_/_/ /_/ 17 | /____/_/ /_/ /____/ 18 | Designed by obgnail 19 | https://github.com/obgnail/typora_plugin 20 | ____________________________________________________________________ 21 | "@ 22 | 23 | function finish {[CmdletBinding()]param ($msg) Write-Host $msg; PAUSE; Exit} 24 | function panic {[CmdletBinding()]param ($msg) Write-Error $msg; PAUSE; Exit} 25 | 26 | Write-Host $banner 27 | Write-Host "" 28 | Write-Host "[1/5] check whether file window.html exists in $rootDir" 29 | if (!(Test-Path -Path $windowHTMLPath)) { 30 | panic "window.html does not exist in $rootDir" 31 | } 32 | 33 | Write-Host "[2/5] check whether folder app/appsrc exists in $rootDir" 34 | if (Test-Path -Path $appsrcPath) { 35 | $frameScript = $newFrameScript 36 | } elseif (Test-Path -Path $appPath) { 37 | $frameScript = $oldFrameScript 38 | } else { 39 | panic "appsrc/app does not exist in $rootDir" 40 | } 41 | 42 | $fileContent = Get-Content -Path $windowHTMLPath -Encoding UTF8 -Raw 43 | $replacement = "" 44 | 45 | Write-Host "[3/5] check window.html content" 46 | if (!$fileContent.Contains($frameScript)) { 47 | panic "window.html does not contains $frameScript" 48 | } 49 | if (!$fileContent.Contains($pluginScript)) { 50 | finish "plugin has already been uninstalled" 51 | } 52 | 53 | Write-Host "[4/5] delete window.html.bak" 54 | Remove-Item -Path $windowHTMLBakPath 55 | 56 | Write-Host "[5/5] update window.html" 57 | $newFileContent = $fileContent -Replace [Regex]::Escape($pluginScript), $replacement 58 | Set-Content -Path $windowHTMLPath -Value $newFileContent -Encoding UTF8 59 | finish "plugin uninstall successfully" 60 | -------------------------------------------------------------------------------- /resources/plugin/bin/version.json: -------------------------------------------------------------------------------- 1 | {"url":"https://api.github.com/repos/obgnail/typora_plugin/releases/207074079","assets_url":"https://api.github.com/repos/obgnail/typora_plugin/releases/207074079/assets","upload_url":"https://uploads.github.com/repos/obgnail/typora_plugin/releases/207074079/assets{?name,label}","html_url":"https://github.com/obgnail/typora_plugin/releases/tag/1.13.6","id":207074079,"author":{"login":"github-actions[bot]","id":41898282,"node_id":"MDM6Qm90NDE4OTgyODI=","avatar_url":"https://avatars.githubusercontent.com/in/15368?v=4","gravatar_id":"","url":"https://api.github.com/users/github-actions%5Bbot%5D","html_url":"https://github.com/apps/github-actions","followers_url":"https://api.github.com/users/github-actions%5Bbot%5D/followers","following_url":"https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github-actions%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/github-actions%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/github-actions%5Bbot%5D/repos","events_url":"https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/github-actions%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false},"node_id":"RE_kwDOJzwCYc4MV7Mf","tag_name":"1.13.6","target_commitish":"master","name":"1.13.6","draft":false,"prerelease":false,"created_at":"2025-03-20T05:45:30Z","published_at":"2025-03-20T06:36:12Z","assets":[{"url":"https://api.github.com/repos/obgnail/typora_plugin/releases/assets/239157071","id":239157071,"node_id":"RA_kwDOJzwCYc4OQT9P","name":"typora-plugin@v1.13.6.zip","label":"","uploader":{"login":"github-actions[bot]","id":41898282,"node_id":"MDM6Qm90NDE4OTgyODI=","avatar_url":"https://avatars.githubusercontent.com/in/15368?v=4","gravatar_id":"","url":"https://api.github.com/users/github-actions%5Bbot%5D","html_url":"https://github.com/apps/github-actions","followers_url":"https://api.github.com/users/github-actions%5Bbot%5D/followers","following_url":"https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github-actions%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/github-actions%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/github-actions%5Bbot%5D/repos","events_url":"https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/github-actions%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false},"content_type":"application/zip","state":"uploaded","size":3472825,"download_count":200,"created_at":"2025-03-20T06:36:12Z","updated_at":"2025-03-20T06:36:12Z","browser_download_url":"https://github.com/obgnail/typora_plugin/releases/download/1.13.6/typora-plugin%40v1.13.6.zip"}],"tarball_url":"https://api.github.com/repos/obgnail/typora_plugin/tarball/1.13.6","zipball_url":"https://api.github.com/repos/obgnail/typora_plugin/zipball/1.13.6","body":"1. 【feat】【markdownLint】支持自定义检测规则\r\n2. 【feat】【markdownLint】新增自定义的检测规则 MD101:MathBlocks must be surrounded by blank lines(#957)\r\n3. 【feat】【slash_commands】支持获取命令的文字环境(#961)\r\n4. 【feat】【slash_commands】command 类型支持使用 cursorOffset 参数\r\n5. 【chg】【slash_commands】优化代码\r\n\r\n![markdownlint-rule-math](https://github.com/user-attachments/assets/d6069683-0993-4289-942b-7854b5b7cec1)\r\n"} 2 | -------------------------------------------------------------------------------- /resources/plugin/blur.js: -------------------------------------------------------------------------------- 1 | class blurPlugin extends BasePlugin { 2 | beforeProcess = () => { 3 | if (!this.utils.supportHasSelector) { 4 | return this.utils.stopLoadPluginError 5 | } 6 | } 7 | 8 | hotkey = () => [{ hotkey: this.config.HOTKEY, callback: this.call }] 9 | 10 | init = () => { 11 | this.blurType = { BLUR: "blur", HIDE: "hide" }; 12 | this.css_id = "plugin-blur-style"; 13 | this.inBlur = this.config.BLUR_DEFAULT; 14 | } 15 | 16 | process = () => this.run(false); 17 | 18 | call = () => { 19 | this.inBlur = !this.inBlur; 20 | this.run(); 21 | } 22 | 23 | getStyleText = () => { 24 | const selector = "#write > [cid]:not(.md-focus):not(:has(.md-focus)):not(:has(.md-focus-container))"; 25 | const [effect, restore] = (this.config.BLUR_TYPE === this.blurType.HIDE) 26 | ? ["visibility: hidden;", "visibility: visible;"] 27 | : [`filter: blur(${this.config.BLUR_LEVEL}px);`, "filter: initial;"] 28 | 29 | let css = `${selector} { ${effect} }`; 30 | if (this.config.RESRTORE_WHEN_HOVER) { 31 | css += `${selector}:hover { ${restore} }`; 32 | } 33 | return css 34 | } 35 | 36 | run = (showNotification = true) => { 37 | if (this.inBlur) { 38 | this.utils.insertStyle(this.css_id, this.getStyleText()) 39 | } else { 40 | this.utils.removeStyle(this.css_id) 41 | } 42 | if (showNotification) { 43 | const msg = this.i18n.t(this.inBlur ? "modeEnabled" : "modeDisabled") 44 | this.utils.notification.show(msg) 45 | } 46 | } 47 | } 48 | 49 | module.exports = { 50 | plugin: blurPlugin, 51 | } 52 | -------------------------------------------------------------------------------- /resources/plugin/cipher/index.js: -------------------------------------------------------------------------------- 1 | class cipherPlugin extends BasePlugin { 2 | hotkey = () => [ 3 | { hotkey: this.config.ENCRYPT_HOTKEY, callback: () => this.call("encrypt") }, 4 | { hotkey: this.config.DECRYPT_HOTKEY, callback: () => this.call("decrypt") }, 5 | ] 6 | 7 | init = () => { 8 | this.AES_ECB = null 9 | // To prevent decryption failures, users are restricted from modifying the hard-coded secret key 10 | this.key = "n0hLis5FjgQxa3f31sSa2wm37J81g3upTlq9it9WlfK" 11 | this.showMessageBox = this.config.SHOW_HINT_MODAL 12 | this.staticActions = this.i18n.fillActions([ 13 | { act_value: "encrypt", act_hotkey: this.config.ENCRYPT_HOTKEY }, 14 | { act_value: "decrypt", act_hotkey: this.config.DECRYPT_HOTKEY }, 15 | ]) 16 | } 17 | 18 | call = async action => { 19 | const func = this[action] 20 | if (func) { 21 | await this.utils.editCurrentFile(func) 22 | } 23 | } 24 | 25 | encrypt = async raw => { 26 | const { encrypt } = this.lazyLoad() 27 | const isCiphered = this.utils.isBase64(raw) 28 | if (!this.showMessageBox && !isCiphered) { 29 | return encrypt(raw, this.key) 30 | } 31 | 32 | const title = this.i18n.t("msgBox.encrypt.title") 33 | const message = this.i18n.t(isCiphered ? "msgBox.encrypt.onCiphered" : "msgBox.encrypt.onPlain") 34 | const checkboxLabel = this.i18n._t("global", "disableReminder") 35 | const op = { type: "info", title, message, checkboxLabel } 36 | const { response, checkboxChecked } = await this.utils.showMessageBox(op) 37 | if (checkboxChecked) { 38 | this.showMessageBox = false 39 | } 40 | if (response === 0) { 41 | return isCiphered ? raw : encrypt(raw, this.key) 42 | } else if (response === 1) { 43 | return raw 44 | } 45 | } 46 | 47 | decrypt = async ciphered => { 48 | const { decrypt } = this.lazyLoad() 49 | const isCiphered = this.utils.isBase64(ciphered) 50 | if (isCiphered) { 51 | return decrypt(ciphered, this.key) 52 | } 53 | const title = this.i18n.t("msgBox.decrypt.title") 54 | const message = this.i18n.t("msgBox.decrypt.onPlain") 55 | const confirm = this.i18n._t("global", "confirm") 56 | const op = { type: "info", title, message, buttons: [confirm] } 57 | await this.utils.showMessageBox(op) 58 | return ciphered 59 | } 60 | 61 | lazyLoad = () => { 62 | this.AES_ECB = this.AES_ECB || require("./aes_ecb.min.js") 63 | return { encrypt: this.AES_ECB.AES_ECB_ENCRYPT, decrypt: this.AES_ECB.AES_ECB_DECRYPT } 64 | } 65 | } 66 | 67 | module.exports = { 68 | plugin: cipherPlugin, 69 | } 70 | -------------------------------------------------------------------------------- /resources/plugin/collapse_list.js: -------------------------------------------------------------------------------- 1 | /** To improve performance, the logic is moved to CSS, so this plugin uses a very hacky implementation approach. 2 | * 1. Use the pseudo-class ::before as the click button 3 | * 2. ::before uses the left style to float out of the parent element's BoundingClientRect 4 | * 3. When the parent element detects a click, check the mouse position. If the mouse position is outside the parent element's Rect, then determine that the pseudo-class has been clicked 5 | */ 6 | class collapseListPlugin extends BasePlugin { 7 | beforeProcess = () => { 8 | this.className = "plugin-collapsed-list"; 9 | this.selector = '#write [mdtype="list"]'; 10 | const color = this.config.TRIANGLE_COLOR || "var(--meta-content-color)"; 11 | this.triangleStyle = { left: -18, top: 0, height: 9, halfWidth: 7, color: color }; 12 | } 13 | 14 | styleTemplate = () => true 15 | 16 | process = () => { 17 | this.utils.runtime.autoSaveConfig(this); 18 | this.recordCollapseState(false); 19 | this.utils.entities.eWrite.addEventListener("click", ev => { 20 | const parent = ev.target.closest(this.selector); 21 | if (!parent) return; 22 | 23 | const { clientX, clientY } = ev; 24 | const { left: PLeft, top: PTop } = parent.getBoundingClientRect(); 25 | const { left: TLeft, top: TTop, height: THeight, halfWidth: THalfWidth } = this.triangleStyle; 26 | 27 | const left = PLeft + TLeft; 28 | const top = PTop + TTop; 29 | const height = THeight; 30 | const width = 2 * THalfWidth; 31 | if ( 32 | left - width <= clientX 33 | && clientX <= left + width 34 | && top - height <= clientY 35 | && clientY <= top + height 36 | ) { 37 | ev.stopPropagation(); 38 | ev.preventDefault(); 39 | this.toggleCollapse(parent); 40 | } 41 | }) 42 | } 43 | 44 | checkCollapse = ele => ele.classList.contains(this.className); 45 | setCollapse = ele => ele.classList.add(this.className); 46 | cancelCollapse = ele => ele.classList.remove(this.className); 47 | toggleCollapse = ele => ele.classList.toggle(this.className); 48 | 49 | recordCollapseState = (needChange = true) => { 50 | const name = "recordCollapseList"; 51 | if (needChange) { 52 | this.config.RECORD_COLLAPSE = !this.config.RECORD_COLLAPSE; 53 | } 54 | if (this.config.RECORD_COLLAPSE) { 55 | this.utils.stateRecorder.register(name, this.selector, this.checkCollapse, this.setCollapse) 56 | } else { 57 | this.utils.stateRecorder.unregister(name); 58 | } 59 | } 60 | 61 | rollback = start => { 62 | let cur = start; 63 | while (true) { 64 | cur = cur.closest(`.${this.className}`); 65 | if (!cur) return; 66 | this.cancelCollapse(cur); 67 | cur = cur.parentElement; 68 | } 69 | } 70 | 71 | getDynamicActions = () => this.i18n.fillActions([ 72 | { act_value: "record_collapse_state", act_state: this.config.RECORD_COLLAPSE } 73 | ]) 74 | 75 | call = action => { 76 | if (action === "record_collapse_state") { 77 | this.recordCollapseState(true); 78 | } 79 | } 80 | } 81 | 82 | module.exports = { 83 | plugin: collapseListPlugin 84 | } 85 | -------------------------------------------------------------------------------- /resources/plugin/collapse_table.js: -------------------------------------------------------------------------------- 1 | class collapseTablePlugin extends BasePlugin { 2 | styleTemplate = () => true 3 | 4 | init = () => { 5 | this.className = "plugin-collapse-table"; 6 | } 7 | 8 | process = () => { 9 | this.utils.runtime.autoSaveConfig(this); 10 | this.recordCollapseState(false); 11 | 12 | this.utils.decorate(() => File && File.editor && File.editor.tableEdit, "showTableEdit", null, (result, ...args) => { 13 | const $figure = args[0] 14 | if (!$figure || $figure.length === 0 || !$figure.find) return 15 | const $edit = $figure.find(".md-table-edit") 16 | if (!$edit || $edit.length === 0) return 17 | 18 | const icon = $figure.hasClass(this.className) ? "fa fa-plus" : "fa fa-minus" 19 | const span = ` 20 | 23 | ` 24 | $edit.append($(span)) 25 | }) 26 | 27 | this.utils.entities.eWrite.addEventListener("click", ev => { 28 | const btn = ev.target.closest(".plugin-collapse-table-btn"); 29 | if (!btn) return; 30 | const figure = btn.closest("figure"); 31 | if (!figure) return; 32 | this.toggleTable(figure); 33 | }) 34 | } 35 | 36 | call = (action, meta) => { 37 | if (action === "convert_current") { 38 | this.toggleTable(meta.target); 39 | } else if (action === "record_collapse_state") { 40 | this.recordCollapseState(true); 41 | } 42 | } 43 | 44 | getDynamicActions = (anchorNode, meta) => { 45 | const figure = anchorNode.closest("#write .table-figure") 46 | const act_hint = !figure ? this.i18n.t("actHint.convert_current") : "" 47 | meta.target = figure 48 | return this.i18n.fillActions([ 49 | { act_value: "convert_current", act_hint, act_disabled: !figure }, 50 | { act_value: "record_collapse_state", act_state: this.config.RECORD_COLLAPSE } 51 | ]) 52 | } 53 | 54 | toggleTable = figure => { 55 | const table = figure.querySelector("table"); 56 | if (!table) return; 57 | figure.classList.toggle(this.className); 58 | const btn = figure.querySelector(".plugin-collapse-table-btn"); 59 | if (btn) { 60 | const span = btn.querySelector("span"); 61 | span.classList.toggle("fa-plus"); 62 | span.classList.toggle("fa-minus"); 63 | } 64 | } 65 | 66 | rollback = start => { 67 | let cur = start; 68 | while (true) { 69 | cur = cur.closest(`.${this.className}`); 70 | if (!cur) return; 71 | this.toggleTable(cur); 72 | cur = cur.parentElement; 73 | } 74 | } 75 | 76 | checkCollapse = figure => figure.classList.contains(this.className); 77 | 78 | recordCollapseState = (needChange = true) => { 79 | const name = "recordCollapseTable"; 80 | const selector = "#write .table-figure"; 81 | if (needChange) { 82 | this.config.RECORD_COLLAPSE = !this.config.RECORD_COLLAPSE; 83 | } 84 | if (this.config.RECORD_COLLAPSE) { 85 | this.utils.stateRecorder.register(name, selector, this.checkCollapse, this.toggleTable); 86 | } else { 87 | this.utils.stateRecorder.unregister(name); 88 | } 89 | } 90 | } 91 | 92 | module.exports = { 93 | plugin: collapseTablePlugin 94 | } 95 | -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/abc/index.js: -------------------------------------------------------------------------------- 1 | class abcPlugin extends BaseCustomPlugin { 2 | init = () => this.ABCJS = null 3 | 4 | callback = anchorNode => this.utils.insertText(anchorNode, this.config.TEMPLATE) 5 | 6 | process = () => { 7 | const parser = this.utils.thirdPartyDiagramParser 8 | parser.register({ 9 | lang: this.config.LANGUAGE, 10 | mappingLang: this.config.LANGUAGE, 11 | destroyWhenUpdate: false, 12 | interactiveMode: this.config.INTERACTIVE_MODE, 13 | checkSelector: ".plugin-notation-content", 14 | wrapElement: '
', 15 | setStyleFunc: parser.STYLE_SETTER_SIMPLE({ 16 | height: this.config.DEFAULT_FENCE_HEIGHT, 17 | "background-color": this.config.DEFAULT_FENCE_BACKGROUND_COLOR 18 | }), 19 | lazyLoadFunc: this.lazyLoad, 20 | createFunc: this.create, 21 | updateFunc: null, 22 | destroyFunc: null, 23 | beforeExportToNative: null, 24 | beforeExportToHTML: null, 25 | extraStyleGetter: null, 26 | versionGetter: this.versionGetter, 27 | }) 28 | } 29 | 30 | create = ($wrap, content) => { 31 | const options = { ...this.config.VISUAL_OPTIONS } // set prototype 32 | this.ABCJS.renderAbc($wrap[0], content, options) 33 | } 34 | 35 | versionGetter = () => this.ABCJS && this.ABCJS.signature 36 | 37 | lazyLoad = () => this.ABCJS = require("./abcjs-basic-min.js") 38 | } 39 | 40 | module.exports = { 41 | plugin: abcPlugin 42 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/blockSideBySide.js: -------------------------------------------------------------------------------- 1 | class blockSideBySidePlugin extends BaseCustomPlugin { 2 | hotkey = () => [this.config.hotkey] 3 | 4 | styleTemplate = () => true 5 | 6 | callback = async anchorNode => { 7 | const enable = this.utils.styleTemplater.getStyleContent(this.fixedName); 8 | const func = enable ? "unregister" : "register"; 9 | await this.utils.styleTemplater[func](this.fixedName); 10 | } 11 | } 12 | 13 | module.exports = { 14 | plugin: blockSideBySidePlugin, 15 | }; -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/calendar/index.js: -------------------------------------------------------------------------------- 1 | class calendarPlugin extends BaseCustomPlugin { 2 | init = () => this.Calendar = null 3 | 4 | callback = anchorNode => this.utils.insertText(anchorNode, this.config.TEMPLATE) 5 | 6 | process = () => { 7 | const parser = this.utils.thirdPartyDiagramParser 8 | parser.register({ 9 | lang: this.config.LANGUAGE, 10 | mappingLang: "javascript", 11 | destroyWhenUpdate: false, 12 | interactiveMode: this.config.INTERACTIVE_MODE, 13 | checkSelector: ".plugin-calender-content", 14 | wrapElement: '
', 15 | setStyleFunc: parser.STYLE_SETTER({ 16 | height: this.config.DEFAULT_FENCE_HEIGHT, 17 | "background-color": this.config.DEFAULT_FENCE_BACKGROUND_COLOR 18 | }), 19 | lazyLoadFunc: this.lazyLoad, 20 | createFunc: this.create, 21 | updateFunc: null, 22 | destroyFunc: this.destroy, 23 | beforeExportToNative: null, 24 | beforeExportToHTML: null, 25 | extraStyleGetter: null, 26 | versionGetter: this.versionGetter, 27 | }) 28 | } 29 | 30 | create = ($wrap, content) => { 31 | const Calendar = this.Calendar 32 | const calendar = new this.Calendar($wrap[0]) 33 | let option = {} 34 | eval(content) 35 | calendar.setOptions(option) 36 | return calendar 37 | } 38 | 39 | destroy = instance => { 40 | instance.clear() 41 | instance.destroy() 42 | } 43 | 44 | versionGetter = () => "2.1.3" 45 | 46 | lazyLoad = () => { 47 | this.utils.insertStyleFile("plugin-calendar-style", "./plugin/custom/plugins/calendar/toastui-calendar.min.css") 48 | const { Calendar } = require("./toastui-calendar.min.js") 49 | this.Calendar = Calendar 50 | } 51 | } 52 | 53 | module.exports = { 54 | plugin: calendarPlugin 55 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/chart/index.js: -------------------------------------------------------------------------------- 1 | class chartPlugin extends BaseCustomPlugin { 2 | init = () => this.ChartPkg = null 3 | 4 | callback = anchorNode => this.utils.insertText(anchorNode, this.config.TEMPLATE) 5 | 6 | process = () => { 7 | const parser = this.utils.thirdPartyDiagramParser 8 | parser.register({ 9 | lang: this.config.LANGUAGE, 10 | mappingLang: "javascript", 11 | destroyWhenUpdate: false, 12 | interactiveMode: this.config.INTERACTIVE_MODE, 13 | checkSelector: ".plugin-chart-content", 14 | wrapElement: '
', 15 | setStyleFunc: parser.STYLE_SETTER({ 16 | height: this.config.DEFAULT_FENCE_HEIGHT, 17 | "background-color": this.config.DEFAULT_FENCE_BACKGROUND_COLOR 18 | }), 19 | lazyLoadFunc: this.lazyLoad, 20 | createFunc: this.create, 21 | updateFunc: null, 22 | destroyFunc: this.destroy, 23 | beforeExportToNative: null, 24 | beforeExportToHTML: this.beforeExportToHTML, 25 | extraStyleGetter: null, 26 | versionGetter: this.versionGetter, 27 | }) 28 | } 29 | 30 | create = ($wrap, content) => { 31 | const $canvas = $wrap.find("canvas") 32 | if ($canvas.length) { 33 | const ctx = $canvas[0].getContext("2d") 34 | return this.drawChart(ctx, content) 35 | } 36 | } 37 | 38 | destroy = instance => { 39 | instance.clear() 40 | instance.destroy() 41 | } 42 | 43 | drawChart = (ctx, content) => { 44 | let config = {} 45 | const Chart = this.ChartPkg.Chart 46 | eval(content) 47 | return new Chart(ctx, config) 48 | } 49 | 50 | beforeExportToHTML = (preview, instance) => { 51 | const img = new Image() 52 | img.src = instance.toBase64Image() 53 | $(preview).html(img) 54 | } 55 | 56 | versionGetter = () => this.ChartPkg && this.ChartPkg.version 57 | 58 | lazyLoad = () => this.ChartPkg = require("./chart.min.js") 59 | } 60 | 61 | module.exports = { 62 | plugin: chartPlugin 63 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/echarts/index.js: -------------------------------------------------------------------------------- 1 | class echartsPlugin extends BaseCustomPlugin { 2 | init = () => { 3 | this.echartsPkg = null 4 | this.exportType = this.config.EXPORT_TYPE.toLowerCase() 5 | } 6 | 7 | callback = anchorNode => this.utils.insertText(anchorNode, this.config.TEMPLATE) 8 | 9 | process = () => { 10 | const parser = this.utils.thirdPartyDiagramParser 11 | parser.register({ 12 | lang: this.config.LANGUAGE, 13 | mappingLang: "javascript", 14 | destroyWhenUpdate: false, 15 | interactiveMode: this.config.INTERACTIVE_MODE, 16 | checkSelector: ".plugin-echarts-content", 17 | wrapElement: '
', 18 | setStyleFunc: parser.STYLE_SETTER({ 19 | height: this.config.DEFAULT_FENCE_HEIGHT, 20 | "background-color": this.config.DEFAULT_FENCE_BACKGROUND_COLOR 21 | }), 22 | lazyLoadFunc: this.lazyLoad, 23 | createFunc: this.create, 24 | updateFunc: null, 25 | destroyFunc: this.destroy, 26 | beforeExportToNative: null, 27 | beforeExportToHTML: this.beforeExportToHTML, 28 | extraStyleGetter: null, 29 | versionGetter: this.versionGetter, 30 | }) 31 | } 32 | 33 | create = ($wrap, content) => { 34 | const myChart = this.echartsPkg.init($wrap[0], null, { renderer: this.config.RENDERER }) 35 | this.drawChart(myChart, content) 36 | return myChart 37 | } 38 | 39 | drawChart = (myChart, content, resize = false) => { 40 | // chart.showLoading() 41 | let echarts = this.echartsPkg 42 | let option = {} 43 | eval(content) 44 | myChart.clear() 45 | myChart.setOption(option) 46 | if (resize) { 47 | myChart.resize() 48 | } 49 | // chart.hideLoading() 50 | } 51 | 52 | destroy = instance => { 53 | instance.clear() 54 | instance.dispose() 55 | } 56 | 57 | beforeExportToHTML = (preview, instance) => { 58 | instance.setOption({ animation: false }) 59 | if (this.exportType === "png" || this.exportType === "jpg") { 60 | const img = new Image() 61 | img.src = instance.getDataURL({ type: this.exportType }) 62 | $(preview).html(img) 63 | } else if (this.exportType === "svg") { 64 | const svg = instance.renderToSVGString() 65 | $(preview).html(svg) 66 | } 67 | } 68 | 69 | versionGetter = () => this.echartsPkg && this.echartsPkg.version 70 | 71 | lazyLoad = () => this.echartsPkg = require("./echarts.min.js") 72 | } 73 | 74 | module.exports = { 75 | plugin: echartsPlugin 76 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/markdownLint/linter-worker.js: -------------------------------------------------------------------------------- 1 | let LIB 2 | let RULES 3 | let CUSTOM_RULES 4 | 5 | const linter = { 6 | init: ({ libPath, customRulePaths, config, content }) => { 7 | LIB = require(libPath) 8 | RULES = { "default": true, ...config } 9 | CUSTOM_RULES = customRulePaths.map(e => require(e)) 10 | console.debug(`markdownlint@${LIB.getVersion()} worker is initialized with rules`, RULES) 11 | if (content) { 12 | return linter.check({ content }) 13 | } 14 | }, 15 | check: async ({ content }) => { 16 | const op = { strings: { content }, config: RULES, customRules: CUSTOM_RULES } 17 | const result = await LIB.lint(op) 18 | return result.content.sort((a, b) => a.lineNumber - b.lineNumber) 19 | }, 20 | fix: async ({ content, fixInfo }) => { 21 | if (fixInfo && fixInfo.length) { 22 | return LIB.applyFixes(content, fixInfo) 23 | } 24 | }, 25 | } 26 | 27 | onmessage = async ({ data: { action, payload } }) => { 28 | if (!payload) return 29 | 30 | const fn = linter[action] 31 | if (!fn) { 32 | console.error("get error action:", action) 33 | return 34 | } 35 | const result = await fn(payload) 36 | if (result) { 37 | postMessage({ action, result }) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/marp/index.js: -------------------------------------------------------------------------------- 1 | class marpPlugin extends BaseCustomPlugin { 2 | styleTemplate = () => true 3 | 4 | init = () => this.marpPkg = null 5 | 6 | callback = anchorNode => this.utils.insertText(anchorNode, this.config.TEMPLATE) 7 | 8 | process = () => { 9 | const parser = this.utils.thirdPartyDiagramParser 10 | parser.register({ 11 | lang: this.config.LANGUAGE, 12 | mappingLang: "markdown", 13 | destroyWhenUpdate: false, 14 | interactiveMode: this.config.INTERACTIVE_MODE, 15 | checkSelector: ".plugin-marp-content", 16 | wrapElement: '
', 17 | setStyleFunc: null, 18 | lazyLoadFunc: this.lazyLoad, 19 | createFunc: this.create, 20 | updateFunc: null, 21 | destroyFunc: this.destroy, 22 | beforeExportToNative: null, 23 | beforeExportToHTML: null, 24 | extraStyleGetter: null, 25 | versionGetter: this.versionGetter, 26 | }) 27 | } 28 | 29 | create = ($wrap, content) => { 30 | const { Marp, marp } = this.marpPkg // more detail: https://github.com/marp-team/marp-core 31 | const shadowRoot = $wrap[0].shadowRoot || $wrap[0].attachShadow({ mode: "open" }) // use shadowDOM to isolate styles 32 | const { html, css } = marp.render(content) 33 | shadowRoot.innerHTML = `` + html 34 | return shadowRoot 35 | } 36 | 37 | destroy = shadowRoot => shadowRoot.innerHTML = "" 38 | 39 | versionGetter = () => "marp-core@3.9.0" 40 | 41 | lazyLoad = () => this.marpPkg = require("./marp.min.js") 42 | } 43 | 44 | module.exports = { 45 | plugin: marpPlugin 46 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/redirectLocalRootUrl.js: -------------------------------------------------------------------------------- 1 | class redirectLocalRootUrlPlugin extends BaseCustomPlugin { 2 | beforeProcess = () => { 3 | if (!this.config.root) { 4 | return this.utils.stopLoadPluginError 5 | } 6 | } 7 | 8 | init = () => { 9 | const { filter_regexp } = this.config 10 | this.filter = filter_regexp ? new RegExp(filter_regexp) : undefined 11 | } 12 | 13 | needRedirect = (filepath = this.utils.getFilePath()) => { 14 | return this.filter ? this.filter.test(filepath) : true 15 | } 16 | 17 | process = () => { 18 | const redirect = typoraRootUrl => { 19 | const dontRedirect = typoraRootUrl || !this.needRedirect() 20 | return dontRedirect 21 | ? typoraRootUrl 22 | : this.utils.Package.Path.resolve(this.utils.getCurrentDirPath(), this.config.root) 23 | } 24 | this.utils.decorate(() => File && File.editor && File.editor.docMenu, "getLocalRootUrl", null, redirect, true) 25 | } 26 | } 27 | 28 | module.exports = { 29 | plugin: redirectLocalRootUrlPlugin 30 | } 31 | -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/reopenClosedFiles/index.js: -------------------------------------------------------------------------------- 1 | class reopenClosedFilesPlugin extends BaseCustomPlugin { 2 | init = () => { 3 | this.windowTabBarPlugin = null; 4 | this.saveFile = this.utils.joinPath("./plugin/custom/plugins/reopenClosedFiles/remain.json"); 5 | } 6 | 7 | hotkey = () => [this.config.hotkey] 8 | 9 | process = () => { 10 | this.utils.eventHub.addEventListener(this.utils.eventHub.eventType.allPluginsHadInjected, async () => { 11 | this.windowTabBarPlugin = this.utils.getPlugin("window_tab"); 12 | if (!this.windowTabBarPlugin) return; 13 | await this.ensureFile(); 14 | if (this.config.auto_reopen_when_init) { 15 | // Redirection is disabled when opening specific files (isDiscardableUntitled === false). 16 | this.utils.loopDetector(this.utils.isDiscardableUntitled, this.callback, 40, 2000, false); 17 | } 18 | setTimeout(() => this.utils.eventHub.addEventListener(this.utils.eventHub.eventType.fileContentLoaded, this.save), 2500); 19 | }) 20 | } 21 | 22 | save = async () => this.windowTabBarPlugin && this.windowTabBarPlugin.saveTabs(this.saveFile); 23 | 24 | ensureFile = async () => await this.utils.Package.FsExtra.ensureFile(this.saveFile); 25 | 26 | callback = anchorNode => this.windowTabBarPlugin && this.windowTabBarPlugin.openSaveTabs(this.saveFile, true); 27 | } 28 | 29 | module.exports = { 30 | plugin: reopenClosedFilesPlugin, 31 | } 32 | -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/reopenClosedFiles/remain.json: -------------------------------------------------------------------------------- 1 | { 2 | "save_tabs": [ 3 | { 4 | "idx": 0, 5 | "path": "E:\\book\\dev\\flask.md", 6 | "active": false, 7 | "scrollTop": 7500 8 | }, 9 | { 10 | "idx": 1, 11 | "path": "E:\\book\\dev\\gitbook.md", 12 | "active": true, 13 | "scrollTop": 5422 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /resources/plugin/custom/plugins/scrollBookmarker/bookmark.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /resources/plugin/dark.js: -------------------------------------------------------------------------------- 1 | class darkModePlugin extends BasePlugin { 2 | styleTemplate = () => true 3 | 4 | init = () => { 5 | this.class = "plugin-dark" 6 | this.isDarkMode = this.config.DARK_DEFAULT 7 | } 8 | 9 | hotkey = () => [this.config.HOTKEY] 10 | 11 | enableDarkMode = () => this._toggleDarkMode(true) 12 | 13 | disableDarkMode = () => this._toggleDarkMode(false) 14 | 15 | toggleDarkMode = () => { 16 | this._toggleDarkMode(!this.isDarkMode) 17 | const msg = this.i18n.t(this.isDarkMode ? "modeEnabled" : "modeDisabled") 18 | this.utils.notification.show(msg) 19 | } 20 | 21 | _toggleDarkMode = enable => { 22 | document.documentElement.classList.toggle(this.class, enable) 23 | this.isDarkMode = enable 24 | } 25 | 26 | process = () => this.isDarkMode && this.enableDarkMode() 27 | 28 | call = (action, meta) => this.toggleDarkMode() 29 | } 30 | 31 | module.exports = { 32 | plugin: darkModePlugin, 33 | } 34 | -------------------------------------------------------------------------------- /resources/plugin/datatables/resource/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/datatables/resource/sort_asc.png -------------------------------------------------------------------------------- /resources/plugin/datatables/resource/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/datatables/resource/sort_asc_disabled.png -------------------------------------------------------------------------------- /resources/plugin/datatables/resource/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/datatables/resource/sort_both.png -------------------------------------------------------------------------------- /resources/plugin/datatables/resource/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/datatables/resource/sort_desc.png -------------------------------------------------------------------------------- /resources/plugin/datatables/resource/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/datatables/resource/sort_desc_disabled.png -------------------------------------------------------------------------------- /resources/plugin/editor_width_slider.js: -------------------------------------------------------------------------------- 1 | class editorWidthSliderPlugin extends BasePlugin { 2 | process = async () => { 3 | this.utils.runtime.autoSaveConfig(this); 4 | await this._setWidth(); 5 | } 6 | 7 | _setWidth = async (width = this.config.WIDTH_RATIO) => { 8 | const { eWrite } = this.utils.entities; 9 | if (width < 0) { 10 | eWrite.style.removeProperty("max-width"); 11 | } else { 12 | eWrite.style.setProperty("max-width", `${width}%`, "important"); 13 | } 14 | } 15 | 16 | setWidth = async () => { 17 | const labelWidth = this.i18n.t("widthProportion") 18 | const labelRecover = this.i18n.t("recover") 19 | 20 | const { eContent, eWrite } = this.utils.entities 21 | const value = parseInt(eWrite.offsetWidth * 100 / eContent.offsetWidth) 22 | const oninput = ev => this._setWidth(ev.target.value) 23 | 24 | const components = [ 25 | { label: labelWidth, type: "range", min: 30, max: 100, step: 1, value, oninput }, 26 | { label: "", type: "checkbox", list: [{ label: labelRecover, value: "recover" }] }, 27 | ] 28 | const op = { title: this.pluginName, components } 29 | const { response, submit: [width, [checkbox]] } = await this.utils.dialog.modalAsync(op) 30 | if (response === 1) { 31 | this.config.WIDTH_RATIO = checkbox === "recover" ? -1 : width 32 | } 33 | await this._setWidth() 34 | } 35 | 36 | call = async (action, meta) => await this.setWidth() 37 | } 38 | 39 | module.exports = { 40 | plugin: editorWidthSliderPlugin, 41 | } 42 | -------------------------------------------------------------------------------- /resources/plugin/fence_enhance/resource/comment-fold.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function(mod) { 5 | mod(CodeMirror); 6 | })(function(CodeMirror) { 7 | "use strict"; 8 | 9 | CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { 10 | return mode.blockCommentStart && mode.blockCommentEnd; 11 | }, function(cm, start) { 12 | var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; 13 | if (!startToken || !endToken) return; 14 | var line = start.line, lineText = cm.getLine(line); 15 | 16 | var startCh; 17 | for (var at = start.ch, pass = 0;;) { 18 | var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); 19 | if (found == -1) { 20 | if (pass == 1) return; 21 | pass = 1; 22 | at = lineText.length; 23 | continue; 24 | } 25 | if (pass == 1 && found < start.ch) return; 26 | if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && 27 | (found == 0 || lineText.slice(found - endToken.length, found) == endToken || 28 | !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { 29 | startCh = found + startToken.length; 30 | break; 31 | } 32 | at = found - 1; 33 | } 34 | 35 | var depth = 1, lastLine = cm.lastLine(), end, endCh; 36 | outer: for (var i = line; i <= lastLine; ++i) { 37 | var text = cm.getLine(i), pos = i == line ? startCh : 0; 38 | for (;;) { 39 | var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); 40 | if (nextOpen < 0) nextOpen = text.length; 41 | if (nextClose < 0) nextClose = text.length; 42 | pos = Math.min(nextOpen, nextClose); 43 | if (pos == text.length) break; 44 | if (pos == nextOpen) ++depth; 45 | else if (!--depth) { end = i; endCh = pos; break outer; } 46 | ++pos; 47 | } 48 | } 49 | if (end == null || line == end && endCh == startCh) return; 50 | return {from: CodeMirror.Pos(line, startCh), 51 | to: CodeMirror.Pos(end, endCh)}; 52 | }); 53 | 54 | }); -------------------------------------------------------------------------------- /resources/plugin/fence_enhance/resource/foldgutter.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-foldmarker { 2 | color: blue; 3 | text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; 4 | font-family: arial; 5 | line-height: .3; 6 | cursor: pointer; 7 | } 8 | .CodeMirror-foldgutter { 9 | width: .7em; 10 | } 11 | .CodeMirror-foldgutter-open, 12 | .CodeMirror-foldgutter-folded { 13 | cursor: pointer; 14 | } 15 | .CodeMirror-foldgutter-open:after { 16 | content: "\25BE"; 17 | } 18 | .CodeMirror-foldgutter-folded:after { 19 | content: "\25B8"; 20 | } 21 | -------------------------------------------------------------------------------- /resources/plugin/fence_enhance/resource/indent-fold.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function(mod) { 5 | mod(CodeMirror); 6 | })(function(CodeMirror) { 7 | "use strict"; 8 | 9 | function lineIndent(cm, lineNo) { 10 | var text = cm.getLine(lineNo) 11 | var spaceTo = text.search(/\S/) 12 | if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) 13 | return -1 14 | return CodeMirror.countColumn(text, null, cm.getOption("tabSize")) 15 | } 16 | 17 | CodeMirror.registerHelper("fold", "indent", function(cm, start) { 18 | var myIndent = lineIndent(cm, start.line) 19 | if (myIndent < 0) return 20 | var lastLineInFold = null 21 | 22 | // Go through lines until we find a line that definitely doesn't belong in 23 | // the block we're folding, or to the end. 24 | for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { 25 | var indent = lineIndent(cm, i) 26 | if (indent == -1) { 27 | } else if (indent > myIndent) { 28 | // Lines with a greater indent are considered part of the block. 29 | lastLineInFold = i; 30 | } else { 31 | // If this line has non-space, non-comment content, and is 32 | // indented less or equal to the start line, it is the start of 33 | // another block. 34 | break; 35 | } 36 | } 37 | if (lastLineInFold) return { 38 | from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), 39 | to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) 40 | }; 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /resources/plugin/fence_enhance/resource/markdown-fold.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function(mod) { 5 | mod(CodeMirror); 6 | })(function(CodeMirror) { 7 | "use strict"; 8 | 9 | CodeMirror.registerHelper("fold", "markdown", function(cm, start) { 10 | var maxDepth = 100; 11 | 12 | function isHeader(lineNo) { 13 | var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); 14 | return tokentype && /\bheader\b/.test(tokentype); 15 | } 16 | 17 | function headerLevel(lineNo, line, nextLine) { 18 | var match = line && line.match(/^#+/); 19 | if (match && isHeader(lineNo)) return match[0].length; 20 | match = nextLine && nextLine.match(/^[=\-]+\s*$/); 21 | if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; 22 | return maxDepth; 23 | } 24 | 25 | var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); 26 | var level = headerLevel(start.line, firstLine, nextLine); 27 | if (level === maxDepth) return undefined; 28 | 29 | var lastLineNo = cm.lastLine(); 30 | var end = start.line, nextNextLine = cm.getLine(end + 2); 31 | while (end < lastLineNo) { 32 | if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; 33 | ++end; 34 | nextLine = nextNextLine; 35 | nextNextLine = cm.getLine(end + 2); 36 | } 37 | 38 | return { 39 | from: CodeMirror.Pos(start.line, firstLine.length), 40 | to: CodeMirror.Pos(end, cm.getLine(end).length) 41 | }; 42 | }); 43 | 44 | }); -------------------------------------------------------------------------------- /resources/plugin/global/core/i18n.js: -------------------------------------------------------------------------------- 1 | const getUserLocale = (lang) => { 2 | if (lang === "auto") { 3 | lang = window._options.userLocale 4 | } 5 | switch (lang) { 6 | case "zh-CN": 7 | case "zh-Hans": 8 | return "zh-CN" 9 | case "zh-TW": 10 | case "zh-Hant": 11 | return "zh-TW" 12 | // case "ko": 13 | // case "ko-KR": 14 | // return "ko" 15 | // case "ja": 16 | // case "ja-JP": 17 | // return "ja" 18 | case "Base": 19 | case "en-US": 20 | case "en-BG": 21 | case "en": 22 | default: 23 | return "en" 24 | } 25 | } 26 | 27 | const i18n = { 28 | locale: "", 29 | data: {}, 30 | init: async function (locale) { 31 | try { 32 | locale = getUserLocale(locale) 33 | const path = require("path") 34 | const file = path.join(path.dirname(__dirname), "locales", `${locale}.json`) 35 | const json = await require("fs").promises.readFile(file, "utf8") 36 | this.data = JSON.parse(json) 37 | this.locale = locale 38 | } catch (error) { 39 | console.error("Could not load translations:", error) 40 | } 41 | }, 42 | t: function (field, key, variables) { 43 | const field_ = i18n.data[field] 44 | if (field_ === undefined) { 45 | return key 46 | } 47 | let text = field_[key] 48 | if (text === undefined) { 49 | return key 50 | } 51 | if (variables) { 52 | for (const [k, v] of Object.entries(variables)) { 53 | const placeholder = new RegExp(`{{${k}}}`, "g") 54 | text = text.replace(placeholder, v) 55 | } 56 | } 57 | return text 58 | }, 59 | link: function (parts) { 60 | return parts.join(i18n.locale.startsWith("zh") ? "" : " ") 61 | }, 62 | array: function (field, keys, prefix = "") { 63 | return keys.map(k => i18n.t(field, prefix + k)) 64 | }, 65 | entries: function (field, keys, prefix = "") { 66 | return Object.fromEntries(keys.map(k => [k, i18n.t(field, prefix + k)])) 67 | }, 68 | bind: function (field) { 69 | return { 70 | data: i18n.data[field], 71 | link: i18n.link, 72 | _t: i18n.t, 73 | t: (key, variables) => i18n.t(field, key, variables), 74 | array: (keys, prefix) => i18n.array(field, keys, prefix), 75 | entries: (keys, prefix) => i18n.entries(field, keys, prefix), 76 | fillActions: (actions) => { 77 | for (const act of actions) { 78 | if (!act.act_name && act.act_value) { 79 | act.act_name = i18n.t(field, `act.${act.act_value}`) 80 | } 81 | } 82 | return actions 83 | }, 84 | } 85 | } 86 | } 87 | 88 | module.exports = { 89 | i18n 90 | } 91 | -------------------------------------------------------------------------------- /resources/plugin/global/core/index.js: -------------------------------------------------------------------------------- 1 | const { i18n } = require("./i18n") 2 | const { utils, hook } = require("./utils") 3 | const { BasePlugin, BaseCustomPlugin, LoadPlugins } = require("./plugin") 4 | 5 | async function entry() { 6 | /** 7 | * Initializes global variables. 8 | * The plugin system exposes a total of 8 global variables, but only 3 are actually useful: BasePlugin, BaseCustomPlugin, and LoadPlugins. 9 | * The remaining 4 are exposed by the static class `utils` and should never be referenced by business plugins. 10 | * Furthermore, `utils` is also an instance property of BasePlugin and BaseCustomPlugin, so `utils` itself doesn't need to be exposed. 11 | * If they will never be referenced by business plugins, why are they set as global variables? Answer: For debugging convenience. 12 | **/ 13 | const initVariable = settings => { 14 | global.BasePlugin = BasePlugin 15 | global.BaseCustomPlugin = BaseCustomPlugin 16 | global.LoadPlugins = LoadPlugins 17 | 18 | global.__plugins__ = null 19 | global.__plugin_utils__ = utils 20 | global.__plugin_i18n__ = i18n 21 | global.__plugin_settings__ = settings 22 | global.__global_settings__ = settings.global 23 | 24 | delete settings.global 25 | } 26 | 27 | const initI18N = (locale) => i18n.init(locale) 28 | 29 | const loadPlugins = async () => { 30 | const { enable, disable, stop, error, nosetting } = await LoadPlugins(global.__plugin_settings__, false) 31 | global.__plugins__ = enable 32 | } 33 | 34 | /** 35 | * For Typora versions below 0.9.98, a compatibility warning is issued when running the plugin system. 36 | */ 37 | const showWarn = () => { 38 | const need = global.__global_settings__.SHOW_INCOMPATIBLE_WARNING 39 | const incompatible = utils.compareVersion(utils.typoraVersion, "0.9.98") < 0 40 | if (need && incompatible) { 41 | const msg = i18n.t("global", "incompatibilityWarning") 42 | utils.notification.show(msg, "warning", 5000) 43 | } 44 | } 45 | 46 | const launch = async () => { 47 | const settings = await utils.runtime.readBasePluginSetting() 48 | const enable = settings && settings.global && settings.global.ENABLE 49 | if (!enable) { 50 | console.warn("disable typora plugin") 51 | return 52 | } 53 | 54 | await initI18N(settings.global.LOCALE) 55 | initVariable(settings) 56 | await hook(loadPlugins) 57 | showWarn() 58 | } 59 | 60 | await launch() 61 | } 62 | 63 | module.exports = { 64 | entry 65 | } 66 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/common/toml/index.js: -------------------------------------------------------------------------------- 1 | var parser = require('./parser'); 2 | var compiler = require('./compiler'); 3 | var stringify = require('./stringify'); 4 | 5 | module.exports = { 6 | parse: function(input) { 7 | var nodes = parser.parse(input.toString()); 8 | return compiler.compile(nodes); 9 | }, 10 | stringify, 11 | }; 12 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/env.js: -------------------------------------------------------------------------------- 1 | const getHook = utils => { 2 | const { i18n } = require("../i18n") 3 | const MIXIN = require("./mixin") 4 | const mixin = Object.fromEntries(Object.entries(MIXIN).map(([name, cls]) => [[name], new cls(utils, i18n)])) 5 | 6 | const { 7 | hotkeyHub, eventHub, stateRecorder, exportHelper, contextMenu, 8 | notification, progressBar, dialog, diagramParser, thirdPartyDiagramParser, 9 | extra, polyfill, 10 | } = mixin 11 | 12 | // monkey patch 13 | // we should use composition to layer various functions, but utils is outdated and has become legacy code. My apologies 14 | Object.assign(utils, mixin, { 15 | /** @deprecated new API: utils.hotkeyHub.register */ 16 | registerHotkey: hotkeyHub.register, 17 | /** @deprecated new API: utils.hotkeyHub.registerSingle */ 18 | registerSingleHotkey: hotkeyHub.registerSingle, 19 | 20 | /** @deprecated new API: utils.eventHub.eventType */ 21 | eventType: eventHub.eventType, 22 | /** @deprecated new API: utils.eventHub.addEventListener */ 23 | addEventListener: eventHub.addEventListener, 24 | 25 | /** @deprecated new API: utils.dialog.modal */ 26 | modal: dialog.modal 27 | }) 28 | 29 | const registerMixin = (...ele) => Promise.all(ele.map(h => h.process && h.process())) 30 | const optimizeMixin = () => Promise.all(Object.values(mixin).map(h => h.afterProcess && h.afterProcess())) 31 | 32 | const registerPreMixin = async () => { 33 | await registerMixin(polyfill) 34 | await registerMixin(extra) 35 | await registerMixin(contextMenu, notification, progressBar, dialog, stateRecorder, hotkeyHub, exportHelper) 36 | } 37 | 38 | const registerPostMixin = async () => { 39 | await registerMixin(eventHub) 40 | await registerMixin(diagramParser, thirdPartyDiagramParser) 41 | eventHub.publishEvent(eventHub.eventType.allPluginsHadInjected) 42 | } 43 | 44 | // Due to the use of async, some events may have been missed (such as afterAddCodeBlock), reload it 45 | const postLoadPlugin = () => { 46 | if (File.getMountFolder() != null) { 47 | setTimeout(utils.reload, 50) 48 | } 49 | } 50 | 51 | return async pluginLoader => { 52 | await registerPreMixin() 53 | await pluginLoader() 54 | await registerPostMixin() 55 | await optimizeMixin() 56 | postLoadPlugin() 57 | } 58 | } 59 | 60 | module.exports = { 61 | getHook 62 | } 63 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/entities.js: -------------------------------------------------------------------------------- 1 | class entities { 2 | constructor(utils) { 3 | this.utils = utils; 4 | this.eWrite = document.querySelector("#write"); 5 | this.eContent = document.querySelector("content"); 6 | this.$eWrite = $(this.eWrite); 7 | this.$eContent = $(this.eContent); 8 | 9 | this.querySelectorAllInWrite = (...args) => this.eWrite.querySelectorAll(...args); 10 | this.querySelectorInWrite = (...args) => this.eWrite.querySelector(...args); 11 | } 12 | } 13 | 14 | module.exports = { 15 | entities 16 | } 17 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/extra.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Register additional HTML and CSS. 3 | */ 4 | class extra { 5 | constructor(utils) { 6 | this.utils = utils; 7 | } 8 | 9 | registerCSS = async () => { 10 | const files = ["plugin-common", "customize"]; 11 | return Promise.all(files.map(f => this.utils.styleTemplater.register(f))); 12 | } 13 | 14 | registerHTML = () => { 15 | this.utils.insertElement(` 16 | 17 | 18 | Processing 19 | 20 | 21 | 22 | `); 23 | } 24 | 25 | process = async () => { 26 | await this.registerCSS(); 27 | this.registerHTML(); 28 | } 29 | } 30 | 31 | module.exports = { 32 | extra 33 | } 34 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/hotkeyHub.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dynamically register and unregister hotkeys. 3 | */ 4 | class hotkeyHub { 5 | constructor(utils) { 6 | this.utils = utils; 7 | this.map = new Map(); 8 | } 9 | 10 | normalize = hotkeyString => { 11 | const modifier = ["ctrl", "shift", "alt"]; 12 | const keyList = hotkeyString.toLowerCase().split("+").map(k => k.trim()); 13 | const modifierKeys = modifier.filter(k => keyList.includes(k)); 14 | const mainKey = keyList.find(k => !modifier.includes(k)) || (hotkeyString.includes("++") ? "+" : " "); 15 | return [...modifierKeys, mainKey].join("+"); 16 | } 17 | 18 | _register = (hotkey, call) => { 19 | if (typeof hotkey === "string" && hotkey.length) { 20 | this.map.set(this.normalize(hotkey), call); 21 | // A callback may correspond to multiple hotkeys. 22 | } else if (hotkey instanceof Array) { 23 | for (const hk of hotkey) { 24 | this._register(hk, call); 25 | } 26 | } 27 | } 28 | 29 | /** 30 | * Does not validate the legality of hotkeyString. The caller needs to ensure that the hotkey is not occupied and has no typos. 31 | * @param {[{string, function}]} hotkeyList: [ { hotkey: "ctrl+shift+c", callback: () => console.log("ctrl+shift+c pressed") }, ] 32 | */ 33 | register = hotkeyList => { 34 | if (!hotkeyList) return; 35 | for (const item of hotkeyList) { 36 | if (item instanceof Array) { 37 | this.register(item); 38 | } else { 39 | this._register(item.hotkey, item.callback); 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * @param {string} hotkeyString: "ctrl+shift+c" 46 | */ 47 | unregister = hotkeyString => this.map.delete(this.normalize(hotkeyString)) 48 | 49 | registerSingle = (hotkeyString, callback) => this._register(hotkeyString, callback) 50 | 51 | process = () => { 52 | window.addEventListener("keydown", ev => { 53 | if (ev.key === undefined) return; 54 | const arr = []; 55 | this.utils.metaKeyPressed(ev) && arr.push("ctrl"); 56 | this.utils.shiftKeyPressed(ev) && arr.push("shift"); 57 | this.utils.altKeyPressed(ev) && arr.push("alt"); 58 | arr.push(ev.key.toLowerCase()); 59 | const key = arr.join("+"); 60 | const callback = this.map.get(key); 61 | if (callback) { 62 | callback(); 63 | ev.preventDefault(); 64 | ev.stopPropagation(); 65 | } 66 | }, true) 67 | } 68 | } 69 | 70 | module.exports = { 71 | hotkeyHub 72 | } 73 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/htmlTemplater.js: -------------------------------------------------------------------------------- 1 | /** 2 | * insert html tag 3 | * 3x faster then innerHTML, less memory usage, more secure, but poor readable 4 | * don't use unless element is simple enough or there are secure issues 5 | */ 6 | class htmlTemplater { 7 | constructor(utils) { 8 | this.utils = utils; 9 | this.defaultElement = "div"; 10 | } 11 | 12 | create = template => { 13 | if (!template) return; 14 | if (template instanceof Element) return template 15 | 16 | const el = document.createElement(template.ele || this.defaultElement); 17 | this.setAttributes(el, template); 18 | return el 19 | } 20 | 21 | setAttributes(el, obj) { 22 | for (const [prop, value] of Object.entries(obj)) { 23 | if (value == null) continue; 24 | switch (prop) { 25 | case "ele": 26 | break; 27 | case "class": 28 | case "className": 29 | case "class_": 30 | el.classList.add(...(Array.isArray(value) ? value : value.trim().split(/\s+/g))); 31 | break; 32 | case "text": 33 | el.innerText = value; 34 | break; 35 | case "style": 36 | Object.assign(el.style, value); 37 | break; 38 | case "children": 39 | this.appendElements(el, value); 40 | break; 41 | default: 42 | el.setAttribute(prop, value); 43 | } 44 | } 45 | } 46 | 47 | createList = templates => templates.map(this.create).filter(Boolean) 48 | insert = templates => this.utils.insertElement(this.createList(templates)) 49 | appendElements = (parent, templates) => parent.append(...this.createList(templates)) 50 | } 51 | 52 | module.exports = { 53 | htmlTemplater 54 | } -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("./polyfill"), 3 | ...require("./runtime"), 4 | ...require("./migrate"), 5 | ...require("./hotkeyHub"), 6 | ...require("./eventHub"), 7 | ...require("./stateRecorder"), 8 | ...require("./exportHelper"), 9 | ...require("./styleTemplater"), 10 | ...require("./htmlTemplater"), 11 | ...require("./contextMenu"), 12 | ...require("./notification"), 13 | ...require("./progressBar"), 14 | ...require("./dialog"), 15 | ...require("./diagramParser"), 16 | ...require("./thirdPartyDiagramParser"), 17 | ...require("./entities"), 18 | ...require("./extra"), 19 | ...require("./searchStringParser"), 20 | } -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/notification.js: -------------------------------------------------------------------------------- 1 | class notification { 2 | constructor(utils) { 3 | this.utils = utils; 4 | this.timer = null; 5 | this.types = { 6 | success: { bgColor: "#e6ffed", iconColor: "#009688", icon: "fa fa-check" }, 7 | info: { bgColor: "#e6f7ff", iconColor: "#448aff", icon: "fa fa-info-circle" }, 8 | warning: { bgColor: "#fffbe6", iconColor: "#f57c00", icon: "fa fa-warning" }, 9 | error: { bgColor: "#ffe6e6", iconColor: "#d32f2f", icon: "fa fa-bug" }, 10 | } 11 | } 12 | 13 | process = async () => { 14 | await this.utils.styleTemplater.register("plugin-common-notification"); 15 | this.utils.insertElement(` 16 |
17 | 18 | 19 | 20 |
21 | `); 22 | document.querySelector(".plugin-common-notification .notification-close-btn").addEventListener("click", () => this.hide()); 23 | } 24 | 25 | getNotification = () => document.querySelector(".plugin-common-notification") 26 | 27 | hide = () => this.utils.hide(this.getNotification()) 28 | 29 | show = (message, type = "success", last = 3000) => { 30 | clearTimeout(this.timer) 31 | if (!this.types.hasOwnProperty(type)) { 32 | type = "info" 33 | } 34 | const { bgColor, iconColor, icon } = this.types[type] 35 | const notification = this.getNotification() 36 | notification.querySelector(".notification-message").textContent = message 37 | notification.querySelector(".notification-icon").className = `notification-icon ${icon}` 38 | notification.style.setProperty("--notification-bg-color", bgColor) 39 | notification.style.setProperty("--notification-icon-color", iconColor) 40 | this.utils.show(notification) 41 | if (last > 0) { 42 | this.timer = setTimeout(() => this.hide(), last) 43 | } 44 | } 45 | } 46 | 47 | module.exports = { 48 | notification 49 | } 50 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/polyfill.js: -------------------------------------------------------------------------------- 1 | class polyfill { 2 | constructor(utils) { 3 | this.utils = utils; 4 | } 5 | 6 | process = () => { 7 | this.array() 8 | this.object() 9 | } 10 | 11 | array = () => { 12 | if (!Array.prototype.at) { 13 | Array.prototype.at = function (index) { 14 | const len = this.length 15 | if (index < 0) { 16 | index = len + index 17 | } 18 | if (index >= len || index < 0) { 19 | return undefined 20 | } 21 | return this[index] 22 | } 23 | } 24 | } 25 | 26 | object = () => { 27 | // try not to use it 28 | if (this.utils.isBetaVersion) { 29 | Object.defineProperty(Object.prototype, "?.", { 30 | value: function (prop) { 31 | return this == null ? undefined : this[prop] 32 | }, 33 | writable: false, 34 | enumerable: false, 35 | configurable: true 36 | }) 37 | } 38 | } 39 | } 40 | 41 | module.exports = { 42 | polyfill 43 | } 44 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/progressBar.js: -------------------------------------------------------------------------------- 1 | class progressBar { 2 | constructor(utils) { 3 | this.utils = utils; 4 | this.progressBar = null; 5 | } 6 | 7 | process = async () => { 8 | await this.utils.styleTemplater.register("plugin-common-progress-bar"); 9 | this.utils.insertElement(``); 10 | this.progressBar = document.querySelector(".plugin-common-progress-bar"); 11 | } 12 | 13 | progress = percent => this.progressBar.value = percent; 14 | 15 | done = () => this.progressBar.value = 0; 16 | 17 | animateTo100 = (interval = 50) => new Promise(resolve => { 18 | let val = this.progressBar.value; 19 | const timer = setInterval(() => { 20 | val += 10; 21 | this.progress(val); 22 | if (val >= 100) { 23 | clearInterval(timer); 24 | resolve(); 25 | } 26 | }, interval); 27 | }) 28 | 29 | fake = ({ timeout, isDone = this._timeout(), strategy = this._fade, animateTo100 = true, interval = 50 }) => new Promise(resolve => { 30 | let timer; 31 | const start = new Date().getTime(); 32 | const end = start + timeout; 33 | const _stop = async ok => { 34 | if (ok && animateTo100) { 35 | await this.animateTo100(); 36 | } 37 | this.done(); 38 | clearInterval(timer); 39 | resolve(ok); 40 | } 41 | timer = setInterval(() => { 42 | const now = new Date().getTime(); 43 | if (isDone() === true) { 44 | _stop(true); 45 | } else if (now > end) { 46 | _stop(false); 47 | } else { 48 | const percent = strategy(start, end, now, timeout); 49 | this.progress(percent); 50 | } 51 | }, interval) 52 | }) 53 | 54 | _timeout = (timeout = 30 * 1000) => { 55 | const start = new Date().getTime(); 56 | return () => new Date().getTime() - start > timeout; 57 | } 58 | 59 | _linear = (start, end, now, timeout) => Math.min((now - start) * 100 / timeout, 99) 60 | _fade = (start, end, now, timeout) => { 61 | const power = 5; // 1 - e^(-5) = 0.99326 62 | return (1 - Math.exp((-power * (now - start)) / timeout)) * 100 63 | } 64 | } 65 | 66 | module.exports = { 67 | progressBar 68 | } 69 | -------------------------------------------------------------------------------- /resources/plugin/global/core/utils/mixin/styleTemplater.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dynamically register CSS files. 3 | */ 4 | class styleTemplater { 5 | constructor(utils) { 6 | this.utils = utils; 7 | } 8 | 9 | getID = name => `plugin-${name}-style` 10 | 11 | register = async (name, args) => { 12 | const files = ["user_styles", "styles"].map(dir => this.utils.joinPath("./plugin/global", dir, name + ".css")); 13 | const [userStyles, defaultStyles] = await this.utils.readFiles(files); 14 | const data = userStyles || defaultStyles; 15 | if (data === "") return; 16 | if (data === undefined) { 17 | console.error(`there is not such style file: ${name}`); 18 | return; 19 | } 20 | try { 21 | const css = data.replace(/\${(.+?)}/g, (_, $arg) => $arg.split(".").reduce((obj, attr) => obj[attr], args)); 22 | this.utils.insertStyle(this.getID(name), css); 23 | } catch (err) { 24 | console.error(`replace args error. file: ${name}. err: ${err}`); 25 | } 26 | } 27 | 28 | unregister = name => this.utils.removeStyle(this.getID(name)); 29 | 30 | reset = async (name, args) => { 31 | this.unregister(name) 32 | await this.register(name, args) 33 | } 34 | 35 | getStyleContent = name => { 36 | const style = document.getElementById(this.getID(name)); 37 | return style ? style.innerHTML : undefined; 38 | } 39 | } 40 | 41 | module.exports = { 42 | styleTemplater 43 | } 44 | -------------------------------------------------------------------------------- /resources/plugin/global/settings/README.md: -------------------------------------------------------------------------------- 1 | ## \*.default.toml 和 \*.user.toml 的区别 2 | 3 | - `*.default.toml`:默认配置文件,请勿修改。 4 | - `*.user.toml`:用户配置文件,优先级高于 `default.toml`。 5 | 6 | 插件系统会优先从 `user.toml` 获取配置项,如果 `user.toml` 没有对应的配置项,则从 `default.toml` 获取。 7 | 8 | **设计原因**:区分用户配置和默认配置。在插件升级迭代过程中,`default.toml` 会被不断修改,而 `user.toml` 会被保留和尊重。这确保了插件升级时用户的自定义配置不会被覆盖。 9 | 10 | 11 | 12 | ## settings.\*.toml 和 custom_plugin.\*.toml 的区别 13 | 14 | - `custom_plugin.*.toml`:用户插件(二级插件)配置。所有 `常用插件→二级插件` 下的插件配置都在这里。 15 | - `settings.*.toml`:默认插件(一级插件)配置。其余所有插件的配置都在这里。 16 | 17 | 一级插件从 `settings.*.toml` 获取配置项,二级插件从 `custom_plugin.*.toml` 获取配置项。 18 | 19 | **设计原因**:区分用户插件和默认插件。插件系统提供开放能力,用户可以自行编写插件,这些插件的配置需要写在 `custom_plugin.user.toml` 中。 20 | 21 | 22 | 23 | ## 如何修改配置 24 | 25 | > 注意:配置选项区分大小写。 26 | 27 | 以修改只读模式的 `HOTKEY` 和 `READ_ONLY_DEFAULT` 配置为例: 28 | 29 | 1. 打开 `settings.default.toml`,找到需要修改的插件配置(如 `read_only`),内容如下: 30 | 31 | ```toml 32 | [read_only] 33 | # 启用插件 34 | ENABLE = true 35 | # 插件名称 36 | NAME = "只读模式" 37 | # 进入和脱离只读模式的快捷键 38 | HOTKEY = "ctrl+shift+r" 39 | # 默认使用只读模式(打开Typora就进入只读模式) 40 | READ_ONLY_DEFAULT = false 41 | # 开启只读模式后,右下角数字统计区域出现的提示文字 42 | SHOW_TEXT = "ReadOnly" 43 | ``` 44 | 45 | 2. 打开 `settings.user.toml`,添加如下内容: 46 | 47 | ```toml 48 | [read_only] 49 | HOTKEY = "ctrl+alt+shift+r" # 快捷键修改为 ctrl+alt+shift+r 50 | READ_ONLY_DEFAULT = true # 启动 Typora 时自动进入只读模式 51 | ``` 52 | 53 | 3. 保存并重启 Typora。这样一来,`settings.user.toml` 里的 `HOTKEY` 和 `READ_ONLY_DEFAULT` 选项就会覆盖掉 `settings.default.toml`,并且 **其他选项保持不变**。 54 | 55 | 56 | 57 | ## 配置示例 58 | 59 | 以下是个人的配置文件,供参考: 60 | 61 | ### settings.user.toml 62 | 63 | ```toml 64 | [auto_number] 65 | ENABLE_TABLE = false 66 | ENABLE_IMAGE = false 67 | ENABLE_FENCE = false 68 | 69 | [fence_enhance] 70 | REMOVE_BUTTON_HINT = true 71 | 72 | [window_tab] 73 | NEW_TAB_AT = "end" 74 | WHEN_CLOSE_LAST_TAB = "blankPage" 75 | 76 | [toolbar] 77 | DEFAULT_TOOL = "plu" 78 | 79 | [ripgrep] 80 | HOTKEY = "ctrl+alt+j" 81 | 82 | [collapse_table] 83 | ENABLE = false 84 | ``` 85 | 86 | 87 | 88 | ### custom_plugin.user.toml 89 | 90 | ```toml 91 | [reopenClosedFiles] 92 | hide = true 93 | auto_reopen_when_init = true 94 | 95 | [chineseSymbolAutoPairer] 96 | auto_swap = true 97 | ``` 98 | 99 | 100 | 101 | ## TOML 教程 102 | 103 | - 如果不熟悉 TOML 格式,可以花三分钟 [学习](https://toml.io/cn/v1.0.0)。 104 | - 如果配置文件的内容存在格式错误,将无法被正确读取。请前往 [格式校验网站](https://www.bejson.com/validators/toml_editor/) 检查。 105 | 106 | 107 | 108 | ## 隔离配置文件 109 | 110 | 如果希望隔离配置文件,可以将 `user.toml` 文件存放于 `~/.config/typora_plugin/` 目录下。此方法适用于 Linux、Windows 平台。 111 | 112 | ```bash 113 | $ dir /b /s "C:\Users\用户名\.config\typora_plugin" 114 | 115 | C:\Users\用户名\.config\typora_plugin\custom_plugin.user.toml 116 | C:\Users\用户名\.config\typora_plugin\settings.user.toml 117 | ``` 118 | 119 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/blockSideBySide.css: -------------------------------------------------------------------------------- 1 | /* Math display side-by-side */ 2 | .mathjax-block.md-rawblock-on-edit .md-rawblock-tooltip { 3 | right: -10%; 4 | } 5 | 6 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel { 7 | display: grid; 8 | grid-template-columns: 55% 45%; /* edit for proportions between code and rendering*/ 9 | grid-template-rows: auto auto auto; 10 | margin: 0 -10%; /* edit this value to enlarge the math edition width */ 11 | background-color: var(--rawblock-edit-panel-bd); /* edition panel background color */ 12 | } 13 | 14 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel .md-rawblock-before { 15 | grid-row-start: 1; 16 | overflow-x: scroll; 17 | } 18 | 19 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel .md-rawblock-input { 20 | grid-column-start: 1; 21 | grid-row-start: 2; 22 | border-right: 1px solid var(--text-color); /* vertical separation bar color */ 23 | } 24 | 25 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel .md-rawblock-after { 26 | grid-row-start: 3; 27 | overflow-x: scroll; 28 | } 29 | 30 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel .code-tooltip { 31 | grid-column-start: 2; 32 | grid-row-start: 2; 33 | display: grid; 34 | box-shadow: none; 35 | align-items: center; 36 | margin: 0 10px; 37 | overflow-x: scroll; 38 | overflow-y: hidden; 39 | border: none; 40 | background-color: var(--rawblock-edit-panel-bd); /* edition panel background color */ 41 | } 42 | 43 | .mathjax-block.md-rawblock-on-edit .md-rawblock-panel .code-tooltip .mathjax-candidate { 44 | overflow: unset; 45 | } 46 | 47 | .md-fences.md-diagram.md-focus { 48 | display: flex; 49 | background-color: var(--bg-color-1); 50 | box-shadow: none; 51 | border-radius: unset; 52 | margin: 0 -10% !important; 53 | padding: unset !important; 54 | } 55 | 56 | .md-fences.md-diagram.md-focus .CodeMirror { 57 | width: 45%; 58 | background-color: var(--rawblock-edit-panel-bd); 59 | } 60 | 61 | .md-fences.md-diagram.md-focus .md-diagram-panel { 62 | position: unset; 63 | width: 55%; 64 | } 65 | 66 | .md-fences.md-diagram.md-focus .CodeMirror .CodeMirror-scroll { 67 | margin-top: 6px; 68 | } 69 | 70 | .md-fences.md-diagram.md-focus .code-tooltip, 71 | .md-fences.md-diagram.md-focus .fence-enhance { 72 | right: 55% !important; 73 | } 74 | 75 | /* TODO side by side only when sufficient width @media */ -------------------------------------------------------------------------------- /resources/plugin/global/styles/callouts.css: -------------------------------------------------------------------------------- 1 | .plugin-callout { 2 | background-color: var(--callout-bg-color); 3 | border-left: 4px solid var(--callout-left-line-color); 4 | padding: 10px 10px 10px 15px; 5 | box-shadow: ${this.config.box_shadow}; 6 | overflow: hidden; 7 | } 8 | 9 | .plugin-callout[callout-type] { 10 | --callout-bg-color: ${this.config.default_background_color}; 11 | --callout-left-line-color: ${this.config.default_left_line_color}; 12 | --callout-icon: "${this.config.default_icon}"; 13 | } 14 | 15 | .plugin-callout > p:first-child { 16 | margin: -10px -10px -10px -15px; 17 | padding: 10px 10px 10px 15px; 18 | letter-spacing: 1px; 19 | } 20 | 21 | .plugin-callout > p:first-child::before { 22 | font-family: ${this.config.font_family}; 23 | content: var(--callout-icon); 24 | margin-right: 0.5em; 25 | } 26 | 27 | /* 默认显示 type */ 28 | .plugin-callout > p:first-child > span:first-child { 29 | font-weight: bold; 30 | font-size: 0; 31 | } 32 | 33 | .plugin-callout > p:first-child > span:first-child::after { 34 | content: attr(data-type); 35 | font-size: initial; 36 | } 37 | 38 | /* 光标移动到标题行,即获得焦点时,显示原始的 [!type] */ 39 | .plugin-callout > p:first-child > span:first-child:focus, 40 | .plugin-callout > p:first-child > span:first-child:focus-within, 41 | .plugin-callout > p:first-child.md-focus > span:first-child { 42 | font-size: initial; 43 | } 44 | 45 | .plugin-callout > p:first-child > span:first-child:focus::after, 46 | .plugin-callout > p:first-child > span:first-child:focus-within::after, 47 | .plugin-callout > p:first-child.md-focus > span:first-child::after { 48 | content: none; 49 | } 50 | 51 | .callout-folded > p:first-child :not(:first-child) { display: none; } 52 | .callout-folded > p:not(:first-child) { display: none; } 53 | 54 | .callout-folded:has(.md-focus) :not(:first-child):not(.md-softbreak) { display: inherit !important; } 55 | ${hover} 56 | ${color} 57 | ${callouts} 58 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/chat.css: -------------------------------------------------------------------------------- 1 | .plugin-chat { 2 | background-color: #ebebeb; 3 | overflow: hidden; 4 | color: #000; 5 | } 6 | 7 | .plugin-chat-content { 8 | width: 100%; 9 | padding: 25px; 10 | } 11 | 12 | .plugin-chat-content > :last-child { 13 | margin-bottom: 0; 14 | } 15 | 16 | .plugin-chat-time { 17 | margin-bottom: 1.2em; 18 | font-size: 0.9em; 19 | color: #888; 20 | white-space: break-spaces; 21 | word-wrap: break-word; 22 | } 23 | 24 | 25 | .plugin-chat-receive, 26 | .plugin-chat-send { 27 | display: flex; 28 | margin-bottom: 1.2em; 29 | } 30 | 31 | .plugin-chat-send { 32 | flex-direction: row-reverse; 33 | } 34 | 35 | 36 | .plugin-chat-avatar { 37 | width: 3em !important; 38 | height: 3em !important; 39 | border: 0; 40 | border-radius: 5px; 41 | background: #fff; 42 | margin-right: 10px; 43 | } 44 | 45 | .plugin-chat-send .plugin-chat-avatar { 46 | margin-left: 10px; 47 | margin-right: 0; 48 | } 49 | 50 | .plugin-chat-avatar .avatar-font { 51 | display: flex; 52 | justify-content: center; 53 | align-items: center; 54 | width: 100%; 55 | height: 100%; 56 | font-size: 1.5em; 57 | line-height: 1; 58 | } 59 | 60 | 61 | .plugin-chat-quote { 62 | text-align: initial; 63 | max-width: 60%; 64 | } 65 | 66 | .plugin-chat-nickname { 67 | font-size: 0.85em; 68 | margin-bottom: 0.1em; 69 | overflow: hidden; 70 | text-overflow: ellipsis; 71 | color: #888; 72 | } 73 | 74 | 75 | .plugin-chat-text { 76 | width: fit-content; 77 | max-width: 100%; 78 | font-size: 1.2em; 79 | background: #fff; 80 | border-radius: 5px; 81 | padding: 0.5em 0.8em; 82 | white-space: break-spaces; 83 | word-wrap: break-word; 84 | position: relative; 85 | } 86 | 87 | .plugin-chat-send .plugin-chat-text { 88 | background: #95ec69; 89 | } 90 | 91 | .plugin-chat-text::after { 92 | content: ""; 93 | top: 0.8em; 94 | position: absolute; 95 | border-top-width: 7px; 96 | border-top-style: solid; 97 | border-left: 5px solid transparent; 98 | border-right: 5px solid transparent; 99 | } 100 | 101 | .plugin-chat-receive .plugin-chat-text::after { 102 | left: -0.45em; 103 | border-top-color: #fff; 104 | transform: rotate(90deg) translateX(50%); 105 | } 106 | 107 | .plugin-chat-send .plugin-chat-text::after { 108 | right: -0.45em; 109 | border-top-color: #95ec69; 110 | transform: rotate(-90deg) translateX(-50%); 111 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/collapse_list.css: -------------------------------------------------------------------------------- 1 | #write .ul-list, 2 | #write .ol-list { 3 | position: relative !important; 4 | } 5 | 6 | #write .ul-list:before, 7 | #write .ol-list:before { 8 | position: absolute; 9 | content: ""; 10 | top: ${this.triangleStyle.top}px; 11 | left: ${this.triangleStyle.left}px; 12 | border-left: ${this.triangleStyle.halfWidth}px solid transparent; 13 | border-right: ${this.triangleStyle.halfWidth}px solid transparent; 14 | border-top: ${this.triangleStyle.height}px solid ${this.triangleStyle.color}; 15 | transition: transform .1s ease-in-out; 16 | cursor: pointer; 17 | } 18 | 19 | #write .${this.className}:before { 20 | transform: rotate(-90deg); 21 | } 22 | 23 | #write .${this.className} > li:nth-child(n+2) { 24 | display: none !important; 25 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/collapse_paragraph.css: -------------------------------------------------------------------------------- 1 | #write .plugin-collapsed-paragraph::after { 2 | display: initial; 3 | content: "{\2026}" !important; 4 | margin: 0 0.6rem; 5 | padding: 0 1px; 6 | color: white; 7 | opacity: 0.6; 8 | background-color: gray; 9 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/collapse_table.css: -------------------------------------------------------------------------------- 1 | .plugin-collapse-table tbody { 2 | display: none !important; 3 | } 4 | 5 | .plugin-collapse-table thead { 6 | border: 1px solid #f22f27 !important; 7 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/commander.css: -------------------------------------------------------------------------------- 1 | #plugin-commander { 2 | top: 30%; 3 | left: 50%; 4 | width: 600px; 5 | } 6 | 7 | #plugin-commander-form { 8 | display: flex; 9 | align-items: center; 10 | font-size: 14px; 11 | line-height: 25px; 12 | } 13 | 14 | #plugin-commander-form select, 15 | #plugin-commander-form input { 16 | border: 1px solid #ddd; 17 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); 18 | border-radius: 2px; 19 | height: 28px; 20 | margin: 1px 0; 21 | } 22 | 23 | #plugin-commander-form input { 24 | flex-basis: 60%; 25 | margin-right: 2px; 26 | padding-left: 5px; 27 | padding-right: 24px; 28 | } 29 | 30 | #plugin-commander-form select { 31 | flex-basis: 20%; 32 | margin-left: 2px; 33 | padding: 1px 2px; 34 | } 35 | 36 | #plugin-commander-form .plugin-commander-commit { 37 | position: absolute; 38 | padding: 1px; 39 | left: 336px; 40 | opacity: 0.7; 41 | cursor: pointer; 42 | } 43 | 44 | .plugin-commander-output { 45 | margin-top: 0; 46 | cursor: default; 47 | max-height: 340px; 48 | overflow: auto; 49 | } 50 | 51 | .plugin-commander-output pre { 52 | display: inline-block; 53 | font-size: 13px; 54 | line-height: 1.2; 55 | margin: 0; 56 | padding: 5px; 57 | } 58 | 59 | .plugin-commander-output pre.error { 60 | color: red; 61 | } 62 | 63 | #plugin-commander-form input:focus, 64 | #plugin-commander-form pre:focus { 65 | outline: 0 66 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/customize.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/global/styles/customize.css -------------------------------------------------------------------------------- /resources/plugin/global/styles/dark.css: -------------------------------------------------------------------------------- 1 | .plugin-dark { 2 | filter: invert(.9) hue-rotate(.5turn); 3 | } 4 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/datatables.css: -------------------------------------------------------------------------------- 1 | #write figure select, 2 | #write figure input { 3 | border: 1px solid #ddd; 4 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); 5 | border-radius: 2px; 6 | height: 27px; 7 | margin-top: 5px; 8 | margin-bottom: 1px; 9 | max-width: 10em; 10 | } 11 | 12 | .dataTables_wrapper .dataTables_paginate .paginate_button { 13 | padding: 0.05em 0.1em; 14 | } 15 | 16 | .dataTables_wrapper .dataTables_length, .dataTables_filter { 17 | margin-bottom: 0.25em; 18 | } 19 | 20 | .dataTables_wrapper .dataTables_info { 21 | padding-top: 0.25em; 22 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/drawIO.css: -------------------------------------------------------------------------------- 1 | #write .plugin-drawio-content, 2 | .geDiagramContainer svg { 3 | line-height: initial; 4 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/fence_enhance.css: -------------------------------------------------------------------------------- 1 | #write .fence-enhance { 2 | display: inline-flex; 3 | flex-direction: row-reverse; 4 | position: absolute; 5 | z-index: 8; 6 | top: ${this.config.BUTTON_TOP}; 7 | right: ${this.config.BUTTON_RIGHT}; 8 | font-size: ${this.config.BUTTON_SIZE}; 9 | color: ${this.config.BUTTON_COLOR}; 10 | } 11 | 12 | .fence-enhance .enhance-btn { 13 | opacity: ${this.config.BUTTON_OPACITY}; 14 | cursor: pointer; 15 | margin-left: ${this.config.BUTTON_MARGIN}; 16 | } 17 | 18 | .fence-enhance .enhance-btn:last-child { 19 | margin-left: 0; 20 | } 21 | 22 | .fence-enhance .enhance-btn:hover { 23 | opacity: ${this.config.BUTTON_OPACITY_HOVER}; 24 | } 25 | 26 | .CodeMirror-line:hover { 27 | background-color: ${bgColorWhenHover}; 28 | } 29 | 30 | .plugin-fence-enhance-highlight { 31 | background-color: ${this.config.HIGHLIGHT_LINE_COLOR} !important; 32 | } 33 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/file_counter.css: -------------------------------------------------------------------------------- 1 | .plugin-file-counter { 2 | float: right; 3 | overflow-x: visible; 4 | overflow-y: hidden; 5 | margin-right: 10px; 6 | padding: 0 3px; 7 | border-radius: 3px; 8 | background: ${background_color}; 9 | color: ${color}; 10 | font-weight: ${font_weight}; 11 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/kanban.css: -------------------------------------------------------------------------------- 1 | .plugin-kanban { 2 | font-family: sans-serif; 3 | } 4 | 5 | .plugin-kanban .plugin-kanban-title { 6 | font-size: 1.5rem; 7 | font-weight: bold; 8 | } 9 | 10 | .plugin-kanban .plugin-kanban-content { 11 | display: flex; 12 | overflow-x: auto; 13 | flex-wrap: ${wrap}; 14 | } 15 | 16 | .plugin-kanban-content .no-wrap-title { 17 | overflow: hidden; 18 | white-space: nowrap; 19 | text-overflow: ellipsis; 20 | text-align: left; 21 | padding-left: 4px; 22 | } 23 | 24 | .plugin-kanban-content .kanban-box { 25 | border-radius: 4px; 26 | box-shadow: 0 2px 4px -1px rgba(0,0,0,0.2), 0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12); 27 | } 28 | 29 | .plugin-kanban-content .kanban-item-box { 30 | border-radius: 4px; 31 | box-shadow: 0 2px 1px -1px rgba(0,0,0,0.2), 0 1px 1px 0 rgba(0,0,0,0.14), 0 1px 3px 0 rgba(0,0,0,0.12); 32 | } 33 | 34 | .plugin-kanban-content .plugin-kanban-col { 35 | width: ${kanbanWidth} !important; 36 | margin: 8px; 37 | } 38 | 39 | .plugin-kanban-col p { 40 | margin: 4px; 41 | } 42 | 43 | .plugin-kanban-content .plugin-kanban-col-item-list { 44 | display: flex; 45 | flex-direction: column; 46 | overflow-y: overlay; 47 | padding: 0 4px 4px 4px; 48 | max-height: ${maxHeight}; 49 | } 50 | 51 | .plugin-kanban-content .plugin-kanban-col-name { 52 | font-size: 1rem; 53 | font-weight: bold; 54 | border-color: rgba(0, 0, 0, 0.08); 55 | border-bottom-style: solid; 56 | border-width: 1px; 57 | padding: 8px 8px 4px 10px; 58 | } 59 | 60 | .plugin-kanban-content .plugin-kanban-col-item { 61 | margin: 4px; 62 | padding: 8px; 63 | } 64 | 65 | .plugin-kanban-content .plugin-kanban-col-item-desc { 66 | overflow: hidden; 67 | margin-top: 5px; 68 | height: ${taskDescMaxHeight}; 69 | padding-left: 4px; 70 | text-align: left; 71 | white-space: break-spaces; 72 | word-wrap: break-word; 73 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/markdownLint.css: -------------------------------------------------------------------------------- 1 | #plugin-markdownlint { 2 | display: flex; 3 | flex-direction: column; 4 | top: 10%; 5 | right: 25px; 6 | margin: 5px; 7 | overflow: auto; 8 | resize: vertical; 9 | line-height: ${this.config.modal_line_height}; 10 | width: ${modal_width}; 11 | min-width: 380px; 12 | max-height: ${this.config.modal_max_height}; 13 | min-height: 150px; 14 | z-index: 9993; 15 | } 16 | 17 | .plugin-markdownlint-icon-group { 18 | display: flex; 19 | flex-direction: row-reverse; 20 | font-size: 1.3em; 21 | margin: 0.3em; 22 | user-select: none; 23 | } 24 | 25 | .plugin-markdownlint-icon-group .plugin-markdownlint-icon { 26 | cursor: pointer; 27 | margin-left: 0.6em; 28 | opacity: 0.6; 29 | } 30 | 31 | .plugin-markdownlint-icon:hover { 32 | opacity: 1; 33 | transform: translateY(-2px) scale(1.2); 34 | } 35 | 36 | .plugin-markdownlint-table { 37 | overflow: auto; 38 | } 39 | 40 | #plugin-markdownlint table { 41 | cursor: default; 42 | margin-top: 0; 43 | font-size: ${this.config.modal_font_size}; 44 | } 45 | 46 | #plugin-markdownlint table th, 47 | #plugin-markdownlint table td[colspan], 48 | #plugin-markdownlint table td:nth-child(4) { 49 | text-align: center; 50 | } 51 | 52 | #plugin-markdownlint i:hover { 53 | color: var(--active-file-border-color, darkred); 54 | cursor: pointer; 55 | } 56 | 57 | #plugin-markdownlint i + i { 58 | margin-left: 0.7em; 59 | } 60 | 61 | #plugin-markdownlint-button { 62 | position: fixed; 63 | right: 9px; 64 | width: ${this.config.button_width}; 65 | height: ${this.config.button_height}; 66 | background-color: ${this.config.pass_color}; 67 | cursor: pointer; 68 | transition: background-color 0.1s ease 0s; 69 | z-index: 9992; 70 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/markmap.css: -------------------------------------------------------------------------------- 1 | .md-diagram-panel .plugin-fence-markmap-svg { 2 | line-height: initial !important; 3 | user-select: none; 4 | } 5 | 6 | .plugin-fence-markmap-svg table { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | #plugin-markmap { 12 | transition: all 0.8s ease 0s; 13 | user-select: none; 14 | pointer-events: auto; 15 | min-width: 120px; 16 | min-height: 120px; 17 | } 18 | 19 | #plugin-markmap.noBoxShadow { 20 | box-shadow: none; 21 | } 22 | 23 | #plugin-markmap.penetrateMouse { 24 | pointer-events: none; 25 | background: none; 26 | backdrop-filter: blur(15px); 27 | } 28 | 29 | .plugin-markmap-wrap { 30 | display: flex; 31 | flex-direction: row; 32 | width: 100%; 33 | height: 100%; 34 | } 35 | 36 | .plugin-markmap-grip.grip-up { 37 | position: absolute; 38 | bottom: -5px; 39 | width: 100%; 40 | height: 10px; 41 | cursor: ns-resize; 42 | } 43 | 44 | .plugin-markmap-grip.grip-right { 45 | position: absolute; 46 | left: -5px; 47 | width: 10px; 48 | height: 100%; 49 | cursor: ew-resize; 50 | } 51 | 52 | #plugin-markmap-svg .markmap-node .markmap-foreign:hover { 53 | outline: ${this.config.BORDER_STYLE_WHEN_NODE_HOVER}; 54 | } 55 | 56 | #plugin-markmap-svg .markmap-node:hover { 57 | cursor: pointer; 58 | } 59 | 60 | .plugin-markmap-header { 61 | display: flex; 62 | flex-direction: column; 63 | flex-wrap: wrap; 64 | justify-content: flex-start; 65 | align-items: center; 66 | max-width: 2em; 67 | } 68 | 69 | .plugin-markmap-icon { 70 | cursor: pointer; 71 | font-size: 1.2em; 72 | opacity: 0.6; 73 | margin: 0 0.4em; 74 | pointer-events: auto; 75 | } 76 | 77 | .plugin-markmap-icon:not([action="resize"]):hover { 78 | opacity: 1; 79 | transform: translateY(-2px) scale(1.2); 80 | } 81 | 82 | #plugin-markmap.penetrateMouse .plugin-markmap-icon[action="penetrateMouse"] { 83 | opacity: 1; 84 | color: rgb(194, 24, 91); 85 | } 86 | 87 | .plugin-markmap-icon[action="resize"] { 88 | position: absolute; 89 | display: flex; 90 | bottom: 0.2em; 91 | right: 0.2em; 92 | margin: 0; 93 | cursor: nwse-resize; 94 | font-size: 1.1em; 95 | } 96 | 97 | .plugin-markmap-icon[action="resize"] svg { 98 | fill: currentColor; 99 | height: 1.1em; 100 | width: 1.1em; 101 | } 102 | 103 | #plugin-markmap-svg { 104 | flex: 1; 105 | user-select: none; 106 | color: currentColor; 107 | } 108 | 109 | #plugin-markmap-svg .markmap-foreign { 110 | line-height: 20px; 111 | } 112 | 113 | .plugin-markmap-color-scheme { 114 | display: inline-flex; 115 | position: absolute; 116 | height: 20px; 117 | max-width: calc(var(--markmap-color-width) * 14); 118 | --markmap-color-width: 32px; 119 | } 120 | 121 | .plugin-markmap-color { 122 | width: var(--markmap-color-width); 123 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/marp.css: -------------------------------------------------------------------------------- 1 | #write .plugin-marp-content { 2 | all: initial; 3 | } 4 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/no_image.css: -------------------------------------------------------------------------------- 1 | #write .md-htmlblock-container img, 2 | #write .md-image { 3 | opacity: 0; 4 | transition: opacity ${transition_duration}ms ease ${transition_delay}ms; 5 | } 6 | 7 | #write .md-htmlblock-container img:hover, 8 | #write .md-image:hover { 9 | opacity: ${opacity_on_hover}; 10 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/pie_menu.css: -------------------------------------------------------------------------------- 1 | .plugin-pie-menu { 2 | position: fixed; 3 | left: 50vw; 4 | top: 50vh; 5 | width: var(--menu-circle-size); 6 | height: var(--menu-circle-size); 7 | transform: rotate(var(--menu-rotate)); 8 | z-index: 9998; 9 | cursor: pointer; 10 | transition: transform 0.15s; 11 | user-select: none; 12 | 13 | --menu-rotate: 0deg; 14 | --menu-circle-size: 56px; 15 | --menu-inner-size: 205px; 16 | --menu-outer-size: 310px; 17 | --menu-icon-size: 34px; 18 | --menu-item-radius: 165px; 19 | --menu-background-color: #fafafa; 20 | --menu-background-zebra-color: #f3f2ee; 21 | --menu-border-color: #ccc; 22 | --menu-hover-color: #ccc; 23 | --menu-icon-color: #999; 24 | } 25 | 26 | .plugin-pie-menu-circle { 27 | position: absolute; 28 | width: var(--menu-circle-size); 29 | height: var(--menu-circle-size); 30 | border-width: 2px; 31 | border-style: dashed; 32 | border-color: var(--menu-border-color); 33 | border-radius: 50%; 34 | background-color: var(--menu-background-color); 35 | transition: all 0.15s; 36 | } 37 | 38 | .plugin-pie-menu-inner { 39 | z-index: 1; 40 | } 41 | 42 | .plugin-pie-menu-solid { 43 | z-index: 2; 44 | } 45 | 46 | .plugin-pie-menu-inner, 47 | .plugin-pie-menu-outer { 48 | top: 50%; 49 | left: 50%; 50 | transform: translate(-50%, -50%); 51 | overflow: hidden; 52 | } 53 | 54 | .plugin-pie-menu.pin-menu .plugin-pie-menu-solid { 55 | background-color: var(--menu-border-color); 56 | } 57 | 58 | .plugin-pie-menu.expand-menu > .plugin-pie-menu-circle { 59 | border-style: solid; 60 | } 61 | 62 | .plugin-pie-menu.expand-menu .plugin-pie-menu-inner, 63 | .plugin-pie-menu:hover .plugin-pie-menu-inner { 64 | width: var(--menu-inner-size); 65 | height: var(--menu-inner-size); 66 | } 67 | 68 | .plugin-pie-menu.expand-menu .plugin-pie-menu-outer, 69 | .plugin-pie-menu:hover .plugin-pie-menu-outer { 70 | width: var(--menu-outer-size); 71 | height: var(--menu-outer-size); 72 | } 73 | 74 | .plugin-pie-menu-item { 75 | width: var(--menu-item-radius); 76 | height: var(--menu-item-radius); 77 | border: 1px solid var(--menu-border-color); 78 | display: flex; 79 | justify-content: flex-end; 80 | position: absolute; 81 | left: 50%; 82 | top: 50%; 83 | transform-origin: bottom right; 84 | transform: translate(-100%, -100%) rotate(var(--menu-item-rotate)) skew(30deg, 15deg); 85 | } 86 | 87 | .plugin-pie-menu .plugin-pie-menu-item:hover { 88 | background-color: var(--menu-hover-color); 89 | } 90 | 91 | .plugin-pie-menu-item:nth-child(even) { 92 | background-color: var(--menu-background-zebra-color); 93 | } 94 | 95 | .plugin-pie-menu-item:nth-child(1) { 96 | --menu-item-rotate: 75deg; 97 | } 98 | 99 | .plugin-pie-menu-item:nth-child(2) { 100 | --menu-item-rotate: 120deg; 101 | } 102 | 103 | .plugin-pie-menu-item:nth-child(3) { 104 | --menu-item-rotate: 165deg; 105 | } 106 | 107 | .plugin-pie-menu-item:nth-child(4) { 108 | --menu-item-rotate: 210deg; 109 | } 110 | 111 | .plugin-pie-menu-item:nth-child(5) { 112 | --menu-item-rotate: 255deg; 113 | } 114 | 115 | .plugin-pie-menu-item:nth-child(6) { 116 | --menu-item-rotate: 300deg; 117 | } 118 | 119 | .plugin-pie-menu-item:nth-child(7) { 120 | --menu-item-rotate: 345deg; 121 | } 122 | 123 | .plugin-pie-menu-item:nth-child(8) { 124 | --menu-item-rotate: 390deg; 125 | } 126 | 127 | .plugin-pie-menu-item-text-inner, 128 | .plugin-pie-menu-item-text-outer { 129 | display: flex; 130 | justify-content: center; 131 | width: 0; 132 | font-size: var(--menu-icon-size); 133 | transform-origin: bottom right; 134 | transform: skew(-30deg, -15deg) rotate(-50deg); 135 | color: var(--menu-icon-color); 136 | } 137 | 138 | .plugin-pie-menu-item-text-inner { 139 | align-items: center; 140 | } 141 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/plugin-common-menu.css: -------------------------------------------------------------------------------- 1 | .plugin-common-menu { 2 | display: none; 3 | position: fixed; 4 | z-index: 99999; 5 | font-size: .9rem; 6 | padding: 6px 0; 7 | line-height: 1.7; 8 | min-width: 150px; 9 | border-radius: 6px; 10 | background-color: var(--bg-color); 11 | box-shadow: rgba(15, 15, 15, .03) 0 0 0 1px, rgba(15, 15, 15, .04) 0 3px 6px, rgba(15, 15, 15, .05) 0 9px 24px; 12 | } 13 | 14 | .plugin-common-menu.show { 15 | display: block; 16 | } 17 | 18 | .plugin-common-menu .menu-item { 19 | padding: 0 10px; 20 | user-select: none; 21 | min-width: 124px; 22 | position: relative; 23 | } 24 | 25 | .plugin-common-menu .menu-item:hover { 26 | background-color: var(--item-hover-bg-color); 27 | } 28 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/plugin-common-notification.css: -------------------------------------------------------------------------------- 1 | .plugin-common-notification { 2 | position: fixed; 3 | top: 8%; 4 | left: 50%; 5 | transform: translate(-50%, -50%); 6 | min-width: 400px; 7 | max-width: 700px; 8 | padding: 15px 20px; 9 | color: rgb(51, 51, 51); 10 | box-shadow: rgba(0, 0, 0, 0.1) 0 2px 10px; 11 | border-radius: 2px; 12 | z-index: 9999; 13 | text-align: left; 14 | display: flex; 15 | align-items: baseline; 16 | background-color: var(--notification-bg-color); 17 | --notification-bg-color: "#e6f7ff"; 18 | --notification-icon-color: currentColor; 19 | } 20 | 21 | .plugin-common-notification .notification-icon { 22 | width: 16px; 23 | margin-right: 10px; 24 | color: var(--notification-icon-color); 25 | } 26 | 27 | .plugin-common-notification .notification-message { 28 | flex: 1 1 0; 29 | margin: 0; 30 | font-size: 16px; 31 | white-space: break-spaces; 32 | word-break: break-word; 33 | } 34 | 35 | .plugin-common-notification .notification-close-btn { 36 | background: none; 37 | border: none; 38 | font-size: 16px; 39 | color: rgb(136, 136, 136); 40 | cursor: pointer; 41 | margin-left: 10px; 42 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/plugin-common-progress-bar.css: -------------------------------------------------------------------------------- 1 | .plugin-common-progress-bar { 2 | position: fixed; 3 | left: 0; 4 | top: 0; 5 | z-index: 1000; 6 | width: 100%; 7 | height: 3px; 8 | border: none; 9 | background-color: transparent; 10 | color: #e91e63; 11 | } 12 | 13 | .plugin-common-progress-bar::-webkit-progress-bar { 14 | background-color: transparent; 15 | } 16 | 17 | .plugin-common-progress-bar::-webkit-progress-value { 18 | background-color: #e91e63; 19 | } 20 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/plugin-common.css: -------------------------------------------------------------------------------- 1 | .plugin-common-modal { 2 | position: fixed; 3 | z-index: 9999; 4 | padding: 4px; 5 | background-color: var(--side-bar-bg-color); 6 | box-shadow: 0 4px 10px rgba(0, 0, 0, .5); 7 | border-top: none; 8 | color: var(--text-color); 9 | border-radius: 4px; 10 | } 11 | 12 | .plugin-common-hidden { 13 | display: none !important; 14 | } 15 | 16 | .plugin-wait-mask-wrapper { 17 | z-index: 9999; 18 | position: fixed; 19 | width: 100px; 20 | height: 100px; 21 | border-radius: 2px; 22 | top: calc(50% - 50px); 23 | left: calc(50% - 50px); 24 | background-color: rgba(51,51,51,.62); 25 | } 26 | 27 | .plugin-wait-mask { 28 | width: 100px; 29 | height: 100px; 30 | text-align: center; 31 | background-color: transparent; 32 | display: block; 33 | border-radius: 4px; 34 | } 35 | 36 | .plugin-wait-mask .plugin-wait-label { 37 | display: block; 38 | color: #ddd; 39 | font-size: 14px; 40 | margin-top: 16px; 41 | margin-bottom: 12px; 42 | } 43 | 44 | .plugin-wait-mask .truncate-line { 45 | display: inline-block; 46 | width: 8px; 47 | height: 8px; 48 | margin-left: 2px; 49 | margin-right: 2px; 50 | background-color: #ccc; 51 | } 52 | 53 | .plugin-wait-mask .truncate-line:nth-last-child(1) { 54 | animation: loadingC .6s .1s linear infinite 55 | } 56 | 57 | .plugin-wait-mask .truncate-line:nth-last-child(2) { 58 | animation: loadingC .6s .2s linear infinite 59 | } 60 | 61 | .plugin-wait-mask .truncate-line:nth-last-child(3) { 62 | animation: loadingC .6s .3s linear infinite 63 | } 64 | 65 | .dropdown-menu { 66 | z-index: 9998; 67 | } 68 | 69 | #md-searchpanel.searchpanel-replace-mode { 70 | z-index: 99999 !important; 71 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/plugin-diagram-parser.css: -------------------------------------------------------------------------------- 1 | .md-fences-advanced:not(.md-focus) .CodeMirror { 2 | display: none; 3 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/quickButton.css: -------------------------------------------------------------------------------- 1 | .ty-footer { 2 | z-index: 9999 !important; 3 | } 4 | 5 | #plugin-quick-button { 6 | position: fixed; 7 | display: grid; 8 | z-index: 9991; 9 | font-size: 17px; 10 | text-align: center; 11 | grid-template-columns: repeat(${colCount}, 1fr); 12 | grid-template-rows: repeat(${rowCount}, 1fr); 13 | gap: ${this.config.button_gap}; 14 | right: ${this.config.position_right}; 15 | bottom: ${this.config.position_bottom}; 16 | color: var(--active-file-border-color); 17 | } 18 | 19 | #plugin-quick-button .action-item { 20 | cursor: pointer; 21 | transition: all 50ms ease-in 0s; 22 | width: ${this.config.button_size}; 23 | height: ${this.config.button_size}; 24 | line-height: ${this.config.button_size}; 25 | box-shadow: ${this.config.button_box_shadow}; 26 | border-radius: ${this.config.button_border_radius}; 27 | } 28 | 29 | #plugin-quick-button .action-item:hover { 30 | transform: translateY(-2px); 31 | box-shadow: 0 2px 10px 3px rgba(0, 0, 0, .15); 32 | } 33 | 34 | #plugin-quick-button .plu-hidden, 35 | #plugin-quick-button .plu-unused { 36 | visibility: hidden; 37 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/read_only.css: -------------------------------------------------------------------------------- 1 | #footer-word-count-label::before { 2 | content: attr(data-value) !important 3 | } 4 | 5 | .plu-disable-menu { 6 | color: rgb(196, 198, 204); 7 | pointer-events: none; 8 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/resize_table.css: -------------------------------------------------------------------------------- 1 | table.md-table td { 2 | min-width: 1px !important; 3 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/resourceOperation.css: -------------------------------------------------------------------------------- 1 | #plugin-resource-operation { 2 | display: flex; 3 | flex-direction: column; 4 | resize: both; 5 | overflow: auto; 6 | min-width: 120px; 7 | min-height: 120px; 8 | } 9 | 10 | #plugin-resource-operation .plugin-resource-operation-wrap { 11 | overflow: scroll; 12 | } 13 | 14 | #plugin-resource-operation .plugin-resource-operation-popup { 15 | max-width: 500px; 16 | max-height: 500px; 17 | position: fixed; 18 | box-shadow: 0 0 0.125em 0 rgba(0, 0, 0, .5); 19 | border-radius: 0.5em; 20 | background-color: var(--side-bar-bg-color); 21 | z-index: 9999; 22 | } 23 | 24 | .non-exist-in-file-table th:first-child { 25 | width: 10px; 26 | } 27 | .non-exist-in-file-table th:last-child { 28 | width: 150px; 29 | } 30 | .non-exist-in-file-table td:nth-of-type(2) { 31 | max-width: 200px; 32 | white-space: break-spaces; 33 | word-break: break-word; 34 | } 35 | .non-exist-in-file-table td:nth-of-type(3) { 36 | max-width: 100px; 37 | max-height: 100px; 38 | } 39 | .non-exist-in-file-table td:last-of-type { 40 | text-align: center; 41 | } 42 | 43 | #plugin-resource-operation tbody { 44 | font-size: 0.7em; 45 | } 46 | 47 | .plugin-resource-operation-message { 48 | font-size: 1.2em; 49 | margin-top: 1.2em; 50 | margin-left: 0.2em; 51 | padding-bottom: 2px; 52 | border-bottom: 1px solid #ececec; 53 | text-align: center; 54 | } 55 | 56 | #plugin-resource-operation textarea { 57 | width: 100%; 58 | margin-top: 10px; 59 | } 60 | 61 | #plugin-resource-operation .plugin-resource-operation-icon-group { 62 | display: flex; 63 | flex-direction: row-reverse; 64 | font-size: 1.2em; 65 | margin-right: 0.4em; 66 | } 67 | 68 | .plugin-resource-operation-icon-group .plugin-resource-operation-icon { 69 | cursor: pointer; 70 | margin-left: 0.4em; 71 | opacity: 0.6; 72 | } 73 | 74 | .plugin-resource-operation-icon:hover { 75 | opacity: 1; 76 | transform: translateY(-2px) scale(1.2); 77 | } 78 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/right_click_menu.css: -------------------------------------------------------------------------------- 1 | .plugin-menu-second.ext-context-menu, 2 | .plugin-menu-third.ext-context-menu { 3 | min-width: ${menu_min_width}; 4 | } 5 | 6 | #context-menu > li:not([data-key="typora-plugin"]) { 7 | display: ${menu_option_display}; 8 | } 9 | 10 | .ty-menu-shortcut { 11 | padding-left: 1em; 12 | } 13 | 14 | .context-menu .state-run:before { 15 | content: '\2318'; 16 | margin-left: -10px; 17 | margin-right: 10px; 18 | } 19 | 20 | /*.plugin-menu-second .state-off:before,*/ 21 | /*.plugin-menu-third .state-off:before {*/ 22 | /* content: '\2717' !important;*/ 23 | /* margin-left: -10px;*/ 24 | /* margin-right: 10px;*/ 25 | /*}*/ -------------------------------------------------------------------------------- /resources/plugin/global/styles/ripgrep.css: -------------------------------------------------------------------------------- 1 | #plugin-ripgrep { 2 | top: ${topPercent}; 3 | } 4 | 5 | .plugin-ripgrep-prefix { 6 | font-size: 1.4em; 7 | margin: 2px 6px; 8 | } 9 | 10 | #plugin-ripgrep-form { 11 | display: flex; 12 | align-items: center; 13 | font-size: 14px; 14 | line-height: 25px; 15 | } 16 | 17 | #plugin-ripgrep-form input { 18 | width: 100%; 19 | margin-left: 0; 20 | margin-right: 2px; 21 | padding-left: 5px; 22 | padding-right: 24px; 23 | } 24 | 25 | .plugin-ripgrep-output { 26 | margin-top: 0; 27 | cursor: default; 28 | max-height: 25em; 29 | overflow-y: auto; 30 | overflow-x: auto; 31 | } 32 | 33 | .plugin-ripgrep-output pre { 34 | display: inline-block; 35 | font-size: 13px; 36 | line-height: 1.1; 37 | margin: 10px 10px 5px 5px; 38 | } 39 | 40 | .plugin-ripgrep-output pre.error { 41 | color: red; 42 | } 43 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/scrollBookmarker.css: -------------------------------------------------------------------------------- 1 | #plugin-scroll-bookmarker { 2 | right: 25px; 3 | width: 300px; 4 | max-height: 500px; 5 | overflow-y: overlay; 6 | } 7 | 8 | .plugin-scroll-bookmarker-icon-group { 9 | display: flex; 10 | flex-direction: row-reverse; 11 | font-size: 1.3em; 12 | margin: 0 0.3em; 13 | user-select: none; 14 | } 15 | 16 | .plugin-scroll-bookmarker-icon-group .plugin-scroll-bookmarker-icon { 17 | cursor: pointer; 18 | margin-left: 0.6em; 19 | opacity: 0.6; 20 | } 21 | 22 | .plugin-scroll-bookmarker-icon:hover { 23 | opacity: 1; 24 | transform: translateY(-2px) scale(1.2); 25 | } 26 | 27 | #plugin-scroll-bookmarker .bookmark-item { 28 | display: flex; 29 | margin: 0.3rem; 30 | align-items: center; 31 | padding-left: 0.5em; 32 | border-radius: 5px; 33 | background-color: #f8f8f8; 34 | cursor: pointer; 35 | } 36 | 37 | #plugin-scroll-bookmarker .bookmark-item:hover { 38 | background-color: var(--item-hover-bg-color); 39 | } 40 | 41 | #plugin-scroll-bookmarker .bookmark-item-content { 42 | padding-right: 10px; 43 | /* word-wrap: break-word; */ 44 | /* flex-wrap: wrap; */ 45 | flex: 1; 46 | font-size: 15px; 47 | overflow-wrap: anywhere; 48 | } 49 | 50 | #plugin-scroll-bookmarker .bookmark-btn { 51 | font-size: 17px; 52 | cursor: pointer; 53 | padding: 4px; 54 | } 55 | 56 | #plugin-scroll-bookmarker .bookmark-btn:hover { 57 | color: #f70505; 58 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/slash_commands.css: -------------------------------------------------------------------------------- 1 | .auto-suggest-container li.plugin-slash-command { 2 | padding-left: 10px; 3 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/text_stylize.css: -------------------------------------------------------------------------------- 1 | #plugin-text-stylize { 2 | top: 10%; 3 | background-color: ${backgroundColor}; 4 | } 5 | 6 | #plugin-text-stylize .stylize-tool { 7 | display: flex; 8 | } 9 | 10 | #plugin-text-stylize .stylize-tool > [action] { 11 | fill: currentColor; 12 | cursor: pointer; 13 | width: 25px; 14 | height: 25px; 15 | opacity: 0.6; 16 | } 17 | 18 | #plugin-text-stylize .stylize-tool > [action].select { 19 | background: var(--active-file-bg-color); 20 | color: var(--active-file-text-color); 21 | opacity: 1; 22 | outline: 1px solid #32a1ce; 23 | } 24 | 25 | #plugin-text-stylize .stylize-palette { 26 | position: absolute; 27 | left: 0; 28 | top: 30px; 29 | margin-top: 10px; 30 | display: none; 31 | } 32 | 33 | #plugin-text-stylize .stylize-palette td { 34 | width: 30px; 35 | height: 17px; 36 | border: 1px #000 solid; 37 | cursor: pointer; 38 | } 39 | 40 | #plugin-text-stylize .stylize-palette td:hover { 41 | box-shadow: inset 0 0 0 2px #fff; 42 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/timeline.css: -------------------------------------------------------------------------------- 1 | .plugin-timeline { 2 | padding: 15px 40px 30px 40px; 3 | background-color: ${this.config.BACKGROUND_COLOR}; 4 | } 5 | 6 | .plugin-timeline .timeline-title { 7 | font-size: ${this.config.TITLE_FONT_SIZE}; 8 | font-weight: ${this.config.TITLE_FONT_WEIGHT}; 9 | color: ${this.config.TITLE_COLOR}; 10 | white-space: break-spaces; 11 | word-break: break-word; 12 | } 13 | 14 | .plugin-timeline .timeline-content { 15 | display: grid; 16 | grid-template-columns: ${this.config.LINE_WIDTH} calc(100% - ${this.config.LINE_WIDTH}); 17 | } 18 | 19 | .plugin-timeline .timeline-line { 20 | position: relative; 21 | background-color: ${this.config.LINE_COLOR}; 22 | } 23 | 24 | .plugin-timeline .timeline-circle { 25 | position: absolute; 26 | top: ${this.config.CIRCLE_TOP}; 27 | left: 50%; 28 | width: ${this.config.CIRCLE_DIAMETER} !important; 29 | height: ${this.config.CIRCLE_DIAMETER} !important; 30 | border-radius: 50%; 31 | background-color: ${this.config.CIRCLE_COLOR}; 32 | transform: translateX(-50%); 33 | } 34 | 35 | .plugin-timeline .timeline-wrapper { 36 | margin-left: 1em; 37 | text-align: left; 38 | } 39 | 40 | .plugin-timeline .timeline-time { 41 | font-size: large; 42 | font-weight: bold; 43 | white-space: break-spaces; 44 | word-break: break-word; 45 | color: ${this.config.TIME_COLOR}; 46 | } 47 | 48 | .plugin-timeline .timeline-event { 49 | margin-top: 1em; 50 | margin-bottom: 3em; 51 | white-space: break-spaces; 52 | word-break: break-word; 53 | } 54 | 55 | .plugin-timeline .timeline-wrapper:last-child .timeline-event { 56 | margin-bottom: 0; 57 | } 58 | 59 | .plugin-timeline .timeline-task-list { 60 | padding-left: 10px; 61 | } 62 | 63 | .plugin-timeline .timeline-task-list input { 64 | margin-right: .5em; 65 | } -------------------------------------------------------------------------------- /resources/plugin/global/styles/toc.css: -------------------------------------------------------------------------------- 1 | #plugin-toc { 2 | height: 95%; 3 | right: 0; 4 | box-shadow: initial; 5 | border-left: dashed 1px rgba(0, 0, 0, 0.2); 6 | z-index: 9990; 7 | } 8 | 9 | #plugin-toc .grip-right { 10 | position: absolute; 11 | left: -5px; 12 | width: 10px; 13 | height: 100%; 14 | cursor: ew-resize; 15 | } 16 | 17 | #plugin-toc .plugin-toc-wrap { 18 | width: 100%; 19 | height: 100%; 20 | } 21 | 22 | #plugin-toc .plugin-toc-header { 23 | display: inline-flex; 24 | width: 100%; 25 | padding-bottom: 0.25em; 26 | border-bottom: dashed 1px rgba(0, 0, 0, 0.1); 27 | } 28 | 29 | #plugin-toc .plugin-toc-icon { 30 | opacity: .7; 31 | margin: 1px 2px; 32 | border-radius: 3px; 33 | cursor: pointer; 34 | font-size: 1.1em; 35 | line-height: 1.6em; 36 | flex-grow: 1; 37 | text-align: center; 38 | } 39 | 40 | #plugin-toc .plugin-toc-icon.select, 41 | #plugin-toc .plugin-toc-icon:hover { 42 | background: var(--active-file-bg-color); 43 | color: var(--active-file-text-color); 44 | opacity: 1; 45 | } 46 | 47 | #plugin-toc .plugin-toc-list { 48 | height: 100%; 49 | overflow: scroll; 50 | font-size: ${this.config.toc_font_size}; 51 | } 52 | 53 | #plugin-toc .toc-root { 54 | margin: 0 0.5em 4em 0.5em; 55 | } 56 | 57 | #plugin-toc .toc-header-node { 58 | opacity: 0.6; 59 | } 60 | 61 | #plugin-toc ul { 62 | position: relative; 63 | list-style: none; 64 | padding: 0; 65 | text-align: left; 66 | } 67 | 68 | #plugin-toc li { 69 | margin-bottom: 0.1em; 70 | overflow-wrap: break-word; 71 | list-style: none; 72 | } 73 | 74 | #plugin-toc ul ul { 75 | margin-left: 1.5em; 76 | } 77 | 78 | #plugin-toc .toc-node { 79 | padding: 1px 5px; 80 | border-radius: 4px; 81 | user-select: none; 82 | } 83 | 84 | #plugin-toc .toc-node:hover { 85 | cursor: pointer; 86 | background-color: var(--item-hover-bg-color); 87 | } 88 | 89 | #plugin-toc .toc-node.active { 90 | font-weight: 700; 91 | } 92 | 93 | #plugin-toc .toc-text:hover { 94 | text-decoration: underline; 95 | } 96 | 97 | /*preview-threading*/ 98 | #plugin-toc .plugin-toc-list { 99 | padding-left: 0.8rem; 100 | --line-width: 0.07rem; 101 | --line-color: rgba(0, 0, 0, 0.1); 102 | --line-width-select: 0.1rem; 103 | --line-color-select: red; 104 | } 105 | 106 | .toc-root .toc-node:before { 107 | content: ""; 108 | display: inline-block; 109 | width: .8rem; 110 | height: var(--line-width); 111 | position: absolute; 112 | z-index: 10; 113 | left: -0.72rem; 114 | margin-right: .2rem; 115 | top: 1rem; 116 | background: var(--line-color); 117 | } 118 | 119 | /*#plugin-toc ul:has(.toc-node.active):after,*/ 120 | #plugin-toc ul:before { 121 | content: ""; 122 | display: inline-block; 123 | width: var(--line-width); 124 | position: absolute; 125 | top: -0.1rem; 126 | left: -0.8rem; 127 | z-index: 15; 128 | margin-bottom: .8rem; 129 | } 130 | 131 | #plugin-toc ul:before { 132 | height: calc(100% - 0.5rem); 133 | background: var(--line-color); 134 | } 135 | 136 | /*#plugin-toc ul:has(.toc-node.active):after {*/ 137 | /* height: calc(100% - 0.5rem);*/ 138 | /* background: var(--line-color-select);*/ 139 | /*}*/ 140 | 141 | .toc-root .toc-node.active:before, 142 | .toc-root .toc-node:has(+ ul .toc-node.active):before { 143 | background: var(--line-color-select); 144 | height: var(--line-width-select); 145 | } 146 | -------------------------------------------------------------------------------- /resources/plugin/global/styles/toolbar.css: -------------------------------------------------------------------------------- 1 | #plugin-toolbar { 2 | top: ${topPercent}; 3 | } 4 | 5 | #plugin-toolbar-input { 6 | font-size: 1.2em; 7 | } 8 | 9 | #plugin-toolbar-input input { 10 | width: 100%; 11 | height: 1.5em; 12 | padding-left: 10px; 13 | } 14 | 15 | .plugin-toolbar-result { 16 | margin-top: 0; 17 | max-height: 400px; 18 | overflow-x: hidden; 19 | overflow-y: auto; 20 | scroll-padding: 2.5em; 21 | } 22 | 23 | .plugin-toolbar-item { 24 | display: block; 25 | height: 2.5em; 26 | line-height: 2.5em; 27 | padding-left: 20px; 28 | padding-right: 20px; 29 | overflow: hidden; 30 | cursor: pointer; 31 | border-bottom: 1px solid #ddd; 32 | } 33 | 34 | .plugin-toolbar-item:hover, .plugin-toolbar-item.active { 35 | background-color: var(--active-file-bg-color); 36 | } 37 | 38 | .plugin-toolbar-result .plugin-toolbar-item:last-child { 39 | border: none; 40 | } 41 | -------------------------------------------------------------------------------- /resources/plugin/global/user_styles/README.md: -------------------------------------------------------------------------------- 1 | ## user_styles 目录的作用 2 | 3 | 用于自定义样式。 4 | 5 | 6 | 7 | ## 原理 8 | 9 | `./plugin/global/styles` 目录下存储了各个插件的样式文件。插件系统在读取样式文件时,`user_styles` 目录下文件的优先级高于 `styles` 目录下的文件,所以可以通过在 `user_styles` 下创建同名的 CSS 文件覆盖掉 `styles` 下的文件,实现自定义样式。 10 | 11 | 12 | 13 | ## 如何使用 14 | 15 | 将 `styles` 目录下需要修改的文件 **复制** 到 `user_styles` 目录,接着就可以修改了。 16 | 17 | > 其中有个特殊文件:`customize.css`。若需要添加一些样式,可以在 `user_styles` 里创建此文件并写入 CSS 代码。 18 | 19 | 20 | 21 | ## 渲染变量 22 | 23 | > 类似于 less 的 `@` 变量。 24 | 25 | `styles` 和 `user_styles` 目录下的 CSS 文件支持 JavaScript 的 `${变量}` ,表示渲染变量。 26 | 27 | 举例:下面代码的 `${topPercent}` 将在加载过程中被替换为具体的数值。 28 | 29 | ```css 30 | /* styles/toolbar.css */ 31 | 32 | #plugin-toolbar { 33 | top: ${topPercent}; 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## 选读:插件系统的 CSS 文件加载机制 40 | 41 | ```javascript 42 | // name: css文件名 43 | // args: 该css文件可用的渲染变量($变量) 44 | async registerCssFile(name, args) { 45 | // 获取文件路径 46 | const files = ["user_styles", "styles"].map(dir => this.utils.joinPath("./plugin/global", dir, `${name}.css`)); 47 | 48 | // 读取两个文件的内容(当文件不存在时会返回空) 49 | const [userStyles, defaultStyles] = await this.utils.readFiles(files); 50 | 51 | // userStyles优先于defaultStyles 52 | const data = userStyles || defaultStyles; 53 | if (data === "") return; 54 | if (data === undefined) { 55 | console.error(`there is not such style file: ${name}`); 56 | return; 57 | } 58 | 59 | try { 60 | // 替换style下的$变量,得到完整的CSS字符串 61 | const css = data.replace(/\${(.+?)}/g, (_, $arg) => $arg.split(".").reduce((obj, attr) => obj[attr], args)); 62 | // 将CSS字符串作为style标签插入到HTML中 63 | this.utils.insertStyle(`plugin-${name}-style`, css); 64 | } catch (err) { 65 | console.error(`replace args error. file: ${name}. err: ${err}`); 66 | } 67 | } 68 | ``` 69 | 70 | ```javascript 71 | // usage: 72 | registerCssFile("toolbar", {topPercent: "20%"}); 73 | ``` 74 | 75 | 76 | 77 | ## 必读:开发者的话 78 | 79 | **原则上开发者是不希望用户手动修改样式的。如果用户修改了插件的样式,有可能在某天会出现样式错乱的情况**。因为: 80 | 81 | 1. 用户希望修改的样式往往可以通过修改 user.toml 配置文件实现,没有必要通过修改 css 文件实现。 82 | 2. 在插件的迭代过程中,样式总是会不断变化,并且样式总是和 JavaScript 代码深度绑定,一旦样式和 JavaScript 代码不匹配,BUG 也就随之而来。 83 | 3. 如果您有更好的样式/交互,欢迎 PR,开发者会将其合并到 `styles` 目录中,这样就不必写在 `user_styles` 中了。 84 | 85 | > 所以,如果您修改了样式,某天出现上述情况,请尝试删除/移动 `user_styles` 目录下的所有文件。 86 | -------------------------------------------------------------------------------- /resources/plugin/global/user_styles/customize.css: -------------------------------------------------------------------------------- 1 | /* .markmap { */ 2 | /* font:300 14px/20px 华康手札体W5P !important; */ 3 | /* } */ -------------------------------------------------------------------------------- /resources/plugin/global/user_styles/请读我.md: -------------------------------------------------------------------------------- 1 | ## user_styles 目录的作用 2 | 3 | 用于自定义样式。 4 | 5 | 6 | 7 | ## 原理 8 | 9 | `./plugin/global/styles` 目录下存储了各个插件的样式文件。插件系统在读取样式文件时,`user_styles` 目录下文件的优先级高于 `styles` 目录下的文件,所以可以通过在 `user_styles` 下创建同名的 CSS 文件覆盖掉 `styles` 下的文件,实现自定义样式。 10 | 11 | 12 | 13 | ## 如何使用 14 | 15 | 将 `styles` 目录下需要修改的文件 **复制** 到 `user_styles` 目录,接着就可以修改了。 16 | 17 | > 其中有个特殊文件:`customize.css`。若需要添加一些样式,可以在 `user_styles` 里创建此文件并写入 CSS 代码。 18 | 19 | 20 | 21 | ## 渲染变量 22 | 23 | > 类似于 less 的 `@` 变量。 24 | 25 | `styles` 和 `user_styles` 目录下的 CSS 文件支持 JavaScript 的 `${变量}` ,表示渲染变量。 26 | 27 | 举例:下面代码的 `${topPercent}` 将在加载过程中被替换为具体的数值。 28 | 29 | ```css 30 | /* styles/toolbar.css */ 31 | 32 | #plugin-toolbar { 33 | top: ${topPercent}; 34 | } 35 | ``` 36 | 37 | 38 | 39 | ## 选读:插件系统的 CSS 文件加载机制 40 | 41 | ```javascript 42 | // name: css文件名 43 | // args: 该css文件可用的渲染变量($变量) 44 | async registerCssFile(name, args) { 45 | // 获取文件路径 46 | const files = ["user_styles", "styles"].map(dir => this.utils.joinPath("./plugin/global", dir, `${name}.css`)); 47 | 48 | // 读取两个文件的内容(当文件不存在时会返回空) 49 | const [userStyles, defaultStyles] = await this.utils.readFiles(files); 50 | 51 | // userStyles优先于defaultStyles 52 | const data = userStyles || defaultStyles; 53 | if (data === "") return; 54 | if (data === undefined) { 55 | console.error(`there is not such style file: ${name}`); 56 | return; 57 | } 58 | 59 | try { 60 | // 替换style下的$变量,得到完整的CSS字符串 61 | const css = data.replace(/\${(.+?)}/g, (_, $arg) => $arg.split(".").reduce((obj, attr) => obj[attr], args)); 62 | // 将CSS字符串作为style标签插入到HTML中 63 | this.utils.insertStyle(`plugin-${name}-style`, css); 64 | } catch (err) { 65 | console.error(`replace args error. file: ${name}. err: ${err}`); 66 | } 67 | } 68 | ``` 69 | 70 | ```javascript 71 | // usage: 72 | registerCssFile("toolbar", {topPercent: "20%"}); 73 | ``` 74 | 75 | 76 | 77 | ## 必读:开发者的话 78 | 79 | **原则上开发者是不希望用户手动修改样式的。如果用户修改了插件的样式,有可能在某天会出现样式错乱的情况**。因为: 80 | 81 | 1. 用户希望修改的样式往往可以通过修改 user.toml 配置文件实现,没有必要通过修改 css 文件实现。 82 | 2. 在插件的迭代过程中,样式总是会不断变化,并且样式总是和 JavaScript 代码深度绑定,一旦样式和 JavaScript 代码不匹配,BUG 也就随之而来。 83 | 3. 如果您有更好的样式/交互,欢迎 PR,开发者会将其合并到 `styles` 目录中,这样就不必写在 `user_styles` 中了。 84 | 85 | > 所以,如果您修改了样式,某天出现上述情况,请尝试删除/移动 `user_styles` 目录下的所有文件。 86 | -------------------------------------------------------------------------------- /resources/plugin/go_top.js: -------------------------------------------------------------------------------- 1 | class goTopPlugin extends BasePlugin { 2 | hotkey = () => [ 3 | { hotkey: this.config.HOTKEY_GO_TOP, callback: this.goTop }, 4 | { hotkey: this.config.HOTKEY_GO_BOTTOM, callback: this.goBottom }, 5 | ] 6 | 7 | call = action => { 8 | const func = (action === "go-bottom") ? "jumpBottom" : "jumpTop" 9 | File.editor.selection[func]() 10 | } 11 | 12 | goTop = () => this.call("go-top") 13 | goBottom = () => this.call("go-bottom") 14 | } 15 | 16 | module.exports = { 17 | plugin: goTopPlugin, 18 | } 19 | -------------------------------------------------------------------------------- /resources/plugin/hotkeys.js: -------------------------------------------------------------------------------- 1 | class hotkeysPlugin extends BasePlugin { 2 | hotkey = () => [this.config.HOTKEY] 3 | 4 | process = () => { 5 | const toHotkey = setting => { 6 | const { hotkey, enable, closestSelector, evil, plugin: fixedName, function: func } = setting; 7 | if (!hotkey || !enable) return; 8 | 9 | let callback = null; 10 | if (evil) { 11 | callback = eval(evil); 12 | } else { 13 | if (!fixedName || !func) return; 14 | 15 | callback = this.utils.getPluginFunction(fixedName, func); 16 | if (!callback || !(callback instanceof Function)) return; 17 | 18 | if (closestSelector) { 19 | callback = this.utils.withAnchorNode(closestSelector, callback); 20 | } 21 | } 22 | if (hotkey !== "-") { 23 | return { hotkey, callback } 24 | } 25 | } 26 | 27 | const { CUSTOM_HOTKEYS } = this.config 28 | if (CUSTOM_HOTKEYS.length) { 29 | this.utils.eventHub.addEventListener(this.utils.eventHub.eventType.allPluginsHadInjected, () => { 30 | const hotkeys = CUSTOM_HOTKEYS.map(toHotkey).filter(Boolean) 31 | this.utils.hotkeyHub.register(hotkeys) 32 | }) 33 | } 34 | } 35 | 36 | call = (action, meta) => { 37 | const thText = this.i18n.t("registeredHotkey") 38 | const hintText = this.i18n.t("editConfigFile") + " " + '' 39 | 40 | const trs = [...this.utils.hotkeyHub.map.keys()].sort().map(hk => { 41 | const hotkey = hk.toUpperCase().split("+").map(h => `${h}`).join("+") 42 | return [hotkey] 43 | }) 44 | const table = this.utils.buildTable([[thText], ...trs]) 45 | const onclick = ev => ev.target.closest("a") && this.utils.runtime.openSettingFolder("settings.user.toml") 46 | const components = [ 47 | { label: hintText, type: "p", onclick }, 48 | { label: table, type: "p" }, 49 | ] 50 | this.utils.dialog.modal({ title: this.pluginName, components }) 51 | } 52 | } 53 | 54 | module.exports = { 55 | plugin: hotkeysPlugin, 56 | } 57 | -------------------------------------------------------------------------------- /resources/plugin/index.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", () => { 2 | const { dirname, __dirname, reqnode } = global 3 | const dir = dirname || __dirname 4 | const core = reqnode("path").join(dir, "./plugin/global/core") 5 | const { entry } = reqnode(core) 6 | entry() 7 | }) 8 | 9 | console.debug(` 10 | ____________________________________________________________________ 11 | ______ __ _ 12 | /_ __/_ ______ ____ _________ _ ____ / /_ ______ _(_)___ 13 | / / / / / / __ \\/ __ \\/ ___/ __ \`/ / __ \\/ / / / / __ \`/ / __ \\ 14 | / / / /_/ / /_/ / /_/ / / / /_/ / / /_/ / / /_/ / /_/ / / / / / 15 | /_/ \\__, / .___/\\____/_/ \\__,_/ / .___/_/\\__,_/\\__, /_/_/ /_/ 16 | /____/_/ /_/ /____/ 17 | 18 | Designed by obgnail 19 | https://github.com/obgnail/typora_plugin 20 | ____________________________________________________________________ 21 | `) 22 | -------------------------------------------------------------------------------- /resources/plugin/json_rpc/README.md: -------------------------------------------------------------------------------- 1 | ## 功能 2 | 3 | 将包括 typora-plugin 所有功能在内的 Typora 的一切能力通过 `json-rpc` 的形式暴露出去,以供 **外部操纵 Typora**。 4 | 5 | 6 | 7 | ## 如何使用 8 | 9 | 1. 启动 json_rpc 插件。如此一来,当运行 Typora 后,内部就会自动运行一个 json-rpc-server。 10 | 2. 使用你喜欢的语言写一个 json-rpc-client,与 Typora 交互。 11 | 12 | 以下为 node 和 python 的 example。 13 | 14 | ### node 15 | 16 | ```javascript 17 | // 文件位于./plugin/json_rpc/node-json-rpc.js,需要改为你的路径 18 | const rpc = require("D:/software/Typora/resources/app/plugin/json_rpc/node-json-rpc.js") 19 | 20 | const options = { 21 | port: 5080, 22 | host: '127.0.0.1', 23 | path: '/', 24 | strict: false 25 | }; 26 | 27 | const client = new rpc.Client(options); 28 | 29 | const handle = (err, res) => { 30 | if (err) { console.log(err); } 31 | else { console.log(res); } 32 | } 33 | 34 | client.call({ method: "ping", params: [] }, handle); 35 | client.call({ method: "callPluginFunction", params: ["search_multi", "call"] }, handle); 36 | client.call({ method: "eval", params: ["console.log(this, File)"] }, handle); 37 | ``` 38 | 39 | ### python 40 | 41 | ```python 42 | import requests 43 | 44 | url = "http://localhost:5080" 45 | 46 | 47 | def _call(method, *params): 48 | return requests.post(url, json={"method": method, "params": params, "jsonrpc": "2.0"}).json().get("result") 49 | 50 | 51 | def test(): 52 | assert _call("ping") == "pong from typora-plugin" 53 | 54 | 55 | def call_plugin_function(fixed_name, *args): 56 | _call("callPluginFunction", fixed_name, *args) 57 | 58 | 59 | def eval_typora(eval_str): 60 | _call("eval", eval_str) 61 | 62 | 63 | if __name__ == "__main__": 64 | # 测试 65 | test() 66 | # 切换只读模式 67 | call_plugin_function("read_only", "call") 68 | # 切换到第一个标签页 69 | call_plugin_function("window_tab", "switchTab", 0) 70 | # 执行alert 71 | eval_typora("alert('this is test')") 72 | 73 | ``` 74 | 75 | 76 | 77 | ## API 78 | 79 | 目前暴露三个接口: 80 | 81 | ### ping 82 | 83 | - 功能:验证功能是否打通,成功时返回 `pong from typora-plugin` 84 | - 参数:无 85 | 86 | 87 | 88 | ### callPluginFunction 89 | 90 | - 功能:调用 typora-plugin 能力 91 | - 参数:(fixedName,functionName,…args) 92 | - fixedName:插件的名称 93 | - functionName:源码中插件的方法 94 | - args:插件方法参数 95 | 96 | 97 | 98 | ### eval 99 | 100 | - 功能:执行 eval() 101 | - 参数:evalString。 102 | - 需要执行的字符串 103 | 104 | -------------------------------------------------------------------------------- /resources/plugin/json_rpc/index.js: -------------------------------------------------------------------------------- 1 | class jsonRpcPlugin extends BasePlugin { 2 | process = () => { 3 | try { 4 | const { Server } = require("./node-json-rpc"); 5 | if (!Server) return; 6 | 7 | const server = new Server(this.config.SERVER_OPTIONS); 8 | this.registerRPCFunction(server); 9 | server.start(err => { 10 | if (err) { 11 | console.error("RPC Server Error:", err); 12 | } else { 13 | console.debug("RPC Server running"); 14 | } 15 | }); 16 | } catch (e) { 17 | console.warn(e); 18 | } 19 | } 20 | 21 | registerRPCFunction = server => { 22 | server.addMethod("ping", (para, callback) => callback(null, "pong from typora-plugin")); 23 | 24 | server.addMethod("callPluginFunction", (para, callback) => { 25 | let error, result; 26 | 27 | const [plugin, func, ...args] = para; 28 | if (!plugin || !func) { 29 | error = { code: 404, message: "param has not plugin or function" }; 30 | } 31 | 32 | const p = this.utils.tryGetPlugin(plugin); 33 | const _func = p && p[func]; 34 | if (!_func) { 35 | error = { code: 404, message: "has not the plugin function" }; 36 | } else { 37 | result = _func.apply(plugin, args) || {}; 38 | } 39 | callback(error, result); 40 | }); 41 | 42 | server.addMethod("eval", (para, callback) => { 43 | let error, result; 44 | 45 | try { 46 | const code = para[0]; 47 | result = eval(code) || {}; 48 | } catch (e) { 49 | error = { code: 500, message: e.toString() }; 50 | } 51 | 52 | callback(error, result); 53 | }) 54 | } 55 | } 56 | 57 | module.exports = { 58 | plugin: jsonRpcPlugin, 59 | }; 60 | -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/default.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Theme: Default 3 | Description: Original highlight.js style 4 | Author: (c) Ivan Sagalaev 5 | Maintainer: @highlightjs/core-team 6 | Website: https://highlightjs.org/ 7 | License: see project LICENSE 8 | Touched: 2021 9 | */pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/markmap/resource/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/plugin/markmap/resource/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /resources/plugin/md_padding/index.js: -------------------------------------------------------------------------------- 1 | class mdPaddingPlugin extends BasePlugin { 2 | hotkey = () => [{ hotkey: this.config.HOTKEY, callback: this.call }] 3 | 4 | formatContent = content => { 5 | const { padMarkdown } = require("./md-padding.min.js") 6 | const options = { ignoreWords: this.config.IGNORE_WORDS, ignorePatterns: this.config.IGNORE_PATTERNS } 7 | return padMarkdown(content, options) 8 | } 9 | 10 | formatSelection = () => { 11 | const content = File.editor.UserOp.getSpeechText() 12 | const formattedContent = this.formatContent(content) 13 | this.utils.insertText(null, formattedContent, false) 14 | } 15 | 16 | formatFile = async () => await this.utils.editCurrentFile(this.formatContent) 17 | 18 | call = async () => { 19 | const running = this.i18n.t("running") 20 | const done = this.i18n.t("done") 21 | 22 | this.utils.notification.show(running, "info") 23 | if (this.config.FORMAT_IN_SELECTION_ONLY && !File.editor.selection.getRangy().collapsed) { 24 | await this.formatSelection() 25 | } else { 26 | await this.formatFile() 27 | } 28 | this.utils.notification.show(done) 29 | } 30 | } 31 | 32 | module.exports = { 33 | plugin: mdPaddingPlugin 34 | } 35 | -------------------------------------------------------------------------------- /resources/plugin/no_image.js: -------------------------------------------------------------------------------- 1 | class noImageModePlugin extends BasePlugin { 2 | init = () => { 3 | this.isNoImageMode = this.config.DEFAULT_NO_IMAGE_MODE; 4 | } 5 | 6 | hotkey = () => [this.config.HOTKEY] 7 | 8 | enableNoImageMode = async () => { 9 | const renderArg = { 10 | transition_duration: this.config.TRANSITION_DURATION, 11 | transition_delay: this.config.TRANSITION_DELAY, 12 | opacity_on_hover: this.config.RESHOW_WHEN_HOVER ? "100%" : "0", 13 | } 14 | await this.utils.styleTemplater.register(this.fixedName, renderArg); 15 | this.isNoImageMode = true; 16 | } 17 | 18 | disableNoImageMode = () => { 19 | this.utils.styleTemplater.unregister(this.fixedName); 20 | this.isNoImageMode = false; 21 | } 22 | 23 | toggleNoImageMode = async () => { 24 | const func = this.isNoImageMode ? this.disableNoImageMode : this.enableNoImageMode 25 | await func() 26 | const msg = this.i18n.t(this.isNoImageMode ? "modeEnabled" : "modeDisabled") 27 | this.utils.notification.show(msg) 28 | } 29 | 30 | process = () => this.isNoImageMode && this.enableNoImageMode(); 31 | 32 | call = (action, meta) => this.toggleNoImageMode() 33 | } 34 | 35 | module.exports = { 36 | plugin: noImageModePlugin, 37 | } 38 | -------------------------------------------------------------------------------- /resources/plugin/preferences.js: -------------------------------------------------------------------------------- 1 | class preferencesPlugin extends BasePlugin { 2 | hotkey = () => [{ hotkey: this.config.HOTKEY, callback: this.call }] 3 | 4 | getSettings = async () => { 5 | const [base, custom] = await Promise.all([this.utils.runtime.readBasePluginSetting(), this.utils.runtime.readCustomPluginSetting()]) 6 | delete base.global 7 | return [base, custom] 8 | } 9 | 10 | togglePlugin = async (enableBasePlugins, enableCustomPlugins) => { 11 | const updateSetting = async (file, setting, enablePlugins, enableKey) => { 12 | const newState = Object.keys(setting).reduce((acc, fixedName) => { 13 | acc[fixedName] = { [enableKey]: enablePlugins.includes(fixedName) } 14 | return acc 15 | }, {}) 16 | const needUpdate = Object.entries(setting).some(([name, plugin]) => plugin[enableKey] !== newState[name][enableKey]) 17 | if (needUpdate) { 18 | const settingPath = await this.utils.runtime.getActualSettingPath(file) 19 | const settingObj = await this.utils.readTomlFile(settingPath) 20 | const mergedSetting = this.utils.merge(settingObj, newState) 21 | const newContent = this.utils.stringifyToml(mergedSetting) 22 | return this.utils.writeFile(settingPath, newContent) 23 | } 24 | } 25 | 26 | const [base, custom] = await this.getSettings() 27 | const baseUpdated = await updateSetting("settings.user.toml", base, enableBasePlugins, "ENABLE") 28 | const customUpdated = await updateSetting("custom_plugin.user.toml", custom, enableCustomPlugins, "enable") 29 | if (baseUpdated || customUpdated) { 30 | await this.utils.showRestartMessageBox({ title: this.pluginName }) 31 | } 32 | } 33 | 34 | call = async () => { 35 | const p = ["blur", "export_enhance", "auto_number", "preferences", "right_click_menu", "custom", "json_rpc", "reopenClosedFiles", "redirectLocalRootUrl", "article_uploader"] 36 | const INFO = this.i18n.entries(p, "info.") 37 | const labelEditConfig = this.i18n.t("editConfigFile") + " " + '' 38 | const legendBasePlugin = this.i18n.t("basePlugin") 39 | const legendCustomPlugin = this.i18n.t("customPlugin") 40 | 41 | const display = ([fixedName, plugin]) => ({ 42 | label: `${plugin.NAME || plugin.name || this.i18n._t(fixedName, "pluginName")}(${fixedName})`, 43 | info: INFO[fixedName], 44 | value: fixedName, 45 | checked: plugin.ENABLE || plugin.enable, 46 | disabled: this.config.IGNORE_PLUGINS.includes(fixedName), 47 | }) 48 | const [base, custom] = await this.getSettings() 49 | const basePlugins = Object.entries(base).map(display) 50 | const customPlugins = Object.entries(custom).map(display) 51 | const onclick = ev => ev.target.closest("a") && this.utils.runtime.openSettingFolder() 52 | const components = [ 53 | { label: labelEditConfig, type: "p", onclick }, 54 | { label: "", legend: legendBasePlugin, type: "checkbox", list: basePlugins }, 55 | { label: "", legend: legendCustomPlugin, type: "checkbox", list: customPlugins }, 56 | ] 57 | const modal = { title: this.pluginName, width: "450px", components } 58 | const { response, submit: [_, _base, _custom] } = await this.utils.dialog.modalAsync(modal) 59 | if (response === 1) { 60 | await this.togglePlugin(_base, _custom) 61 | } 62 | } 63 | } 64 | 65 | module.exports = { 66 | plugin: preferencesPlugin 67 | } 68 | -------------------------------------------------------------------------------- /resources/plugin/test.js: -------------------------------------------------------------------------------- 1 | class testPlugin extends BasePlugin { 2 | exportVar = () => { 3 | global.__require__ = require 4 | global.__module__ = module 5 | } 6 | 7 | oneInstance = () => { 8 | const objGetter = () => File && File.editor && File.editor.library 9 | const callback = () => setTimeout(() => ClientCommand.close(), 500) 10 | this.utils.decorate(objGetter, "openFileInNewWindow", null, callback) 11 | } 12 | 13 | openDevTools = () => { 14 | const { eventHub } = this.utils 15 | eventHub.addEventListener(eventHub.eventType.allPluginsHadInjected, () => JSBridge.invoke("window.toggleDevTools")) 16 | } 17 | 18 | process = () => { 19 | this.exportVar() 20 | this.oneInstance() 21 | this.openDevTools() 22 | } 23 | } 24 | 25 | module.exports = { 26 | plugin: testPlugin 27 | } 28 | -------------------------------------------------------------------------------- /resources/plugin/truncate_text.js: -------------------------------------------------------------------------------- 1 | class truncateTextPlugin extends BasePlugin { 2 | beforeProcess = () => { 3 | this.className = "plugin-truncate-text"; 4 | this.staticActions = this.i18n.fillActions([ 5 | { act_name: this.i18n.t("act.hide_front", { remain: this.config.REMAIN_LENGTH }), act_value: "hide_front", act_hotkey: this.config.HIDE_FRONT_HOTKEY }, 6 | { act_value: "show_all", act_hotkey: this.config.SHOW_ALL_HOTKEY }, 7 | { act_value: "hide_base_view", act_hotkey: this.config.HIDE_BASE_VIEW_HOTKEY } 8 | ]) 9 | } 10 | 11 | hotkey = () => [ 12 | { hotkey: this.config.HIDE_FRONT_HOTKEY, callback: () => this.call("hide_front") }, 13 | { hotkey: this.config.SHOW_ALL_HOTKEY, callback: () => this.call("show_all") }, 14 | { hotkey: this.config.HIDE_BASE_VIEW_HOTKEY, callback: () => this.call("hide_base_view") }, 15 | ] 16 | 17 | callbackOtherPlugin = () => { 18 | this.utils.callPluginFunction("toc", "refresh"); 19 | } 20 | 21 | hideFront = () => { 22 | const write = this.utils.entities.eWrite; 23 | const length = write.children.length; 24 | if (length > this.config.REMAIN_LENGTH) { 25 | for (let i = 0; i <= length - this.config.REMAIN_LENGTH; i++) { 26 | const ele = write.children[i]; 27 | ele.classList.add(this.className); 28 | ele.style.display = "none"; 29 | } 30 | } 31 | } 32 | 33 | showAll = () => { 34 | const write = this.utils.entities.eWrite; 35 | write.getElementsByClassName(this.className).forEach(el => el.classList.remove(this.className)); 36 | write.children.forEach(el => el.style.display = ""); 37 | }; 38 | 39 | hideBaseView = () => { 40 | const write = this.utils.entities.eWrite; 41 | let start = 0, end = 0; 42 | write.children.forEach((ele, idx) => { 43 | if (this.utils.isInViewBox(ele)) { 44 | if (!start) start = idx; 45 | start = Math.min(start, idx); 46 | end = Math.max(end, idx); 47 | } 48 | }); 49 | 50 | const halfLength = this.config.REMAIN_LENGTH / 2; 51 | start = Math.max(start - halfLength, 0); 52 | end = Math.min(end + halfLength, write.children.length); 53 | 54 | write.children.forEach((ele, idx) => { 55 | if (idx < start || idx > end) { 56 | ele.classList.add(this.className); 57 | ele.style.display = "none"; 58 | } else { 59 | ele.classList.remove(this.className); 60 | ele.style.display = ""; 61 | } 62 | }); 63 | } 64 | 65 | rollback = () => { 66 | if (this.utils.entities.querySelectorInWrite(`:scope > .${this.className}`)) { 67 | this.showAll(); 68 | } 69 | }; 70 | 71 | call = action => { 72 | if (action === "hide_front") { 73 | this.hideFront() 74 | } else if (action === "show_all") { 75 | this.showAll() 76 | } else if (action === "hide_base_view") { 77 | this.hideBaseView() 78 | } 79 | this.callbackOtherPlugin() 80 | } 81 | } 82 | 83 | module.exports = { 84 | plugin: truncateTextPlugin 85 | } 86 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/HELP-US-OUT.txt: -------------------------------------------------------------------------------- 1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, 2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, 3 | comprehensive icon sets or copy and paste your own. 4 | 5 | Please. Check it out. 6 | 7 | -Dave Gandy 8 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/style/font-awesome-4.7.0/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/resources/style/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /resources/style/font-awesome-4.7.0/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /themes.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xyz349925756/Typora-Mid/b0abe7d21c9b900642044ed86e67dc470f1c957e/themes.zip --------------------------------------------------------------------------------