├── .github └── workflows │ └── main.yml ├── LICENSE ├── README.md ├── README_zh_CN.md ├── assets ├── addDoc.png ├── bk.png ├── card.png ├── compare.png ├── createCard1.gif ├── createWords.gif ├── dailyCardMenu.png ├── dailyCardTree.png ├── digest1.gif ├── digestTrace.png ├── ditestTree.gif ├── moveBlock.png ├── multilineblank.gif ├── multilines.png ├── multilinesCard.png ├── practiceExtract.png ├── reading.png ├── refLeading.png ├── rewrite.png ├── rightClickMenu.png ├── selected.png ├── split.png ├── writingCard.png └── writingCardInit.png ├── dist ├── README.md ├── README_zh_CN.md ├── i18n │ ├── en_US.json │ ├── es_ES.json │ ├── fr_FR.json │ ├── ja_JP.json │ ├── zh_CHT.json │ └── zh_CN.json ├── icon.png ├── index.css ├── index.js ├── plugin.json └── preview.png ├── icon.png ├── package.json ├── plugin.json ├── preview.png ├── svelte.config.js ├── sy-progressive-plugin ├── LICENSE ├── README.md ├── README_zh_CN.md ├── assets │ ├── addDoc.png │ ├── bk.png │ ├── card.png │ ├── compare.png │ ├── createCard1.gif │ ├── createWords.gif │ ├── dailyCardMenu.png │ ├── dailyCardTree.png │ ├── digest1.gif │ ├── digestTrace.png │ ├── ditestTree.gif │ ├── moveBlock.png │ ├── multilineblank.gif │ ├── multilines.png │ ├── multilinesCard.png │ ├── practiceExtract.png │ ├── reading.png │ ├── refLeading.png │ ├── rewrite.png │ ├── rightClickMenu.png │ ├── selected.png │ ├── split.png │ ├── writingCard.png │ └── writingCardInit.png ├── icon.png ├── package.json ├── plugin.json ├── preview.png ├── src │ ├── AddBook.svelte │ ├── DigestProgressive.svelte │ ├── DigestProgressiveBox.ts │ ├── FlashBox.ts │ ├── FloatingAction.ts │ ├── FloatingButton.svelte │ ├── PieceMovingBox.ts │ ├── PieceSummaryBox.ts │ ├── Progressive.ts │ ├── ProgressiveBtn.ts │ ├── Settings.svelte │ ├── ShowAllBooks.svelte │ ├── Split2Pieces.ts │ ├── SplitSentence.ts │ ├── Storage.ts │ ├── WritingCompareBox.ts │ ├── constants.ts │ ├── digestUtils.ts │ ├── helper.ts │ ├── i18n │ │ ├── en_US.json │ │ ├── es_ES.json │ │ ├── fr_FR.json │ │ ├── ja_JP.json │ │ ├── zh_CHT.json │ │ └── zh_CN.json │ ├── icons.ts │ ├── index.scss │ ├── index.ts │ ├── types │ │ └── utils.d.ts │ └── wordsUtils.ts ├── svelte.config.js ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── sy-tomato-plugin ├── LICENSE ├── README.md ├── README_zh_CN.md ├── assets │ ├── AI_OP.gif │ ├── addPinyin.gif │ ├── baiduAI1.png │ ├── bilink1.gif │ ├── bilink1bottom.gif │ ├── bilink2.gif │ ├── bkAndText2ref.gif │ ├── bookmark.png │ ├── bottomBK.png │ ├── cardSusp.gif │ ├── cardpri1.gif │ ├── changeBG.gif │ ├── cleancards.gif │ ├── cmd.png │ ├── copAsImg.gif │ ├── createCard.gif │ ├── createXmid.gif │ ├── delCard.gif │ ├── fastref.gif │ ├── fixbrokenlnks.gif │ ├── flagBookmark.gif │ ├── gotoBlockID.gif │ ├── iconmenu.png │ ├── idea1.jpg │ ├── idea2.jpg │ ├── ideaconflict.png │ ├── ideadesktop.gif │ ├── knowledgeCfg.png │ ├── knowledgeCreateApp.png │ ├── knowledgeCreateAppID.png │ ├── knowledgeCreateKnowledge.png │ ├── knowledgeCreateKnowledgeID.png │ ├── knowledgeShow.gif │ ├── knowledgeShow2.gif │ ├── knowledgeShow3.png │ ├── knowledgeToken.png │ ├── longCopy.gif │ ├── longMove.gif │ ├── makeItBlur.gif │ ├── makeTab.gif │ ├── menu.png │ ├── mergeDocs.gif │ ├── move2dailynote.gif │ ├── moveDocs.gif │ ├── nextdailynote.png │ ├── openRefByClick.gif │ ├── overlay.gif │ ├── randVedio.gif │ ├── readingpoint.gif │ ├── removeCardsInDoc.gif │ ├── scheduleCopyID.gif │ ├── scheduleSetTime.gif │ ├── scheduleSetTime.png │ ├── settings.gif │ ├── statickLnk.gif │ ├── statustomato.png │ ├── taskrm.gif │ ├── text2ref.gif │ ├── text2refF3.gif │ ├── tidyAssets.gif │ ├── tomatoClockCfg.png │ └── uncorrelated.gif ├── icon.png ├── package.json ├── plugin.json ├── preview.png ├── src │ ├── AIBox.ts │ ├── AIBoxMenu.svelte │ ├── BackLinkBottom.svelte │ ├── BackLinkBottomAutoRefresh.svelte │ ├── BackLinkBottomBox.ts │ ├── BackLinkBottomConTree.svelte │ ├── BackLinkBottomOnceRefresh.svelte │ ├── BuyTomato.svelte │ ├── CardBox.ts │ ├── CardBoxSettings.svelte │ ├── CardPriorityBar.svelte │ ├── CardPriorityBox.ts │ ├── CommentBox.svelte │ ├── CommentBox.ts │ ├── CozeSearchBox.ts │ ├── CozeSearchBoxMenu.svelte │ ├── CpBox.ts │ ├── DailyNoteBox.ts │ ├── DbBkBox.ts │ ├── FastNoteBox.ts │ ├── GraphBox.svelte │ ├── GraphBox.ts │ ├── GraphControl.svelte │ ├── GraphMenu.svelte │ ├── GraphNode.svelte │ ├── ImgBox.ts │ ├── ImgOverlayBox.svelte │ ├── ImgOverlayBox.ts │ ├── IndexConf.svelte │ ├── LinkBox.svelte │ ├── LinkBox.ts │ ├── LinkBoxBar.svelte │ ├── ListBox.ts │ ├── MindWire.ts │ ├── MixBox.ts │ ├── NoteBox.svelte │ ├── NoteBox.ts │ ├── NotebookSelect.svelte │ ├── ReadingPoint.svelte │ ├── ReadingPointBox.ts │ ├── Schedule.ts │ ├── Tag2RefBox.ts │ ├── TomatoClock.ts │ ├── TomatoClockVedio.svelte │ ├── TomatoVIP.svelte │ ├── ToolbarBox.ts │ ├── constants.ts │ ├── cssStyle.ts │ ├── exportFiles.ts │ ├── fold.ts │ ├── i18n │ │ ├── empty.drawio │ │ ├── empty.xmind │ │ ├── en_US.json │ │ ├── es_ES.json │ │ ├── fr_FR.json │ │ ├── ja_JP.json │ │ ├── zh_CHT.json │ │ └── zh_CN.json │ ├── icons.ts │ ├── index.scss │ ├── index.ts │ ├── libs │ │ ├── BaseTomatoPlugin.ts │ │ ├── DialogText.ts │ │ ├── DialogTextSv.svelte │ │ ├── EnumUtils.ts │ │ ├── Events.ts │ │ ├── SelectionML.ts │ │ ├── bkUtils.ts │ │ ├── bookmark.ts │ │ ├── cache.ts │ │ ├── cardUtils.ts │ │ ├── cozeAI.ts │ │ ├── destroyer.ts │ │ ├── docUtils.ts │ │ ├── focusUtils.ts │ │ ├── functional.ts │ │ ├── gconst.ts │ │ ├── globalUtils.ts │ │ ├── hash.ts │ │ ├── ial.ts │ │ ├── keyboard.ts │ │ ├── listUtils.ts │ │ ├── openAI.ts │ │ ├── progressive.ts │ │ ├── search.ts │ │ ├── stores.ts │ │ ├── switchDraft.ts │ │ ├── sydom.ts │ │ ├── taobaocode.ts │ │ ├── text1.ts │ │ ├── text10.ts │ │ ├── text11.ts │ │ ├── text2.ts │ │ ├── text3.ts │ │ ├── text4.ts │ │ ├── text5.ts │ │ ├── text6.ts │ │ ├── text7.ts │ │ ├── text8.ts │ │ ├── text9.ts │ │ ├── timer.ts │ │ ├── tools.ts │ │ ├── types.ts │ │ ├── ui.ts │ │ ├── user.ts │ │ ├── utils.ts │ │ └── winHotkey.ts │ ├── tomatoI18n.ts │ └── types │ │ ├── baidu.d.ts │ │ ├── siyuan.d.ts │ │ └── utils.d.ts ├── svelte.config.js ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Create Release on Tag Push 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | # env: 8 | # PROJ_PATH: sy-progressive-plugin 9 | # DEPS_PATH: sy-tomato-plugin 10 | # YARN_CACHE_DIR_PATH: "" 11 | # jobs: 12 | # build: 13 | # runs-on: ubuntu-latest 14 | # steps: 15 | # - name: Checkout workspace repo # https://github.com/marketplace/actions/checkout#checkout-multiple-repos-side-by-side 16 | # uses: actions/checkout@v4 17 | # with: 18 | # repository: IAliceBobI/sy-plugins 19 | 20 | # - name: Install Node.js 21 | # uses: actions/setup-node@v4 22 | # with: 23 | # node-version: 20 24 | # registry-url: "https://registry.npmjs.org" 25 | 26 | # - name: Install yarn 27 | # run: npm install -g yarn 28 | 29 | # - name: Set yarn cache directory 30 | # shell: bash 31 | # run: echo "YARN_CACHE_DIR_PATH=$(yarn cache dir)" >> $GITHUB_ENV 32 | 33 | # - name: Cache dependencies 34 | # uses: actions/cache@v4 35 | # with: 36 | # path: ${{ env.YARN_CACHE_DIR_PATH }} 37 | # key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 38 | # restore-keys: | 39 | # ${{ runner.os }}-yarn- 40 | 41 | # - name: Install dependencies 42 | # run: | 43 | # cd $PROJ_PATH 44 | # yarn install 45 | # cd .. 46 | # cd $DEPS_PATH 47 | # yarn install 48 | 49 | # - name: Build for production 50 | # run: | 51 | # cd $PROJ_PATH 52 | # yarn build 53 | # mv package.zip .. 54 | 55 | # - name: Release 56 | # uses: ncipollo/release-action@v1 57 | # with: 58 | # allowUpdates: true 59 | # artifactErrorsFailBuild: true 60 | # artifacts: "package.zip" 61 | # token: ${{ secrets.GITHUB_TOKEN }} 62 | # prerelease: false 63 | 64 | jobs: 65 | build: 66 | runs-on: ubuntu-latest 67 | 68 | steps: 69 | - name: Checkout repository 70 | uses: actions/checkout@v3 71 | 72 | - name: Run Script 73 | run: | 74 | cd dist 75 | zip -r package.zip ./* 76 | mv package.zip .. 77 | 78 | - name: Release 79 | uses: ncipollo/release-action@v1 80 | with: 81 | allowUpdates: true 82 | artifactErrorsFailBuild: true 83 | artifacts: "package.zip" 84 | token: ${{ secrets.GITHUB_TOKEN }} 85 | prerelease: false 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SiYuan sy-progressive-plugin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /assets/addDoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/addDoc.png -------------------------------------------------------------------------------- /assets/bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/bk.png -------------------------------------------------------------------------------- /assets/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/card.png -------------------------------------------------------------------------------- /assets/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/compare.png -------------------------------------------------------------------------------- /assets/createCard1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/createCard1.gif -------------------------------------------------------------------------------- /assets/createWords.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/createWords.gif -------------------------------------------------------------------------------- /assets/dailyCardMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/dailyCardMenu.png -------------------------------------------------------------------------------- /assets/dailyCardTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/dailyCardTree.png -------------------------------------------------------------------------------- /assets/digest1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/digest1.gif -------------------------------------------------------------------------------- /assets/digestTrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/digestTrace.png -------------------------------------------------------------------------------- /assets/ditestTree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/ditestTree.gif -------------------------------------------------------------------------------- /assets/moveBlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/moveBlock.png -------------------------------------------------------------------------------- /assets/multilineblank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/multilineblank.gif -------------------------------------------------------------------------------- /assets/multilines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/multilines.png -------------------------------------------------------------------------------- /assets/multilinesCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/multilinesCard.png -------------------------------------------------------------------------------- /assets/practiceExtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/practiceExtract.png -------------------------------------------------------------------------------- /assets/reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/reading.png -------------------------------------------------------------------------------- /assets/refLeading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/refLeading.png -------------------------------------------------------------------------------- /assets/rewrite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/rewrite.png -------------------------------------------------------------------------------- /assets/rightClickMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/rightClickMenu.png -------------------------------------------------------------------------------- /assets/selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/selected.png -------------------------------------------------------------------------------- /assets/split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/split.png -------------------------------------------------------------------------------- /assets/writingCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/writingCard.png -------------------------------------------------------------------------------- /assets/writingCardInit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/assets/writingCardInit.png -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /dist/README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /dist/i18n/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "Collect", 3 | "deletePieceAndExit": "Delete Piece and Exit", 4 | "openFlashcardInTab": "Open Flashcard in Tab", 5 | "tipViewContents": "Interest Driven: Open the Table of Contents and start from the interesting part!", 6 | "tipFullfilContent": "Reinsert Piece Content", 7 | "tipCleanUnchanged": "Delete Unchanged Original Text in Piece", 8 | "tipPrevious": "Previous Piece", 9 | "tipNext": "Next Piece", 10 | "tipDelBack": "Delete Piece, View Previous Piece", 11 | "tipSkip": "Delete Piece, View Next Piece", 12 | "tipAddDocCard": "Document Card Making", 13 | "tipDelDocCard": "Cancel Document Card Making", 14 | "tipQuit": "Close Piece", 15 | "tipNextBook": "Switch to Another Book", 16 | "tipIgnore": "Stop Pushing This Book, You Can Enable It in the Top Bar [View All Progressive Learning Documents]", 17 | "countBlocks": "Counted {iter} Blocks...", 18 | "countingFinished": "Counting Finished...", 19 | "start2count": "Start Counting...", 20 | "getAllChildren": "Get All Child Blocks...", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "Insert Writing Style Flashcard", 31 | "send2dailyCardNoRef": "Make Card and Send to Daily Card (No Reference)", 32 | "send2dailyCard": "Make Card and Send to Daily Card", 33 | "insertBlankSpaceCard": "Make Card", 34 | "autoCard": "Auto Make Card", 35 | "ignoreTxt": "Ignore", 36 | "ignore": "🚫", 37 | "Repiece": "Repiece", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "Delete", 41 | "Reading": "Reading", 42 | "FailToNewDoc": "Failed to Create New Document, Please Try Again Later...", 43 | "thisIsFirstPage": "This is the First Page", 44 | "thisIsLastPage": "This is the Last Page", 45 | "AddADocFirst": "You Haven't Added Any Documents Yet.", 46 | "cannotFindDocWaitForIndex": "Document Not Found, Please Rebuild Index or Wait for Indexing to Complete", 47 | "opsInOriDocOrAddIt": "Please Operate in the Original Article, If the Content is Still Unavailable, Try Adding This Document to the Progressive Learning Plugin.", 48 | "addThisDocFirst": "Please Add This Document to the Progressive Reading List First", 49 | "opsInOriDoc": "Please Operate in the Original Article, This is Just a Reading Piece!", 50 | "addOrReaddDoc": "Add/Re-add Document to Progressive Reading", 51 | "splitByBlockCount": "Split by Block Count (0 for No Block Count Split)", 52 | "splitByWordCount": "Split by Word Count (0 for No Word Count Split)", 53 | "splitByHeadings": "Heading Levels 1~6, b for Bold on a Separate Line, Comma Separated, Leave Blank for No Split.", 54 | "youFoundAPiece": "You Found a Reading Piece!", 55 | "maybeBookRemoved": "It Seems {bookID} Has Been Removed", 56 | "openingDocPieceForYou": "Opening Document Piece for You, Please Wait...", 57 | "cannotFindTheBox": "Cannot Find the Notebook Corresponding to the Document:", 58 | "openAdocFirst": "Please Open a Document First", 59 | "progressiveReadingMenu": "Progressive Reading Menu", 60 | "addProgressiveReading": "Add Current Document to Progressive Reading (Piece Mode)", 61 | "viewAllProgressiveBooks": "View All Progressive Learning Documents", 62 | "startToLearn": "Start Learning", 63 | "startToLearnRand": "Start Random Learning", 64 | "readThisPiece": "Read the Cursor-Located Paragraph", 65 | "slowDownALittleBit": "⏳ Please Wait for Indexing to Be Established... Then Continue Operating...", 66 | "msgIgnoreBook": "This Book Has Been Ignored", 67 | "msgPushBook": "Re-push This Book", 68 | "msgAutoCard": "Auto Document Card Making", 69 | "msgNotAutoCard": "Cancel Auto Document Card Making", 70 | "digestProgressive": "Progressive Reading (Excerpt Mode)", 71 | "extractNotes": "Extract Notes", 72 | "extractAllNotes": "Extract All Piece Notes", 73 | "compareNotes": "Compare with Original Text", 74 | "cardMark": "Cloze Mark", 75 | "lnk2href": "*,@ References Replaced with Hyperlinks" 76 | } -------------------------------------------------------------------------------- /dist/i18n/ja_JP.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "収集", 3 | "deletePieceAndExit": "シャープを削除して終了", 4 | "openFlashcardInTab": "この本のフラッシュカードをタブで開く", 5 | "tipViewContents": "興味駆動:目次を開いて、興味のある部分から始めましょう!", 6 | "tipFullfilContent": "シャープの内容を再挿入", 7 | "tipCleanUnchanged": "シャープ内の変更されていない原文を削除", 8 | "tipPrevious": "前のシャープ", 9 | "tipNext": "次のシャープ", 10 | "tipDelBack": "シャープを削除し、前のシャープを見る", 11 | "tipSkip": "シャープを削除し、次のシャープを見る", 12 | "tipAddDocCard": "ドキュメントカード作成", 13 | "tipDelDocCard": "ドキュメントカード作成をキャンセル", 14 | "tipQuit": "シャープを閉じる", 15 | "tipNextBook": "別の本を読む", 16 | "tipIgnore": "この本のプッシュを停止、トップバーの[すべての漸進学習ドキュメントを表示]からプッシュを再開できます", 17 | "countBlocks": "すでに{iter}個のブロックを統計しました……", 18 | "countingFinished": "文字数統計終了……", 19 | "start2count": "文字数統計を開始……", 20 | "getAllChildren": "すべての子ブロックを取得……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "執筆式フラッシュカードを挿入", 31 | "send2dailyCardNoRef": "カードを作成してdaily cardに送信(参照なし)", 32 | "send2dailyCard": "カードを作成してdaily cardに送信", 33 | "insertBlankSpaceCard": "カードを作成", 34 | "autoCard": "自動カード作成", 35 | "ignoreTxt": "無視", 36 | "ignore": "🚫", 37 | "Repiece": "再シャーピング", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "削除", 41 | "Reading": "読書", 42 | "FailToNewDoc": "新規ファイル作成に失敗しました、しばらくしてから再度お試しください……", 43 | "thisIsFirstPage": "これが最初のページです", 44 | "thisIsLastPage": "これが最後のページです", 45 | "AddADocFirst": "まだドキュメントを追加していません。", 46 | "cannotFindDocWaitForIndex": "ドキュメントが見つかりませんでした、インデックスを再構築するか、インデックス構築が完了するのを待ってください", 47 | "opsInOriDocOrAddIt": "オリジナルの記事で操作してください、まだこの内容が見つからない場合は、このドキュメントを漸進学習プラグインに追加することを試してください。", 48 | "addThisDocFirst": "まずこのドキュメントを漸進学習リストに追加してください", 49 | "opsInOriDoc": "オリジナルの記事で操作してください、これは単なる読書シャープです!", 50 | "addOrReaddDoc": "ドキュメントを漸進読書に追加/再追加", 51 | "splitByBlockCount": "ブロック数で分割(0はブロック数で分割しない)", 52 | "splitByWordCount": "文字数で分割(0は文字数で分割しない)", 53 | "splitByHeadings": "見出しレベル1〜6、bは太字で1行、カンマで区切り、空欄は分割しない。", 54 | "youFoundAPiece": "あなたは読書シャープを見つけました!", 55 | "maybeBookRemoved": "{bookID}は削除された可能性があります", 56 | "openingDocPieceForYou": "ドキュメントのシャープを開いています、お待ちください……", 57 | "cannotFindTheBox": "対応するノートブックが見つかりません:", 58 | "openAdocFirst": "まずドキュメントを開いてください", 59 | "progressiveReadingMenu": "漸進学習メニュー", 60 | "addProgressiveReading": "現在のドキュメントを漸進読書に追加(シャーピングモード)", 61 | "viewAllProgressiveBooks": "すべての漸進学習ドキュメントを表示", 62 | "startToLearn": "学習を開始", 63 | "startToLearnRand": "ランダム学習を開始", 64 | "readThisPiece": "カーソルのあるピースを読む", 65 | "slowDownALittleBit": "⏳インデックスの構築を待ってから操作を続けてください……", 66 | "msgIgnoreBook": "この本は無視されました", 67 | "msgPushBook": "この本のプッシュを再開", 68 | "msgAutoCard": "自動ドキュメントカード作成", 69 | "msgNotAutoCard": "自動ドキュメントカード作成をキャンセル", 70 | "digestProgressive": "漸進読書(抜粋モード)", 71 | "extractNotes": "ノートを抽出", 72 | "extractAllNotes": "すべてのシャープノートを抽出", 73 | "compareNotes": "原文と比較", 74 | "cardMark": "空欄マーク", 75 | "lnk2href": "*,@引用を超リンクに置き換える" 76 | } -------------------------------------------------------------------------------- /dist/i18n/zh_CHT.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "蒐集", 3 | "deletePieceAndExit": "刪除分片並退出", 4 | "openFlashcardInTab": "打開本書的閃卡", 5 | "tipViewContents": "興趣驅動:打開目錄,從感興趣的部分開始吧!", 6 | "tipFullfilContent": "重新插入分片內容", 7 | "tipCleanUnchanged": "刪除分片中未改過的原文", 8 | "tipPrevious": "上一個分片", 9 | "tipNext": "下一個分片", 10 | "tipDelBack": "刪除分片,看上一個分片", 11 | "tipSkip": "刪除分片,看下一個分片", 12 | "tipAddDocCard": "文檔制卡", 13 | "tipDelDocCard": "取消文檔制卡", 14 | "tipQuit": "關閉分片", 15 | "tipNextBook": "換一本書看", 16 | "tipIgnore": "不再推送本書,可在頂欄的[查看所有漸進學習文檔]中開啟推送", 17 | "countBlocks": "已經統計了{iter}個塊……", 18 | "countingFinished": "統計字數結束……", 19 | "start2count": "開始統計字數……", 20 | "getAllChildren": "獲取所有子塊……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "插入寫作式閃卡", 31 | "send2dailyCardNoRef": "制卡並發到 daily card (無引用)", 32 | "send2dailyCard": "制卡並發到 daily card", 33 | "insertBlankSpaceCard": "制卡", 34 | "autoCard": "自動制卡", 35 | "ignoreTxt": "忽略", 36 | "ignore": "🚫", 37 | "Repiece": "重新分片", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "刪除", 41 | "Reading": "閱讀", 42 | "FailToNewDoc": "新建文件失敗,請稍後再試試……", 43 | "thisIsFirstPage": "已經是第一頁了", 44 | "thisIsLastPage": "已經是最後一頁了", 45 | "AddADocFirst": "您還沒添加任何文檔。", 46 | "cannotFindDocWaitForIndex": "未找到文檔,請重新建立索引或者等待索引建立完成", 47 | "opsInOriDocOrAddIt": "請在原始文章中操作,如果還找不到此內容,可嘗試添加此文檔到漸進學習插件。", 48 | "addThisDocFirst": "請先將此文檔加入漸進學習列表", 49 | "opsInOriDoc": "請在原始文章中操作,這只是一個閱讀分片!", 50 | "addOrReaddDoc": "添加文檔/重新添加文檔到漸進閱讀", 51 | "splitByBlockCount": "按塊數拆分(0為不按塊數拆分)", 52 | "splitByWordCount": "字數拆分(0為不根據字數拆分)", 53 | "splitByHeadings": "標題級別1~6,b是粗體單獨一行,逗號隔開,留空不拆分。", 54 | "youFoundAPiece": "你發現了一個閱讀分片!", 55 | "maybeBookRemoved": "似乎{bookID}已經被刪除", 56 | "openingDocPieceForYou": "正在為您打開文檔片段,請耐心等待……", 57 | "cannotFindTheBox": "找不到文檔對應的筆記本:", 58 | "openAdocFirst": "請先打開一個文檔", 59 | "progressiveReadingMenu": "漸進學習菜單", 60 | "addProgressiveReading": "添加當前文檔到漸進閱讀(分片模式)", 61 | "viewAllProgressiveBooks": "查看所有漸進學習文檔", 62 | "startToLearn": "開始學習", 63 | "startToLearnRand": "開始隨機學習", 64 | "readThisPiece": "讀光標所在段", 65 | "slowDownALittleBit": "⏳請等待索引的建立……然後再繼續操作……", 66 | "msgIgnoreBook": "已經忽略本書", 67 | "msgPushBook": "重新推送本書", 68 | "msgAutoCard": "自動文檔制卡", 69 | "msgNotAutoCard": "取消自動文檔制卡", 70 | "digestProgressive": "漸進閱讀(摘抄模式)", 71 | "extractNotes": "提取筆記", 72 | "extractAllNotes": "提取所有分片筆記", 73 | "compareNotes": "對比原文", 74 | "cardMark": "挖空標記", 75 | "lnk2href": "*,@引用替換為超連結" 76 | } -------------------------------------------------------------------------------- /dist/i18n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "搜集", 3 | "deletePieceAndExit": "删除分片并退出", 4 | "openFlashcardInTab": "打开本书的闪卡", 5 | "tipViewContents": "兴趣驱动:打开目录,从感兴趣的部分开始吧!", 6 | "tipFullfilContent": "重新插入分片内容", 7 | "tipCleanUnchanged": "删除分片中未改过的原文", 8 | "tipPrevious": "上一个分片", 9 | "tipNext": "下一个分片", 10 | "tipDelBack": "删除分片,看上一个分片", 11 | "tipSkip": "删除分片,看下一个分片", 12 | "tipAddDocCard": "文档制卡", 13 | "tipDelDocCard": "取消文档制卡", 14 | "tipQuit": "关闭分片", 15 | "tipNextBook": "换一本书看", 16 | "tipIgnore": "不再推送本书,可在顶栏的[查看所有渐进学习文档]中开启推送", 17 | "countBlocks": "已经统计了{iter}个块……", 18 | "countingFinished": "统计字数结束……", 19 | "start2count": "开始统计字数……", 20 | "getAllChildren": "获取所有子块……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "原地制卡", 31 | "send2dailyCardNoRef": "制卡并发到 daily card (无引用)", 32 | "send2dailyCard": "制卡并发到 daily card", 33 | "insertBlankSpaceCard": "制卡", 34 | "autoCard": "自动制卡", 35 | "ignoreTxt": "忽略", 36 | "ignore": "🚫", 37 | "Repiece": "重新分片", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "删除", 41 | "Reading": "阅读", 42 | "FailToNewDoc": "新建文件失败,请稍后再试试……", 43 | "thisIsFirstPage": "已经是第一页了", 44 | "thisIsLastPage": "已经是最后一页了", 45 | "AddADocFirst": "您还没添加任何文档。", 46 | "cannotFindDocWaitForIndex": "未找到文档,请重新建立索引或者等待索引建立完成", 47 | "opsInOriDocOrAddIt": "请在原始文章中操作,如果还找不到此内容,可尝试添加此文档到渐进学习插件。", 48 | "addThisDocFirst": "请先将此文档加入渐进学习列表", 49 | "opsInOriDoc": "请在原始文章中操作,这只是一个阅读分片!", 50 | "addOrReaddDoc": "添加文档/重新添加文档到渐进阅读", 51 | "splitByBlockCount": "按块数拆分(0为不按块数拆分)", 52 | "splitByWordCount": "字数拆分(0为不根据字数拆分)", 53 | "splitByHeadings": "标题级别1~6,b是粗体单独一行,逗号隔开,留空不拆分。", 54 | "youFoundAPiece": "你发现了一个阅读分片!", 55 | "maybeBookRemoved": "似乎{bookID}已经被删除", 56 | "openingDocPieceForYou": "正在为您打开文档片段,请耐心等待……", 57 | "cannotFindTheBox": "找不到文档对应的笔记本:", 58 | "openAdocFirst": "请先打开一个文档", 59 | "progressiveReadingMenu": "渐进学习菜单", 60 | "addProgressiveReading": "添加当前文档到渐进阅读(分片模式)", 61 | "viewAllProgressiveBooks": "查看所有渐进学习文档", 62 | "startToLearn": "开始学习", 63 | "startToLearnRand": "开始随机学习", 64 | "readThisPiece": "读光标所在段", 65 | "slowDownALittleBit": "⏳请等待索引的建立……然后再继续操作……", 66 | "msgIgnoreBook": "已经忽略本书", 67 | "msgPushBook": "重新推送本书", 68 | "msgAutoCard": "自动文档制卡", 69 | "msgNotAutoCard": "取消自动文档制卡", 70 | "digestProgressive": "渐进阅读(摘抄模式)", 71 | "extractNotes": "提取笔记", 72 | "extractAllNotes": "提取所有分片笔记", 73 | "compareNotes": "对比原文", 74 | "cardMark": "挖空标记", 75 | "lnk2href": "*,@引用替换为超链接" 76 | } -------------------------------------------------------------------------------- /dist/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/dist/icon.png -------------------------------------------------------------------------------- /dist/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-progressive-plugin", 3 | "author": "IAliceBobI", 4 | "url": "https://github.com/IAliceBobI/sy-progressive-plugin", 5 | "version": "2.0.76", 6 | "minAppVersion": "2.12.6", 7 | "backends": [ 8 | "all" 9 | ], 10 | "frontends": [ 11 | "all" 12 | ], 13 | "displayName": { 14 | "default": "Progressive Learning", 15 | "zh_CN": "渐进学习" 16 | }, 17 | "description": { 18 | "default": "Excerpt-based progressive learning, chunk-based progressive learning, multi-line selection on mobile, double-tap to show menu on mobile, word highlighting with explanations, sentence splitting, split block by pressing Enter, merge blocks, word flashcards, multi-line cloze deletion, multi-line card creation, Daily Card, display pinyin for content", 19 | "zh_CN": "【已开源】摘抄式渐进学习、分片式渐进学习、移动端双击多行选择、划词解释、断句拆分、按回车拆分块、合并块、单词闪卡、多行挖空、多行制卡、Daily Card、显示拼音" 20 | }, 21 | "readme": { 22 | "default": "README.md", 23 | "zh_CN": "README_zh_CN.md" 24 | }, 25 | "funding": { 26 | "openCollective": "", 27 | "patreon": "", 28 | "github": "", 29 | "custom": [ 30 | "https://afdian.com/a/playerv5" 31 | ] 32 | }, 33 | "keywords": [ 34 | "Learning", 35 | "Progressive", 36 | "Progressive Learning", 37 | "Progressive Reading", 38 | "Progressive Writing" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /dist/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/dist/preview.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-progressive-plugin", 3 | "version": "0.0.1", 4 | "description": "", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite build --watch", 8 | "build": "vite build" 9 | }, 10 | "keywords": [ 11 | "Learning", 12 | "Progressive", 13 | "Progressive Learning", 14 | "Progressive Reading", 15 | "Progressive Writing" 16 | ], 17 | "author": "IAliceBobI", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 21 | "@tsconfig/svelte": "^4.0.1", 22 | "@types/node": "^20.12.7", 23 | "fast-glob": "^3.2.12", 24 | "glob": "^11.0.0", 25 | "minimist": "^1.2.8", 26 | "rollup-plugin-livereload": "^2.0.5", 27 | "sass": "^1.75.0", 28 | "siyuan": "*", 29 | "svelte": "^4.2.0", 30 | "ts-node": "^10.9.1", 31 | "typescript": "^5.4.5", 32 | "vite": "^5.0.0", 33 | "vite-plugin-static-copy": "^1.0.2", 34 | "vite-plugin-zip-pack": "^1.2.3" 35 | }, 36 | "dependencies": { 37 | "@types/uuid": "^9.0.8", 38 | "uuid": "^9.0.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-progressive-plugin", 3 | "author": "IAliceBobI", 4 | "url": "https://github.com/IAliceBobI/sy-progressive-plugin", 5 | "version": "2.0.76", 6 | "minAppVersion": "2.12.6", 7 | "backends": [ 8 | "all" 9 | ], 10 | "frontends": [ 11 | "all" 12 | ], 13 | "displayName": { 14 | "default": "Progressive Learning", 15 | "zh_CN": "渐进学习" 16 | }, 17 | "description": { 18 | "default": "Excerpt-based progressive learning, chunk-based progressive learning, multi-line selection on mobile, double-tap to show menu on mobile, word highlighting with explanations, sentence splitting, split block by pressing Enter, merge blocks, word flashcards, multi-line cloze deletion, multi-line card creation, Daily Card, display pinyin for content", 19 | "zh_CN": "【已开源】摘抄式渐进学习、分片式渐进学习、移动端双击多行选择、划词解释、断句拆分、按回车拆分块、合并块、单词闪卡、多行挖空、多行制卡、Daily Card、显示拼音" 20 | }, 21 | "readme": { 22 | "default": "README.md", 23 | "zh_CN": "README_zh_CN.md" 24 | }, 25 | "funding": { 26 | "openCollective": "", 27 | "patreon": "", 28 | "github": "", 29 | "custom": [ 30 | "https://afdian.com/a/playerv5" 31 | ] 32 | }, 33 | "keywords": [ 34 | "Learning", 35 | "Progressive", 36 | "Progressive Learning", 37 | "Progressive Reading", 38 | "Progressive Writing" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/preview.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | const NoWarns = new Set([ 4 | "a11y-click-events-have-key-events", 5 | "a11y-no-static-element-interactions", 6 | "a11y-no-noninteractive-element-interactions" 7 | ]); 8 | 9 | export default { 10 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 11 | // for more information about preprocessors 12 | preprocess: vitePreprocess(), 13 | onwarn: (warning, handler) => { 14 | // suppress warnings on `vite dev` and `vite build`; but even without this, things still work 15 | if (NoWarns.has(warning.code)) return; 16 | handler(warning); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /sy-progressive-plugin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SiYuan sy-progressive-plugin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sy-progressive-plugin/README.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /sy-progressive-plugin/README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-progressive-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/ZZr9dGoIno5pnVxn2vpch6BCn3f?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/Cm7nd2G9KoJhOjxGACycvJU6nRg?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/addDoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/addDoc.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/bk.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/card.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/compare.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/createCard1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/createCard1.gif -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/createWords.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/createWords.gif -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/dailyCardMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/dailyCardMenu.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/dailyCardTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/dailyCardTree.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/digest1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/digest1.gif -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/digestTrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/digestTrace.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/ditestTree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/ditestTree.gif -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/moveBlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/moveBlock.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/multilineblank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/multilineblank.gif -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/multilines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/multilines.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/multilinesCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/multilinesCard.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/practiceExtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/practiceExtract.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/reading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/reading.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/refLeading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/refLeading.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/rewrite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/rewrite.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/rightClickMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/rightClickMenu.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/selected.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/split.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/writingCard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/writingCard.png -------------------------------------------------------------------------------- /sy-progressive-plugin/assets/writingCardInit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/assets/writingCardInit.png -------------------------------------------------------------------------------- /sy-progressive-plugin/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/icon.png -------------------------------------------------------------------------------- /sy-progressive-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-progressive-plugin", 3 | "version": "0.0.1", 4 | "description": "", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite build --watch", 8 | "build": "vite build" 9 | }, 10 | "keywords": [ 11 | "Learning", 12 | "Progressive", 13 | "Progressive Learning", 14 | "Progressive Reading", 15 | "Progressive Writing" 16 | ], 17 | "author": "IAliceBobI", 18 | "license": "MIT", 19 | "devDependencies": { 20 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 21 | "@tsconfig/svelte": "^4.0.1", 22 | "@types/node": "^20.12.7", 23 | "fast-glob": "^3.2.12", 24 | "glob": "^11.0.0", 25 | "minimist": "^1.2.8", 26 | "rollup-plugin-livereload": "^2.0.5", 27 | "sass": "^1.75.0", 28 | "siyuan": "*", 29 | "svelte": "^4.2.0", 30 | "ts-node": "^10.9.1", 31 | "typescript": "^5.4.5", 32 | "vite": "^5.0.0", 33 | "vite-plugin-static-copy": "^1.0.2", 34 | "vite-plugin-zip-pack": "^1.2.3" 35 | }, 36 | "dependencies": { 37 | "@types/uuid": "^9.0.8", 38 | "uuid": "^9.0.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sy-progressive-plugin/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-progressive-plugin", 3 | "author": "IAliceBobI", 4 | "url": "https://github.com/IAliceBobI/sy-progressive-plugin", 5 | "version": "2.0.76", 6 | "minAppVersion": "2.12.6", 7 | "backends": [ 8 | "all" 9 | ], 10 | "frontends": [ 11 | "all" 12 | ], 13 | "displayName": { 14 | "default": "Progressive Learning", 15 | "zh_CN": "渐进学习" 16 | }, 17 | "description": { 18 | "default": "Excerpt-based progressive learning, chunk-based progressive learning, multi-line selection on mobile, double-tap to show menu on mobile, word highlighting with explanations, sentence splitting, split block by pressing Enter, merge blocks, word flashcards, multi-line cloze deletion, multi-line card creation, Daily Card, display pinyin for content", 19 | "zh_CN": "【已开源】摘抄式渐进学习、分片式渐进学习、移动端双击多行选择、划词解释、断句拆分、按回车拆分块、合并块、单词闪卡、多行挖空、多行制卡、Daily Card、显示拼音" 20 | }, 21 | "readme": { 22 | "default": "README.md", 23 | "zh_CN": "README_zh_CN.md" 24 | }, 25 | "funding": { 26 | "openCollective": "", 27 | "patreon": "", 28 | "github": "", 29 | "custom": [ 30 | "https://afdian.com/a/playerv5" 31 | ] 32 | }, 33 | "keywords": [ 34 | "Learning", 35 | "Progressive", 36 | "Progressive Learning", 37 | "Progressive Reading", 38 | "Progressive Writing" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /sy-progressive-plugin/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-progressive-plugin/preview.png -------------------------------------------------------------------------------- /sy-progressive-plugin/src/FloatingAction.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "siyuan"; 2 | import { DestroyManager } from "../../sy-tomato-plugin/src/libs/destroyer"; 3 | import FloatingButton from "./FloatingButton.svelte" 4 | 5 | const DMKey = "progressive_FloatingBtn_DMKey_MuTepw8eKDTziKHA9W2WQSt"; 6 | 7 | export function getProgFloatingDm() { 8 | return globalThis[DMKey] as DestroyManager 9 | } 10 | 11 | function newProgFloatingDm() { 12 | let dm = globalThis[DMKey] as DestroyManager 13 | dm?.destroyBy(); 14 | dm = new DestroyManager()//(true,"btn"); 15 | globalThis[DMKey] = dm; 16 | return dm; 17 | } 18 | 19 | export function createFloatingBtn(plugin: Plugin, settings: TomatoSettings) { 20 | const dm = newProgFloatingDm(); 21 | const target = document.body.appendChild(document.createElement("div")); 22 | const sv = new FloatingButton({ 23 | target, 24 | props: { 25 | plugin, 26 | settings, 27 | dm, 28 | } 29 | }); 30 | dm.add("sv", () => sv.$destroy()); 31 | dm.add("div", () => target.parentElement?.removeChild(target)); 32 | dm.setData("e", target) 33 | } 34 | -------------------------------------------------------------------------------- /sy-progressive-plugin/src/Split2Pieces.ts: -------------------------------------------------------------------------------- 1 | import { arrayRemove, siyuan } from "../../sy-tomato-plugin/src/libs/utils"; 2 | 3 | export class ContentLenGroup { 4 | private groups: WordCountType[][]; 5 | private accCount: number; 6 | private maxCount: number; 7 | private collect: WordCountType[][]; 8 | private list: WordCountType[]; 9 | constructor(groups: WordCountType[][], maxCount: number) { 10 | this.groups = groups; 11 | this.accCount = 0; 12 | this.collect = []; 13 | this.list = []; 14 | this.maxCount = maxCount; 15 | } 16 | private newList() { 17 | if (this.list.length > 0) { 18 | this.collect.push(this.list); 19 | this.list = []; 20 | this.accCount = 0; 21 | } 22 | } 23 | private add(wc: WordCountType) { 24 | this.list.push(wc); 25 | if (wc.type !== "h") this.accCount += wc.count; 26 | if (this.accCount >= this.maxCount) { 27 | this.newList(); 28 | } 29 | } 30 | private splitPiece(wc: WordCountType[]): WordCountType[][] { 31 | this.collect = []; 32 | for (const line of wc) { 33 | this.add(line); 34 | } 35 | this.newList(); 36 | return this.collect; 37 | } 38 | split() { 39 | const list = []; 40 | for (const piece of this.groups) { 41 | list.push(...this.splitPiece(piece)); 42 | } 43 | return list; 44 | } 45 | } 46 | 47 | export class HeadingGroup { 48 | private wordCount: WordCountType[]; 49 | private group: WordCountType[][]; 50 | private list: WordCountType[]; 51 | private lastType: string; 52 | private bookID: string; 53 | private headings: string[]; 54 | constructor(wordCount: WordCountType[], headings: string[], bookID: string) { 55 | this.wordCount = wordCount; 56 | this.group = []; 57 | this.list = []; 58 | this.headings = headings; 59 | this.bookID = bookID; 60 | } 61 | public async init() { 62 | if (this.headings.includes("b")) { 63 | arrayRemove(this.headings, "b"); 64 | this.headings.push("7"); 65 | 66 | const blocks = await siyuan.sql(`select id from blocks where root_id='${this.bookID}' and markdown like "**%**" limit 10000`); 67 | const s = new Set(blocks.map(b => b.id)); 68 | this.wordCount.forEach(e => { 69 | if (s.has(e.id)) { 70 | e.type = "h"; 71 | e.subType = "h7"; 72 | } 73 | }); 74 | } 75 | this.headings = this.headings.map(i => `h${i}`); 76 | return this; 77 | } 78 | private add(wc: WordCountType) { 79 | this.getList(wc).push(wc); 80 | this.lastType = wc.type; 81 | } 82 | private next() { 83 | if (this.list.length > 0) { 84 | this.group.push(this.list); 85 | this.list = []; 86 | } 87 | } 88 | private shouldNext(wc: WordCountType) { 89 | if (wc.type === "h" && this.headings.includes(wc.subType) && this.lastType != "h") { 90 | return true; 91 | } 92 | return false; 93 | } 94 | private getList(wc: WordCountType) { 95 | if (this.shouldNext(wc)) { 96 | this.next(); 97 | } 98 | return this.list; 99 | } 100 | split() { 101 | if (this.headings.length == 0) return [this.wordCount]; 102 | for (const wc of this.wordCount) { 103 | this.add(wc); 104 | } 105 | this.next(); 106 | return this.group; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /sy-progressive-plugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const STORAGE_BOOKS = "books.json"; 2 | export const TryAddStarsLock = "TryAddStarsLock"; 3 | export const ProgressiveAddBtnListenersLock = "ProgressiveAddBtnListenersLock"; 4 | export const AddProgressiveReadingLock = "AddProgressiveReadingLock"; 5 | export const BuildContentsLock = "BuildContentsLock"; 6 | export const StartToLearnLock = "StartToLearnLock"; 7 | export const IndexTime2Wait = 400; 8 | 9 | export enum HtmlCBType { 10 | previous = 0, 11 | deleteAndNext = 1, 12 | AddDocCard = 2, 13 | // saveDoc = 3, 14 | quit = 4, 15 | nextBook = 5, 16 | next = 6, 17 | ignoreBook = 7, 18 | fullfilContent = 8, 19 | // cleanUnchanged = 9, 20 | DelDocCard = 10, 21 | deleteAndExit = 11, 22 | openFlashcardTab = 12, 23 | deleteAndBack = 13, 24 | viewContents = 14, 25 | splitByPunctuations = 15, 26 | splitByPunctuationsList = 16, 27 | splitByPunctuationsListCheck = 17, 28 | cleanOriginText = 18, 29 | readThisBlock = 19, 30 | nop = 20, 31 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/i18n/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "Collect", 3 | "deletePieceAndExit": "Delete Piece and Exit", 4 | "openFlashcardInTab": "Open Flashcard in Tab", 5 | "tipViewContents": "Interest Driven: Open the Table of Contents and start from the interesting part!", 6 | "tipFullfilContent": "Reinsert Piece Content", 7 | "tipCleanUnchanged": "Delete Unchanged Original Text in Piece", 8 | "tipPrevious": "Previous Piece", 9 | "tipNext": "Next Piece", 10 | "tipDelBack": "Delete Piece, View Previous Piece", 11 | "tipSkip": "Delete Piece, View Next Piece", 12 | "tipAddDocCard": "Document Card Making", 13 | "tipDelDocCard": "Cancel Document Card Making", 14 | "tipQuit": "Close Piece", 15 | "tipNextBook": "Switch to Another Book", 16 | "tipIgnore": "Stop Pushing This Book, You Can Enable It in the Top Bar [View All Progressive Learning Documents]", 17 | "countBlocks": "Counted {iter} Blocks...", 18 | "countingFinished": "Counting Finished...", 19 | "start2count": "Start Counting...", 20 | "getAllChildren": "Get All Child Blocks...", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "Insert Writing Style Flashcard", 31 | "send2dailyCardNoRef": "Make Card and Send to Daily Card (No Reference)", 32 | "send2dailyCard": "Make Card and Send to Daily Card", 33 | "insertBlankSpaceCard": "Make Card", 34 | "autoCard": "Auto Make Card", 35 | "ignoreTxt": "Ignore", 36 | "ignore": "🚫", 37 | "Repiece": "Repiece", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "Delete", 41 | "Reading": "Reading", 42 | "FailToNewDoc": "Failed to Create New Document, Please Try Again Later...", 43 | "thisIsFirstPage": "This is the First Page", 44 | "thisIsLastPage": "This is the Last Page", 45 | "AddADocFirst": "You Haven't Added Any Documents Yet.", 46 | "cannotFindDocWaitForIndex": "Document Not Found, Please Rebuild Index or Wait for Indexing to Complete", 47 | "opsInOriDocOrAddIt": "Please Operate in the Original Article, If the Content is Still Unavailable, Try Adding This Document to the Progressive Learning Plugin.", 48 | "addThisDocFirst": "Please Add This Document to the Progressive Reading List First", 49 | "opsInOriDoc": "Please Operate in the Original Article, This is Just a Reading Piece!", 50 | "addOrReaddDoc": "Add/Re-add Document to Progressive Reading", 51 | "splitByBlockCount": "Split by Block Count (0 for No Block Count Split)", 52 | "splitByWordCount": "Split by Word Count (0 for No Word Count Split)", 53 | "splitByHeadings": "Heading Levels 1~6, b for Bold on a Separate Line, Comma Separated, Leave Blank for No Split.", 54 | "youFoundAPiece": "You Found a Reading Piece!", 55 | "maybeBookRemoved": "It Seems {bookID} Has Been Removed", 56 | "openingDocPieceForYou": "Opening Document Piece for You, Please Wait...", 57 | "cannotFindTheBox": "Cannot Find the Notebook Corresponding to the Document:", 58 | "openAdocFirst": "Please Open a Document First", 59 | "progressiveReadingMenu": "Progressive Reading Menu", 60 | "addProgressiveReading": "Add Current Document to Progressive Reading (Piece Mode)", 61 | "viewAllProgressiveBooks": "View All Progressive Learning Documents", 62 | "startToLearn": "Start Learning", 63 | "startToLearnRand": "Start Random Learning", 64 | "readThisPiece": "Read the Cursor-Located Paragraph", 65 | "slowDownALittleBit": "⏳ Please Wait for Indexing to Be Established... Then Continue Operating...", 66 | "msgIgnoreBook": "This Book Has Been Ignored", 67 | "msgPushBook": "Re-push This Book", 68 | "msgAutoCard": "Auto Document Card Making", 69 | "msgNotAutoCard": "Cancel Auto Document Card Making", 70 | "digestProgressive": "Progressive Reading (Excerpt Mode)", 71 | "extractNotes": "Extract Notes", 72 | "extractAllNotes": "Extract All Piece Notes", 73 | "compareNotes": "Compare with Original Text", 74 | "cardMark": "Cloze Mark", 75 | "lnk2href": "*,@ References Replaced with Hyperlinks" 76 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/i18n/ja_JP.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "収集", 3 | "deletePieceAndExit": "シャープを削除して終了", 4 | "openFlashcardInTab": "この本のフラッシュカードをタブで開く", 5 | "tipViewContents": "興味駆動:目次を開いて、興味のある部分から始めましょう!", 6 | "tipFullfilContent": "シャープの内容を再挿入", 7 | "tipCleanUnchanged": "シャープ内の変更されていない原文を削除", 8 | "tipPrevious": "前のシャープ", 9 | "tipNext": "次のシャープ", 10 | "tipDelBack": "シャープを削除し、前のシャープを見る", 11 | "tipSkip": "シャープを削除し、次のシャープを見る", 12 | "tipAddDocCard": "ドキュメントカード作成", 13 | "tipDelDocCard": "ドキュメントカード作成をキャンセル", 14 | "tipQuit": "シャープを閉じる", 15 | "tipNextBook": "別の本を読む", 16 | "tipIgnore": "この本のプッシュを停止、トップバーの[すべての漸進学習ドキュメントを表示]からプッシュを再開できます", 17 | "countBlocks": "すでに{iter}個のブロックを統計しました……", 18 | "countingFinished": "文字数統計終了……", 19 | "start2count": "文字数統計を開始……", 20 | "getAllChildren": "すべての子ブロックを取得……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "執筆式フラッシュカードを挿入", 31 | "send2dailyCardNoRef": "カードを作成してdaily cardに送信(参照なし)", 32 | "send2dailyCard": "カードを作成してdaily cardに送信", 33 | "insertBlankSpaceCard": "カードを作成", 34 | "autoCard": "自動カード作成", 35 | "ignoreTxt": "無視", 36 | "ignore": "🚫", 37 | "Repiece": "再シャーピング", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "削除", 41 | "Reading": "読書", 42 | "FailToNewDoc": "新規ファイル作成に失敗しました、しばらくしてから再度お試しください……", 43 | "thisIsFirstPage": "これが最初のページです", 44 | "thisIsLastPage": "これが最後のページです", 45 | "AddADocFirst": "まだドキュメントを追加していません。", 46 | "cannotFindDocWaitForIndex": "ドキュメントが見つかりませんでした、インデックスを再構築するか、インデックス構築が完了するのを待ってください", 47 | "opsInOriDocOrAddIt": "オリジナルの記事で操作してください、まだこの内容が見つからない場合は、このドキュメントを漸進学習プラグインに追加することを試してください。", 48 | "addThisDocFirst": "まずこのドキュメントを漸進学習リストに追加してください", 49 | "opsInOriDoc": "オリジナルの記事で操作してください、これは単なる読書シャープです!", 50 | "addOrReaddDoc": "ドキュメントを漸進読書に追加/再追加", 51 | "splitByBlockCount": "ブロック数で分割(0はブロック数で分割しない)", 52 | "splitByWordCount": "文字数で分割(0は文字数で分割しない)", 53 | "splitByHeadings": "見出しレベル1〜6、bは太字で1行、カンマで区切り、空欄は分割しない。", 54 | "youFoundAPiece": "あなたは読書シャープを見つけました!", 55 | "maybeBookRemoved": "{bookID}は削除された可能性があります", 56 | "openingDocPieceForYou": "ドキュメントのシャープを開いています、お待ちください……", 57 | "cannotFindTheBox": "対応するノートブックが見つかりません:", 58 | "openAdocFirst": "まずドキュメントを開いてください", 59 | "progressiveReadingMenu": "漸進学習メニュー", 60 | "addProgressiveReading": "現在のドキュメントを漸進読書に追加(シャーピングモード)", 61 | "viewAllProgressiveBooks": "すべての漸進学習ドキュメントを表示", 62 | "startToLearn": "学習を開始", 63 | "startToLearnRand": "ランダム学習を開始", 64 | "readThisPiece": "カーソルのあるピースを読む", 65 | "slowDownALittleBit": "⏳インデックスの構築を待ってから操作を続けてください……", 66 | "msgIgnoreBook": "この本は無視されました", 67 | "msgPushBook": "この本のプッシュを再開", 68 | "msgAutoCard": "自動ドキュメントカード作成", 69 | "msgNotAutoCard": "自動ドキュメントカード作成をキャンセル", 70 | "digestProgressive": "漸進読書(抜粋モード)", 71 | "extractNotes": "ノートを抽出", 72 | "extractAllNotes": "すべてのシャープノートを抽出", 73 | "compareNotes": "原文と比較", 74 | "cardMark": "空欄マーク", 75 | "lnk2href": "*,@引用を超リンクに置き換える" 76 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/i18n/zh_CHT.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "蒐集", 3 | "deletePieceAndExit": "刪除分片並退出", 4 | "openFlashcardInTab": "打開本書的閃卡", 5 | "tipViewContents": "興趣驅動:打開目錄,從感興趣的部分開始吧!", 6 | "tipFullfilContent": "重新插入分片內容", 7 | "tipCleanUnchanged": "刪除分片中未改過的原文", 8 | "tipPrevious": "上一個分片", 9 | "tipNext": "下一個分片", 10 | "tipDelBack": "刪除分片,看上一個分片", 11 | "tipSkip": "刪除分片,看下一個分片", 12 | "tipAddDocCard": "文檔制卡", 13 | "tipDelDocCard": "取消文檔制卡", 14 | "tipQuit": "關閉分片", 15 | "tipNextBook": "換一本書看", 16 | "tipIgnore": "不再推送本書,可在頂欄的[查看所有漸進學習文檔]中開啟推送", 17 | "countBlocks": "已經統計了{iter}個塊……", 18 | "countingFinished": "統計字數結束……", 19 | "start2count": "開始統計字數……", 20 | "getAllChildren": "獲取所有子塊……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "插入寫作式閃卡", 31 | "send2dailyCardNoRef": "制卡並發到 daily card (無引用)", 32 | "send2dailyCard": "制卡並發到 daily card", 33 | "insertBlankSpaceCard": "制卡", 34 | "autoCard": "自動制卡", 35 | "ignoreTxt": "忽略", 36 | "ignore": "🚫", 37 | "Repiece": "重新分片", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "刪除", 41 | "Reading": "閱讀", 42 | "FailToNewDoc": "新建文件失敗,請稍後再試試……", 43 | "thisIsFirstPage": "已經是第一頁了", 44 | "thisIsLastPage": "已經是最後一頁了", 45 | "AddADocFirst": "您還沒添加任何文檔。", 46 | "cannotFindDocWaitForIndex": "未找到文檔,請重新建立索引或者等待索引建立完成", 47 | "opsInOriDocOrAddIt": "請在原始文章中操作,如果還找不到此內容,可嘗試添加此文檔到漸進學習插件。", 48 | "addThisDocFirst": "請先將此文檔加入漸進學習列表", 49 | "opsInOriDoc": "請在原始文章中操作,這只是一個閱讀分片!", 50 | "addOrReaddDoc": "添加文檔/重新添加文檔到漸進閱讀", 51 | "splitByBlockCount": "按塊數拆分(0為不按塊數拆分)", 52 | "splitByWordCount": "字數拆分(0為不根據字數拆分)", 53 | "splitByHeadings": "標題級別1~6,b是粗體單獨一行,逗號隔開,留空不拆分。", 54 | "youFoundAPiece": "你發現了一個閱讀分片!", 55 | "maybeBookRemoved": "似乎{bookID}已經被刪除", 56 | "openingDocPieceForYou": "正在為您打開文檔片段,請耐心等待……", 57 | "cannotFindTheBox": "找不到文檔對應的筆記本:", 58 | "openAdocFirst": "請先打開一個文檔", 59 | "progressiveReadingMenu": "漸進學習菜單", 60 | "addProgressiveReading": "添加當前文檔到漸進閱讀(分片模式)", 61 | "viewAllProgressiveBooks": "查看所有漸進學習文檔", 62 | "startToLearn": "開始學習", 63 | "startToLearnRand": "開始隨機學習", 64 | "readThisPiece": "讀光標所在段", 65 | "slowDownALittleBit": "⏳請等待索引的建立……然後再繼續操作……", 66 | "msgIgnoreBook": "已經忽略本書", 67 | "msgPushBook": "重新推送本書", 68 | "msgAutoCard": "自動文檔制卡", 69 | "msgNotAutoCard": "取消自動文檔制卡", 70 | "digestProgressive": "漸進閱讀(摘抄模式)", 71 | "extractNotes": "提取筆記", 72 | "extractAllNotes": "提取所有分片筆記", 73 | "compareNotes": "對比原文", 74 | "cardMark": "挖空標記", 75 | "lnk2href": "*,@引用替換為超連結" 76 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/i18n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "collect": "搜集", 3 | "deletePieceAndExit": "删除分片并退出", 4 | "openFlashcardInTab": "打开本书的闪卡", 5 | "tipViewContents": "兴趣驱动:打开目录,从感兴趣的部分开始吧!", 6 | "tipFullfilContent": "重新插入分片内容", 7 | "tipCleanUnchanged": "删除分片中未改过的原文", 8 | "tipPrevious": "上一个分片", 9 | "tipNext": "下一个分片", 10 | "tipDelBack": "删除分片,看上一个分片", 11 | "tipSkip": "删除分片,看下一个分片", 12 | "tipAddDocCard": "文档制卡", 13 | "tipDelDocCard": "取消文档制卡", 14 | "tipQuit": "关闭分片", 15 | "tipNextBook": "换一本书看", 16 | "tipIgnore": "不再推送本书,可在顶栏的[查看所有渐进学习文档]中开启推送", 17 | "countBlocks": "已经统计了{iter}个块……", 18 | "countingFinished": "统计字数结束……", 19 | "start2count": "开始统计字数……", 20 | "getAllChildren": "获取所有子块……", 21 | "nextBook": "📚📖", 22 | "exit": "🕺", 23 | "delDocCard": "-🗃", 24 | "addDocToCard": "+🗃", 25 | "nextPiece": "➡", 26 | "previousPiece": "⬅", 27 | "cleanUnchangedOriginDoc": "🧹", 28 | "insertOriginDoc": "⬇", 29 | "viewContents": "🗂", 30 | "insertBlankSpaceCardHere": "原地制卡", 31 | "send2dailyCardNoRef": "制卡并发到 daily card (无引用)", 32 | "send2dailyCard": "制卡并发到 daily card", 33 | "insertBlankSpaceCard": "制卡", 34 | "autoCard": "自动制卡", 35 | "ignoreTxt": "忽略", 36 | "ignore": "🚫", 37 | "Repiece": "重新分片", 38 | "DeleteAndNext": "🗑 ➡", 39 | "DeleteAndBack": "⬅ 🗑", 40 | "Delete": "删除", 41 | "Reading": "阅读", 42 | "FailToNewDoc": "新建文件失败,请稍后再试试……", 43 | "thisIsFirstPage": "已经是第一页了", 44 | "thisIsLastPage": "已经是最后一页了", 45 | "AddADocFirst": "您还没添加任何文档。", 46 | "cannotFindDocWaitForIndex": "未找到文档,请重新建立索引或者等待索引建立完成", 47 | "opsInOriDocOrAddIt": "请在原始文章中操作,如果还找不到此内容,可尝试添加此文档到渐进学习插件。", 48 | "addThisDocFirst": "请先将此文档加入渐进学习列表", 49 | "opsInOriDoc": "请在原始文章中操作,这只是一个阅读分片!", 50 | "addOrReaddDoc": "添加文档/重新添加文档到渐进阅读", 51 | "splitByBlockCount": "按块数拆分(0为不按块数拆分)", 52 | "splitByWordCount": "字数拆分(0为不根据字数拆分)", 53 | "splitByHeadings": "标题级别1~6,b是粗体单独一行,逗号隔开,留空不拆分。", 54 | "youFoundAPiece": "你发现了一个阅读分片!", 55 | "maybeBookRemoved": "似乎{bookID}已经被删除", 56 | "openingDocPieceForYou": "正在为您打开文档片段,请耐心等待……", 57 | "cannotFindTheBox": "找不到文档对应的笔记本:", 58 | "openAdocFirst": "请先打开一个文档", 59 | "progressiveReadingMenu": "渐进学习菜单", 60 | "addProgressiveReading": "添加当前文档到渐进阅读(分片模式)", 61 | "viewAllProgressiveBooks": "查看所有渐进学习文档", 62 | "startToLearn": "开始学习", 63 | "startToLearnRand": "开始随机学习", 64 | "readThisPiece": "读光标所在段", 65 | "slowDownALittleBit": "⏳请等待索引的建立……然后再继续操作……", 66 | "msgIgnoreBook": "已经忽略本书", 67 | "msgPushBook": "重新推送本书", 68 | "msgAutoCard": "自动文档制卡", 69 | "msgNotAutoCard": "取消自动文档制卡", 70 | "digestProgressive": "渐进阅读(摘抄模式)", 71 | "extractNotes": "提取笔记", 72 | "extractAllNotes": "提取所有分片笔记", 73 | "compareNotes": "对比原文", 74 | "cardMark": "挖空标记", 75 | "lnk2href": "*,@引用替换为超链接" 76 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/icons.ts: -------------------------------------------------------------------------------- 1 | export const ICONS = ` 2 | 3 | 4 | 5 | 6 | 7 | `; 8 | -------------------------------------------------------------------------------- /sy-progressive-plugin/src/index.scss: -------------------------------------------------------------------------------- 1 | // ref path of original 2 | .protyle-wysiwyg div[custom-origin-hpath]:not([custom-prog-origin-text])::before { 3 | content: attr(custom-origin-hpath); 4 | font-size: 80%; 5 | color: var(--b3-font-color2); 6 | padding-left: 15px; 7 | } 8 | 9 | // ref path 10 | .protyle-wysiwyg div[custom-ref-hpath]:not([custom-origin-hpath]):not([custom-prog-origin-text])::before { 11 | content: attr(custom-ref-hpath); 12 | font-size: 80%; 13 | color: var(--b3-font-color3); 14 | padding-left: 15px; 15 | } 16 | 17 | // note in pieces 18 | .protyle-wysiwyg div[custom-progref][custom-paragraph-index]:not([custom-prog-origin-text]):not([custom-prog-key-note]):not([custom-prog-key-no-color]) { 19 | color: var(--b3-font-color2); 20 | } 21 | 22 | // key note 23 | .protyle-wysiwyg div[custom-prog-key-note]:not([custom-prog-key-no-color]) { 24 | color: var(--b3-font-color2); 25 | } 26 | 27 | // last block of the previous piece 28 | .protyle-wysiwyg div[custom-prog-piece-previous] { 29 | transform: scale(0.9); 30 | transform-origin: 0 0; 31 | border-left: 5px solid var(--b3-font-background5); 32 | border-right: 5px solid var(--b3-font-background5); 33 | padding: 10px; 34 | } 35 | 36 | // words 37 | .protyle-wysiwyg div[custom-prog-words] { 38 | color: var(--b3-font-color5); 39 | background-color: var(--b3-font-background5); 40 | } 41 | 42 | // super list 43 | .protyle-wysiwyg div[custom-super-list] { 44 | border-bottom: 1px groove var(--b3-font-color5); 45 | } 46 | 47 | // super block as card 48 | .protyle-wysiwyg div[custom-super-card-box] { 49 | border: 1px solid var(--b3-font-color5); 50 | } 51 | 52 | // settings search 53 | .tomato-highlight { 54 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); 55 | font-size: x-large; 56 | color: var(--b3-font-color2); 57 | } 58 | 59 | .prog-style { 60 | &__p { 61 | margin: 0; 62 | } 63 | 64 | &__checkbox { 65 | top: 0; 66 | left: 0; 67 | height: 18px; 68 | width: 18px; 69 | background-color: var(--b3-theme-background); 70 | border-radius: 3px; 71 | } 72 | 73 | &__container_div { 74 | display: flex; 75 | align-items: center; 76 | justify-content: space-between; 77 | margin-bottom: 10px; 78 | } 79 | 80 | &__container { 81 | display: flex; 82 | justify-content: center; 83 | align-items: center; 84 | height: 100vh; 85 | } 86 | 87 | &__centered-text { 88 | text-align: center; 89 | font-size: 40px; 90 | } 91 | 92 | &__id { 93 | background: var(--b3-card-info-background); 94 | border-radius: 4px; 95 | padding: 2px 8px; 96 | font-size: large; 97 | } 98 | 99 | &__button { 100 | display: inline-block; 101 | padding: 10px 20px; 102 | background-color: var(--b3-font-background12); 103 | color: var(--b3-card-success-color); 104 | text-align: center; 105 | text-decoration: none; 106 | font-size: 16px; 107 | border: none; 108 | border-radius: 4px; 109 | cursor: pointer; 110 | } 111 | 112 | &__button:hover { 113 | background-color: var(--b3-font-background6); 114 | } 115 | 116 | &__button:active { 117 | background-color: var(--b3-font-background7); 118 | } 119 | 120 | &__button.large { 121 | padding: 12px 24px; 122 | font-size: 24px; 123 | } 124 | 125 | &__button.small { 126 | padding: 8px 16px; 127 | font-size: 14px; 128 | } 129 | 130 | &__input { 131 | padding: 10px; 132 | border: 1px solid var(--b3-font-background9); 133 | border-radius: 4px; 134 | font-size: larger; 135 | width: 300px; 136 | } 137 | 138 | &__input::placeholder { 139 | color: var(--b3-font-background9); 140 | } 141 | 142 | &__input:focus { 143 | border-color: var(--b3-font-background9); 144 | box-shadow: 0 0 5px var(--b3-font-background9); 145 | } 146 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/src/types/utils.d.ts: -------------------------------------------------------------------------------- 1 | // https://app.quicktype.io/?l=ts 2 | 3 | type AsList = "p" | "i" | "t"; 4 | 5 | type WordCountType = { id: string; count: number; type: string; subType: string, div: HTMLElement }; 6 | 7 | type BookInfo = { 8 | time: number, 9 | boxID: string, 10 | point: number, 11 | bookID: string, 12 | ignored: boolean, 13 | autoCard: boolean, 14 | showLastBlock: boolean, 15 | autoSplitSentenceP: boolean, 16 | autoSplitSentenceI: boolean, 17 | autoSplitSentenceT: boolean, 18 | addIndex2paragraph: boolean, 19 | }; 20 | 21 | type BookInfos = { [key: string]: BookInfo }; 22 | 23 | 24 | -------------------------------------------------------------------------------- /sy-progressive-plugin/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | const NoWarns = new Set([ 4 | "a11y-click-events-have-key-events", 5 | "a11y-no-static-element-interactions", 6 | "a11y-no-noninteractive-element-interactions" 7 | ]); 8 | 9 | export default { 10 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 11 | // for more information about preprocessors 12 | preprocess: vitePreprocess(), 13 | onwarn: (warning, handler) => { 14 | // suppress warnings on `vite dev` and `vite build`; but even without this, things still work 15 | if (NoWarns.has(warning.code)) return; 16 | handler(warning); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /sy-progressive-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": [ 7 | "ES2022", 8 | "DOM", 9 | "DOM.Iterable" 10 | ], 11 | "skipLibCheck": true, 12 | /* Bundler mode */ 13 | "moduleResolution": "Node", 14 | // "allowImportingTsExtensions": true, 15 | "allowSyntheticDefaultImports": true, 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "noEmit": true, 19 | "jsx": "preserve", 20 | /* Linting */ 21 | "strict": false, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true, 25 | /* Svelte */ 26 | /** 27 | * Typecheck JS in `.svelte` and `.js` files by default. 28 | * Disable checkJs if you'd like to use dynamic types in JS. 29 | * Note that setting allowJs false does not prevent the use 30 | * of JS in `.svelte` files. 31 | */ 32 | "allowJs": true, 33 | "checkJs": true, 34 | "types": [ 35 | "node", 36 | // "vite/client", 37 | // "svelte" 38 | ], 39 | // "baseUrl": "./src", 40 | // "paths": { 41 | // "@/*": ["./src/*"], 42 | // "@/libs/*": ["./src/libs/*"], 43 | // }, 44 | "typeRoots": [ 45 | "./src/types", 46 | "./node_modules/@types" 47 | ], 48 | }, 49 | "include": [ 50 | "src/**/*.ts", 51 | "src/**/*.d.ts", 52 | "src/**/*.svelte", 53 | "../sy-tomato-plugin/src/**/*.ts", 54 | "../sy-tomato-plugin/src/types/**/*.d.ts", 55 | "../sy-tomato-plugin/src/types/**/*.svelte", 56 | ], 57 | "exclude": [ 58 | "node_modules" 59 | ], 60 | "references": [ 61 | { 62 | "path": "./tsconfig.node.json" 63 | } 64 | ], 65 | "root": "." 66 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": [ 10 | "vite.config.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /sy-progressive-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { defineConfig } from "vite"; 3 | import minimist from "minimist"; 4 | import { viteStaticCopy } from "vite-plugin-static-copy"; 5 | import livereload from "rollup-plugin-livereload"; 6 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 7 | import zipPack from "vite-plugin-zip-pack"; 8 | import fg from "fast-glob"; 9 | 10 | const args = minimist(process.argv.slice(2)); 11 | const isWatch = args.watch || args.w || false; 12 | // const devDistDir = "./dev"; 13 | // const distDir = isWatch ? devDistDir : "./dist"; 14 | // console.info("isWatch=>", isWatch); 15 | // console.info("distDir=>", distDir); 16 | const devDistDir = process.env.SYPLUGINDIR + "/sy-progressive-plugin"; 17 | const distDir = devDistDir; 18 | 19 | export default defineConfig({ 20 | resolve: { 21 | alias: { 22 | "@": resolve(__dirname, "src"), 23 | }, 24 | }, 25 | 26 | plugins: [ 27 | svelte(), 28 | viteStaticCopy({ 29 | targets: [ 30 | { 31 | src: "./README*.md", 32 | dest: "./", 33 | }, 34 | { 35 | src: "./icon.png", 36 | dest: "./", 37 | }, 38 | { 39 | src: "./preview.png", 40 | dest: "./", 41 | }, 42 | { 43 | src: "./plugin.json", 44 | dest: "./", 45 | }, 46 | { 47 | src: "./src/i18n/**", 48 | dest: "./i18n/", 49 | }, 50 | ], 51 | }), 52 | ], 53 | 54 | // https://github.com/vitejs/vite/issues/1930 55 | // https://vitejs.dev/guide/env-and-mode.html#env-files 56 | // https://github.com/vitejs/vite/discussions/3058#discussioncomment-2115319 57 | // 在这里自定义变量 58 | define: { 59 | "process.env.DEV_MODE": `"${isWatch}"`, 60 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), 61 | }, 62 | 63 | build: { 64 | // 输出路径 65 | outDir: distDir, 66 | emptyOutDir: false, 67 | 68 | // 构建后是否生成 source map 文件 69 | sourcemap: false, 70 | 71 | // 设置为 false 可以禁用最小化混淆 72 | // 或是用来指定是应用哪种混淆器 73 | // boolean | 'terser' | 'esbuild' 74 | minify: isWatch ? false : "esbuild", // "terser", 75 | 76 | lib: { 77 | // Could also be a dictionary or array of multiple entry points 78 | entry: resolve(__dirname, "src/index.ts"), 79 | // the proper extensions will be added 80 | fileName: "index", 81 | formats: ["cjs"], 82 | }, 83 | 84 | rollupOptions: { 85 | plugins: [ 86 | ...(isWatch 87 | ? [ 88 | livereload(devDistDir), 89 | { 90 | //监听静态资源文件 91 | name: "watch-external", 92 | async buildStart() { 93 | const files = await fg([ 94 | "src/i18n/*.json", 95 | // "./README*.md", 96 | "./plugin.json", 97 | ]); 98 | for (const file of files) { 99 | this.addWatchFile(file); 100 | } 101 | }, 102 | }, 103 | ] 104 | : [ 105 | // zipPack({ 106 | // inDir: "./dist", 107 | // outDir: "./", 108 | // outFileName: "package.zip", 109 | // }), 110 | ]), 111 | ], 112 | 113 | // make sure to externalize deps that shouldn't be bundled 114 | // into your library 115 | external: ["siyuan", "process"], 116 | 117 | output: { 118 | entryFileNames: "[name].js", 119 | assetFileNames: (assetInfo) => { 120 | if (assetInfo.name === "style.css") { 121 | return "index.css"; 122 | } 123 | return assetInfo.name; 124 | }, 125 | }, 126 | }, 127 | }, 128 | }); 129 | -------------------------------------------------------------------------------- /sy-tomato-plugin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SiYuan sy-tomato-plugin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sy-tomato-plugin/README.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-tomato-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/IWPcd438yoL3C6xHC0xcOXDKnmh?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/KekbdZ6Ozo4LLHxAGsncGTKJnff?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /sy-tomato-plugin/README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # [OPEN SOURCE 已开源 🔓](https://github.com/IAliceBobI/sy-tomato-plugin) 2 | 3 | # [DOC 帮助文档 📖](https://awx9773btw.feishu.cn/docx/IWPcd438yoL3C6xHC0xcOXDKnmh?from=from_copylink) 4 | 5 | # [ISSUE 反馈 交流 QQ频道 💬](https://pd.qq.com/s/2fh7nh7gz) 6 | 7 | # [CHANGELOG 更新日志 📅](https://awx9773btw.feishu.cn/docx/KekbdZ6Ozo4LLHxAGsncGTKJnff?from=from_copylink) 8 | 9 | # [ACKNOWLEDGMENTS 鸣谢 🙏](https://awx9773btw.feishu.cn/docx/FQ7udC3jeorfDYxI39ict2UNn2g?from=from_copylink) 10 | 11 | # POWERED BY LOVE 为爱发电 💗 12 | 13 |
14 | alipay 15 |
16 |
17 |
18 | wechat 19 |
20 | -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/AI_OP.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/AI_OP.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/addPinyin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/addPinyin.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/baiduAI1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/baiduAI1.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bilink1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bilink1.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bilink1bottom.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bilink1bottom.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bilink2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bilink2.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bkAndText2ref.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bkAndText2ref.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bookmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bookmark.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/bottomBK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/bottomBK.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/cardSusp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/cardSusp.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/cardpri1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/cardpri1.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/changeBG.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/changeBG.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/cleancards.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/cleancards.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/cmd.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/copAsImg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/copAsImg.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/createCard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/createCard.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/createXmid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/createXmid.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/delCard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/delCard.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/fastref.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/fastref.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/fixbrokenlnks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/fixbrokenlnks.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/flagBookmark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/flagBookmark.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/gotoBlockID.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/gotoBlockID.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/iconmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/iconmenu.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/idea1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/idea1.jpg -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/idea2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/idea2.jpg -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/ideaconflict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/ideaconflict.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/ideadesktop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/ideadesktop.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeCfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeCfg.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeCreateApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeCreateApp.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeCreateAppID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeCreateAppID.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeCreateKnowledge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeCreateKnowledge.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeCreateKnowledgeID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeCreateKnowledgeID.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeShow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeShow.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeShow2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeShow2.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeShow3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeShow3.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/knowledgeToken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/knowledgeToken.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/longCopy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/longCopy.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/longMove.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/longMove.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/makeItBlur.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/makeItBlur.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/makeTab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/makeTab.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/menu.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/mergeDocs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/mergeDocs.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/move2dailynote.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/move2dailynote.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/moveDocs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/moveDocs.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/nextdailynote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/nextdailynote.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/openRefByClick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/openRefByClick.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/overlay.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/randVedio.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/randVedio.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/readingpoint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/readingpoint.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/removeCardsInDoc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/removeCardsInDoc.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/scheduleCopyID.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/scheduleCopyID.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/scheduleSetTime.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/scheduleSetTime.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/scheduleSetTime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/scheduleSetTime.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/settings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/settings.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/statickLnk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/statickLnk.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/statustomato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/statustomato.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/taskrm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/taskrm.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/text2ref.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/text2ref.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/text2refF3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/text2refF3.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/tidyAssets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/tidyAssets.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/tomatoClockCfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/tomatoClockCfg.png -------------------------------------------------------------------------------- /sy-tomato-plugin/assets/uncorrelated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/assets/uncorrelated.gif -------------------------------------------------------------------------------- /sy-tomato-plugin/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/icon.png -------------------------------------------------------------------------------- /sy-tomato-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-tomato-plugin", 3 | "version": "0.0.1", 4 | "description": "", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite build --watch", 8 | "build": "vite build" 9 | }, 10 | "keywords": [ 11 | "TomatoClock", 12 | "Time management", 13 | "Productivity", 14 | "Pomodoro technique", 15 | "Timer plugin", 16 | "Task scheduling", 17 | "Focus sessions", 18 | "Work intervals", 19 | "Breaks", 20 | "Time tracking", 21 | "Timeboxing", 22 | "Time optimization", 23 | "Efficiency", 24 | "Work-life balance", 25 | "Distraction management", 26 | "Task prioritization", 27 | "Time blocking", 28 | "Time visualization", 29 | "Progress tracking", 30 | "Goal setting" 31 | ], 32 | "author": "IAliceBobI", 33 | "license": "MIT", 34 | "devDependencies": { 35 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 36 | "@tsconfig/svelte": "^4.0.1", 37 | "@types/elliptic": "^6.4.18", 38 | "@types/fabric": "^5.3.7", 39 | "@types/node": "^20.12.7", 40 | "fast-glob": "^3.2.12", 41 | "glob": "^11.0.0", 42 | "minimist": "^1.2.8", 43 | "rollup-plugin-livereload": "^2.0.5", 44 | "sass": "^1.75.0", 45 | "siyuan": "*", 46 | "svelte": "^4.2.0", 47 | "ts-node": "^10.9.1", 48 | "typescript": "^5.4.5", 49 | "vite": "^5.0.0", 50 | "vite-plugin-static-copy": "^1.0.2", 51 | "vite-plugin-zip-pack": "^1.2.3" 52 | }, 53 | "dependencies": { 54 | "@dagrejs/dagre": "^1.1.4", 55 | "@types/uuid": "^9.0.8", 56 | "@xyflow/svelte": "^0.1.23", 57 | "elliptic": "^6.5.7", 58 | "fabric": "^5.4.0", 59 | "html2canvas": "^1.4.1", 60 | "moment-timezone": "^0.5.45", 61 | "openai": "^4.49.1", 62 | "pinyin-pro": "^3.20.3", 63 | "terser": "^5.31.6", 64 | "ts-md5": "^1.3.1", 65 | "uuid": "^9.0.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sy-tomato-plugin/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sy-tomato-plugin", 3 | "author": "IAliceBobI", 4 | "url": "https://github.com/IAliceBobI/sy-tomato-plugin", 5 | "version": "4.0.60", 6 | "minAppVersion": "3.0.3", 7 | "backends": [ 8 | "all" 9 | ], 10 | "frontends": [ 11 | "all" 12 | ], 13 | "displayName": { 14 | "default": "Tomato Toolbox", 15 | "zh_CN": "番茄工具箱" 16 | }, 17 | "description": { 18 | "default": "Status Bar Pomodoro, Annotation, Bottom Backlinks, Sync Blocks, Block Relationship Graph, Text to Reference, Flash Idea via Camera, Reading Points, Two-Way Mutual Links, AI Knowledge Base Q&A, Streaming AI, Database Backlinks, Flashcard Priority, Document Merge, Recurring Reminders, Delete Cards During Review, Flashcard Image Cloze, Move to Today's Notes, Clean Up Invalid Flashcards", 19 | "zh_CN": "【已开源】状态栏番茄钟、移动端多选、增强折叠、批注、底部反链、同步块、思维导线、块关系图、文本转引用、拍照闪念、阅读点、双向互链、AI知识库问答、流式AI、数据库反链、闪卡优先级、文档合并、定期提醒、复习时删卡、闪卡图片挖空、移到今日笔记、清理失效闪卡" 20 | }, 21 | "readme": { 22 | "default": "README.md", 23 | "zh_CN": "README_zh_CN.md" 24 | }, 25 | "funding": { 26 | "openCollective": "", 27 | "patreon": "", 28 | "github": "", 29 | "custom": [ 30 | "https://afdian.com/a/playerv5" 31 | ] 32 | }, 33 | "keywords": [ 34 | "TomatoClock", 35 | "Time management", 36 | "Productivity", 37 | "Pomodoro technique", 38 | "Timer plugin", 39 | "Task scheduling", 40 | "Focus sessions", 41 | "Work intervals", 42 | "Breaks", 43 | "Time tracking", 44 | "Timeboxing", 45 | "Time optimization", 46 | "Efficiency", 47 | "Work-life balance", 48 | "Distraction management", 49 | "Task prioritization", 50 | "Time blocking", 51 | "Time visualization", 52 | "Progress tracking", 53 | "Goal setting" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /sy-tomato-plugin/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/preview.png -------------------------------------------------------------------------------- /sy-tomato-plugin/src/AIBox.ts: -------------------------------------------------------------------------------- 1 | import { Dialog, IEventBusMap } from "siyuan"; 2 | import { getAllText, newID, } from "./libs/utils"; 3 | import { events } from "./libs/Events"; 4 | import { aiBoxCheckbox, aiBoxMenuShow, } from "./libs/stores"; 5 | import AIBoxMenu from "./AIBoxMenu.svelte"; 6 | import { DestroyManager } from "./libs/destroyer"; 7 | import { tomatoI18n } from "./tomatoI18n"; 8 | import { BaseTomatoPlugin } from "./libs/BaseTomatoPlugin"; 9 | import { winHotkey } from "./libs/winHotkey"; 10 | 11 | type TomatoMenu = IEventBusMap["click-blockicon"] & IEventBusMap["open-menu-content"]; 12 | export const AIBoxHotkey = winHotkey("⌥⇧S", "人工智能2024-6-9 01:58:39", "💻", () => tomatoI18n.人工智能) 13 | class AIBox { 14 | private plugin: BaseTomatoPlugin; 15 | private dm: DestroyManager; 16 | 17 | async onload(plugin: BaseTomatoPlugin) { 18 | if (!aiBoxCheckbox.get()) return; 19 | 20 | this.plugin = plugin; 21 | this.plugin.addCommand({ 22 | langKey: AIBoxHotkey.langKey, 23 | langText: AIBoxHotkey.langText(), 24 | hotkey: AIBoxHotkey.m, 25 | editorCallback: async (protyle) => { 26 | const { selected, ids } = await events.selectedDivs(protyle); 27 | const id = ids.pop(); 28 | await this.ai(id, getAllText(selected)); 29 | }, 30 | }); 31 | 32 | if (aiBoxMenuShow.get()) { 33 | this.plugin.eventBus.on("open-menu-content", ({ detail }) => { 34 | this.aiMenu(detail as any); 35 | }); 36 | } 37 | } 38 | 39 | blockIconEvent(detail: IEventBusMap["click-blockicon"]) { 40 | if (!this.plugin) return; 41 | if (aiBoxMenuShow.get()) { 42 | this.aiMenu(detail as any); 43 | } 44 | } 45 | 46 | aiMenu(detail: TomatoMenu) { 47 | const menu = detail.menu; 48 | menu.addItem({ 49 | label: AIBoxHotkey.langText(), 50 | iconHTML: AIBoxHotkey.icon, 51 | accelerator: AIBoxHotkey.m, 52 | click: async () => { 53 | const { selected, ids } = await events.selectedDivs(detail.protyle); 54 | const id = ids.pop(); 55 | await this.ai(id, getAllText(selected)); 56 | }, 57 | }); 58 | } 59 | 60 | private async ai(anchorID: string, text: string) { 61 | if (!anchorID) return; 62 | if (this.dm) { 63 | this.dm.run(); 64 | this.dm.destroyBy(); 65 | } else { 66 | this.dm?.destroyBy(); 67 | this.dm = new DestroyManager(); 68 | const id = newID(); 69 | const dialog = new Dialog({ 70 | title: AIBoxHotkey.langText(), 71 | content: `
`, 72 | width: events.isMobile ? "90vw" : "700px", 73 | height: events.isMobile ? "180svw" : null, 74 | destroyCallback: () => { 75 | this.dm?.destroyBy("1") 76 | }, 77 | }); 78 | const d = new AIBoxMenu({ 79 | target: dialog.element.querySelector("#" + id), 80 | props: { 81 | dm: this.dm, 82 | text, 83 | anchorID, 84 | } 85 | }); 86 | this.dm.add("1", () => { dialog.destroy() }) 87 | this.dm.add("2", () => { d.$destroy() }) 88 | this.dm.add("dm", () => { this.dm = null; }) 89 | } 90 | } 91 | } 92 | 93 | export const aiBox = new AIBox(); 94 | 95 | 96 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/BackLinkBottomAutoRefresh.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 25 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/BackLinkBottomConTree.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 |
16 | {#if trees?.size > 0} 17 | {#each trees as [k, v]} 18 | 27 | 28 | {/each} 29 | {/if} 30 |
31 | 32 | 37 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/BackLinkBottomOnceRefresh.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/CozeSearchBox.ts: -------------------------------------------------------------------------------- 1 | import { Dialog, IEventBusMap } from "siyuan"; 2 | import { DestroyManager } from "./libs/destroyer"; 3 | import { tomatoI18n } from "./tomatoI18n"; 4 | import { events } from "./libs/Events"; 5 | import { getAllText, newID, siyuan, } from "./libs/utils"; 6 | import CozeSearchBoxMenu from "./CozeSearchBoxMenu.svelte" 7 | import { BaseTomatoPlugin } from "./libs/BaseTomatoPlugin"; 8 | import { cozeSearchBoxCheckbox, cozeSearchMenuShow } from "./libs/stores"; 9 | import { winHotkey } from "./libs/winHotkey"; 10 | 11 | type TomatoMenu = IEventBusMap["click-blockicon"] & IEventBusMap["open-menu-content"]; 12 | 13 | export const CozeSearchBoxHotkey = winHotkey("⌘⇧o", "coze 2025-1-6 11:44:34",) 14 | class CozeSearchBox { 15 | private plugin: BaseTomatoPlugin; 16 | 17 | async onload(plugin: BaseTomatoPlugin) { 18 | if (!cozeSearchBoxCheckbox.get()) return; 19 | this.plugin = plugin; 20 | 21 | this.plugin.addCommand({ 22 | langKey: CozeSearchBoxHotkey.langKey, 23 | langText: "coze" + tomatoI18n.知识库问答, 24 | hotkey: CozeSearchBoxHotkey.m, 25 | callback: async () => { 26 | try { 27 | const { selected, ids } = await events.selectedDivs(); 28 | const id = ids.pop(); 29 | await this.semantic(id, getAllText(selected)); 30 | } catch { 31 | await this.semantic("", ""); 32 | } 33 | }, 34 | }); 35 | 36 | if (cozeSearchMenuShow.get()) { 37 | this.plugin.eventBus.on("open-menu-content", ({ detail }) => { 38 | this.aiMenu(detail as any); 39 | }); 40 | } 41 | } 42 | 43 | blockIconEvent(detail: IEventBusMap["click-blockicon"]) { 44 | if (!this.plugin) return; 45 | if (cozeSearchMenuShow.get()) { 46 | this.aiMenu(detail as any); 47 | } 48 | } 49 | 50 | aiMenu(detail: TomatoMenu) { 51 | const menu = detail.menu; 52 | menu.addItem({ 53 | label: "coze" + tomatoI18n.知识库问答, 54 | iconHTML: "🔍", 55 | accelerator: CozeSearchBoxHotkey.m, 56 | click: async () => { 57 | const { selected, ids } = await events.selectedDivs(detail.protyle); 58 | const id = ids.pop(); 59 | await this.semantic(id, getAllText(selected)); 60 | }, 61 | }); 62 | } 63 | 64 | private async semantic(anchorID: string, text: string) { 65 | if (events.isBrowser) { 66 | siyuan.pushMsg("can not run in browser env."); 67 | return; 68 | } 69 | const dm = new DestroyManager(); 70 | const id = newID(); 71 | const dialog = new Dialog({ 72 | title: "coze" + tomatoI18n.知识库问答, 73 | content: `
`, 74 | width: events.isMobile ? "90vw" : "400px", 75 | height: events.isMobile ? "180svw" : null, 76 | destroyCallback: () => { 77 | dm.destroyBy("1") 78 | }, 79 | }); 80 | const d = new CozeSearchBoxMenu({ 81 | target: dialog.element.querySelector("#" + id), 82 | props: { 83 | dm, 84 | text, 85 | anchorID, 86 | plugin: this.plugin, 87 | } 88 | }); 89 | dm.add("1", () => { dialog.destroy() }) 90 | dm.add("2", () => { d.$destroy() }) 91 | } 92 | } 93 | 94 | export const cozeSearchBox = new CozeSearchBox(); 95 | 96 | 97 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/CpBox.ts: -------------------------------------------------------------------------------- 1 | import { siyuan, } from "./libs/utils"; 2 | import "./index.scss"; 3 | import { BaseTomatoPlugin } from "./libs/BaseTomatoPlugin"; 4 | import { cpBoxCheckbox } from "./libs/stores"; 5 | import { tomatoI18n } from "./tomatoI18n"; 6 | import { OpenSyFile2 } from "./libs/docUtils"; 7 | import { events } from "./libs/Events"; 8 | import { winHotkey } from "./libs/winHotkey"; 9 | 10 | const LongContentOpsLock = "LongContentOpsLock"; 11 | 12 | export const CpBox批量删除大量连续内容块 = winHotkey("alt+shift+;", "deleteBlocks 2025-5-10 23:28:29") 13 | export const CpBox批量移动大量连续内容块 = winHotkey("alt+shift+'", "moveBlocks 2025-5-10 23:29:52") 14 | export const CpBox批量复制大量连续内容块 = winHotkey("alt+shift+q", "copyBlocks 2025-5-10 23:31:46") 15 | 16 | class CpBox { 17 | private plugin: BaseTomatoPlugin; 18 | 19 | async onload(plugin: BaseTomatoPlugin) { 20 | if (!cpBoxCheckbox.get()) return; 21 | 22 | this.plugin = plugin; 23 | this.plugin.addCommand({ 24 | langKey: CpBox批量删除大量连续内容块.langKey, 25 | langText: tomatoI18n.批量删除大量连续内容块, 26 | hotkey: CpBox批量删除大量连续内容块.m, 27 | callback: async () => { 28 | navigator.locks.request(LongContentOpsLock, { ifAvailable: true }, async (lock) => { 29 | if (lock) { 30 | await this.deleteBlocks(); 31 | } else { 32 | siyuan.pushMsg(this.plugin.i18n.wait4finish); 33 | } 34 | }); 35 | }, 36 | }); 37 | this.plugin.addCommand({ 38 | langKey: CpBox批量移动大量连续内容块.langKey, 39 | langText: tomatoI18n.批量移动大量连续内容块, 40 | hotkey: CpBox批量移动大量连续内容块.m, 41 | callback: async () => { 42 | navigator.locks.request(LongContentOpsLock, { ifAvailable: true }, async (lock) => { 43 | if (lock) { 44 | await this.moveBlocks(false); 45 | } else { 46 | siyuan.pushMsg(this.plugin.i18n.wait4finish); 47 | } 48 | }); 49 | }, 50 | }); 51 | this.plugin.addCommand({ 52 | langKey: CpBox批量复制大量连续内容块.langKey, 53 | langText: tomatoI18n.批量复制大量连续内容块, 54 | hotkey: CpBox批量复制大量连续内容块.m, 55 | callback: async () => { 56 | navigator.locks.request(LongContentOpsLock, { ifAvailable: true }, async (lock) => { 57 | if (lock) { 58 | await this.moveBlocks(true); 59 | } else { 60 | siyuan.pushMsg(this.plugin.i18n.wait4finish); 61 | } 62 | }); 63 | }, 64 | }); 65 | } 66 | 67 | private async deleteBlocks() { 68 | const protyle = events.protyle.protyle; 69 | siyuan.pushMsg(tomatoI18n.批量删除正在检查数据); 70 | await siyuan.deleteBlocksUtil(); 71 | protyle.getInstance().reload(false); 72 | await siyuan.pushMsg("batch deleted!"); 73 | } 74 | 75 | private async moveBlocks(ops: boolean) { 76 | const protyle = events.protyle.protyle; 77 | siyuan.pushMsg(tomatoI18n.批量复制移动正在检查数据); 78 | const blocks = await siyuan.moveBlocksUtil(ops); 79 | if (blocks?.length > 0) { 80 | await OpenSyFile2(this.plugin, blocks[blocks.length - 1].id) 81 | await OpenSyFile2(this.plugin, blocks[0].id) 82 | protyle.getInstance().reload(false); 83 | } 84 | await siyuan.pushMsg("batch moved!"); 85 | } 86 | } 87 | 88 | export const cpBox = new CpBox(); 89 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/FastNoteBox.ts: -------------------------------------------------------------------------------- 1 | import { BaseTomatoPlugin } from "./libs/BaseTomatoPlugin"; 2 | import { fastNoteBoxCheckbox } from "./libs/stores"; 3 | import { siyuan, } from "./libs/utils"; 4 | import { tomatoI18n } from "./tomatoI18n"; 5 | import { OpenSyFile2 } from "./libs/docUtils"; 6 | import { events } from "./libs/Events"; 7 | import { createNote, switchDraft } from "./libs/switchDraft"; 8 | import { winHotkey } from "./libs/winHotkey"; 9 | import { verifyKeyTomato } from "./libs/user"; 10 | 11 | export const FastNoteBox创建快速笔记 = winHotkey("shift+alt+n", "创建快速笔记2024-08-06 10:35:21") 12 | export const FastNoteBox打开最后一个笔记 = winHotkey("⌘⌥N", "2024-08-06 10:35:22") 13 | export const FastNoteBox草稿切换 = winHotkey("alt+F4", "草稿切换 2024-9-13 09:32:44", "", () => tomatoI18n.草稿切换 + " · " + tomatoI18n.切换到文档背面, true) 14 | 15 | class FastNoteBox { 16 | plugin: BaseTomatoPlugin; 17 | 18 | async onload(plugin: BaseTomatoPlugin) { 19 | if (!fastNoteBoxCheckbox.get()) return; 20 | await verifyKeyTomato() 21 | this.plugin = plugin; 22 | this.plugin.addCommand({ 23 | langKey: FastNoteBox创建快速笔记.langKey, 24 | langText: tomatoI18n.创建快速笔记, 25 | hotkey: FastNoteBox创建快速笔记.m, 26 | callback: () => { 27 | navigator.locks.request("FastNoteBox2024-08-06 12:38:21", { mode: "exclusive" }, async (lock) => { 28 | if (lock) await createNote(this.plugin, events.protyle?.protyle); 29 | }) 30 | }, 31 | }); 32 | this.plugin.addCommand({ 33 | langKey: FastNoteBox打开最后一个笔记.langKey, 34 | langText: tomatoI18n.打开最后一个笔记, 35 | hotkey: FastNoteBox打开最后一个笔记.m, 36 | callback: () => { 37 | this.openNote() 38 | }, 39 | }); 40 | this.plugin.addCommand({ 41 | langKey: FastNoteBox草稿切换.langKey, 42 | langText: FastNoteBox草稿切换.langText(), 43 | hotkey: FastNoteBox草稿切换.m, 44 | callback: () => { 45 | if (FastNoteBox草稿切换.cmd()) { 46 | switchDraft(this.plugin, events.protyle?.protyle) 47 | } 48 | }, 49 | }); 50 | } 51 | 52 | private async openNote() { 53 | const kName: keyof (AttrType) = "custom-fastnote"; 54 | const rows = await siyuan.sqlAttr(`select root_id from attributes where name="${kName}" order by value desc limit 1`) 55 | if (!rows || rows.length == 0) { 56 | siyuan.pushMsg("cannot find a fastnote") 57 | return 58 | } 59 | OpenSyFile2(this.plugin, rows[0].root_id) 60 | } 61 | } 62 | 63 | export const fastNoteBox = new FastNoteBox(); 64 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/GraphControl.svelte: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/GraphMenu.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 | 35 | 36 | 37 |
44 | {#if text} 45 |

46 | {text?.slice(0, 10)} 47 |

48 | {/if} 49 | 54 |
55 | 56 | 80 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/GraphNode.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 |
11 | {data.text} 12 |
13 | 14 |
15 | 16 | 21 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/NotebookSelect.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | {#if notebooksPromise} 16 | {#await notebooksPromise} 17 |

...waiting

18 | {:then notebooks} 19 | 38 | {/await} 39 | {/if} 40 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/ReadingPoint.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 |
21 | {#each doms as { dom, row, line }} 22 | {#if row} 23 | 30 | {:else} 31 | {@html dom} 32 | {/if} 33 | {/each} 34 |
35 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/Schedule.ts: -------------------------------------------------------------------------------- 1 | import { siyuan, } from "./libs/utils"; 2 | import "./index.scss"; 3 | import { events } from "./libs/Events"; 4 | import { DATA_NODE_ID } from "./libs/gconst"; 5 | import { findListTypeByElement } from "./libs/listUtils"; 6 | import { BaseTomatoPlugin } from "./libs/BaseTomatoPlugin"; 7 | import { tomatoI18n } from "./tomatoI18n"; 8 | import { winHotkey } from "./libs/winHotkey"; 9 | 10 | export const ScheduleCopyID = winHotkey("shift+alt+3", "copy id 2025-5-12 18:46:16", "", () => tomatoI18n.复制ID) 11 | 12 | class Schedule { 13 | private plugin: BaseTomatoPlugin; 14 | 15 | async onload(plugin: BaseTomatoPlugin) { 16 | this.plugin = plugin; 17 | this.plugin.addCommand({ 18 | langKey: ScheduleCopyID.langKey, 19 | langText: ScheduleCopyID.langText(), 20 | hotkey: ScheduleCopyID.m, 21 | callback: () => { 22 | this.showScheduleDialog(events.lastBlockID); 23 | }, 24 | }); 25 | } 26 | 27 | private async showScheduleDialog(blockID: string) { 28 | if (!blockID) return; 29 | const { id: listID, found } = findListTypeByElement(document.querySelector(`div[data-node-id="${blockID}"]`)) 30 | siyuan.getDocIDByBlockID(blockID).then((id) => { 31 | console.info(`DocID: ${id}`) 32 | console.info(`BlockID: ${blockID}`) 33 | if (listID) console.info(`ListID: ${listID}`) 34 | }) 35 | await copyID(blockID); 36 | const all = document.querySelectorAll(`div[${DATA_NODE_ID}="${blockID}"]`); 37 | if (all?.length == 1) console.info(all[0]) 38 | else console.info(all) 39 | if (found) console.info(found) 40 | } 41 | } 42 | 43 | export async function copyID(idMsg: string) { 44 | await navigator.clipboard.writeText(idMsg); 45 | await siyuan.pushMsg(`copy ID ${idMsg}`); 46 | } 47 | 48 | export const schedule = new Schedule(); 49 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/TomatoClockVedio.svelte: -------------------------------------------------------------------------------- 1 | 48 | 49 | 50 |
51 | {#if !vedioID} 52 |
53 |
{tomatoClock.plugin.i18n.takeARestPlease}
54 |
55 | {:else} 56 |
57 | {/if} 58 |
59 | 60 | 72 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/TomatoVIP.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | {#if codeValid} 9 | 10 | {@html icon("TomatoVIP", ICONS_SIZE)} 12 | {:else} 13 | 14 | {@html icon("VIP", ICONS_SIZE)} 16 | {/if} 17 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/constants.ts: -------------------------------------------------------------------------------- 1 | // export const STORAGE_Prog_SETTINGS = "ProgressiveLearning.json"; 2 | export const STORAGE_Prog_SETTINGS = "tomato-settings.json"; 3 | export const STORAGE_SETTINGS = "tomato-settings.json"; // plugin switch 4 | export const STORAGE_SCHEDULE = "schedule.json"; 5 | export const STORAGE_TOMATO_TIME = "tomato-time.json"; 6 | export const STORAGE_AUTO_BK = "auto_bk"; 7 | export const STORAGE_INSERT_HEADING = "insert_heading"; 8 | export const ATTR_PIC_OVERLAY = "custom-attr-pic-overlay"; 9 | export const OVERLAY_DIV = "overlayDiv"; 10 | 11 | 12 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/empty.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/empty.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IAliceBobI/sy-progressive-plugin/d6c427591521330c7786fa2248b550461b20a1a9/sy-tomato-plugin/src/i18n/empty.xmind -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tomato Timer", 3 | "takeARestPlease": "😊 Take a break!", 4 | "hasWorkedMinutes": "Minutes up", 5 | "takeARestAfterMinutes": "Take a break after", 6 | "startCountdown": "Start countdown", 7 | "cancelCountdown": "Cancel countdown", 8 | "cancelLastCountdown": "Cancel last countdown", 9 | "clickOneBlockFirst": "Please click on a block first", 10 | "setDate": "Set time", 11 | "setDateTitle": "Please set time for the following block", 12 | "scheduledAt": "Reminder time", 13 | "remind": "Remind", 14 | "scheduleSetSuccess": "Reminder set successfully", 15 | "schedule": "Set reminder", 16 | "btnAddADay": "+1 Day", 17 | "addBookmark": "Set reading point", 18 | "addBookmarkWithoutENV": "Set reading point (no environment)", 19 | "removeBrokenCards": "Clean all invalid flashcards cleanCards", 20 | "addFlashCard": "Single list, list card making, cancel card making", 21 | "removedBrokenCards": "Deleted invalid flashcards:", 22 | "thereIsNoInvalidCards": "No invalid flashcards!", 23 | "deleteBlocks": "Batch delete large continuous content blocks deleteBlocks", 24 | "moveBlocks": "Batch move large continuous content blocks moveBlocks", 25 | "copyBlocks": "Batch copy large continuous content blocks copyBlocks", 26 | "deleteBlocksHelp": "Batch delete help:

Please wrap the content to be processed with two lines aacc1 and aacc2.

aacc1
Today has good weather1!
Today has good weather2!
...
Today has good weather3!
aacc2
", 27 | "moveBlocksHelp": "Batch move copy help:

Please wrap the content to be processed with two lines aacc1 and aacc2. Then insert a line aacc3 at the target location.

[Document1]
aacc1
Today has good weather1!
Today has good weather2!
...
Today has good weather3!
aacc2
[Document2]
...
aacc3
...
(Document1 and Document2 can be the same document)
", 28 | "topBarTitleShowContents": "Open contents/bookmark page", 29 | "thereIsNoBookmark": "No bookmarks found", 30 | "showBookmarks": "View reading points", 31 | "lookingForTheList": "Searching for the list...", 32 | "reindex": "Unable to find the list to make cards. If you have indeed placed the cursor within a list item and tried multiple times, you can try rebuilding the index.", 33 | "wait4finish": "Please wait for the previous operation to finish!", 34 | "bilink": "Bidirectional link", 35 | "bilinkSelectBlock": "Bidirectional link: Select block", 36 | "bilinkCreateLnk": "Bidirectional link: Create reciprocal link", 37 | "backlink": "Backlink", 38 | "bottombacklink": "Insert bottom backlink #bottomBacklink", 39 | "bottomMention": "Insert bottom mention #bottomMention", 40 | "addPicOverlay": "Add picture overlay", 41 | "delCard": "Delete current flashcard during review", 42 | "skipCard": "Skip current flashcard during review", 43 | "moveBlock2today": "Move content to daily note", 44 | "previousNote": "Previous note", 45 | "nextNote": "Next note", 46 | "cardPrioritySet": "Document and sub-document flashcard priority", 47 | "setCardPriority": "Set flashcard priority", 48 | "uncheckAll": "Uncheck all completed todo tasks in the current document", 49 | "delAllchecked": "Delete all completed todo tasks in the current document", 50 | "refreshVirRef": "Refresh virtual reference", 51 | "removeDocCards": "Remove all flashcards in the current document", 52 | "hotMenu": "Quick menu", 53 | "spaceRepeat": "Spaced repetition", 54 | "locateDoc": "Global locate document", 55 | "baiduAI": "Send selected content to ERNIE Bot 4", 56 | "addTODOBookmark": "Add a 🚩 bookmark", 57 | "deleteAllTODOBookmarks": "Delete all 🚩 bookmarks", 58 | "txt2ref": "All content separated by spaces is converted to references (ignore content after ##)", 59 | "noteBox": "Capture fleeting thoughts", 60 | "noteBoxGlobal": "Capture fleeting thoughts (global)", 61 | "gotoBlockID": "Jump to block ID in clipboard (gotoBlockID)", 62 | "deleteBookmark": "Delete reading point in current document", 63 | "gotoBookmark": "Jump to reading point in current document" 64 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/ja_JP.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "トマトクロック", 3 | "takeARestPlease": "😊 しばらく休憩しましょう!", 4 | "hasWorkedMinutes": "分間働いた", 5 | "takeARestAfterMinutes": "分後に休憩", 6 | "startCountdown": "カウントダウン開始", 7 | "cancelCountdown": "カウントダウンキャンセル", 8 | "cancelLastCountdown": "前回のカウントダウンをキャンセル", 9 | "clickOneBlockFirst": "まず内容ブロックをクリックしてください", 10 | "setDate": "時間設定", 11 | "setDateTitle": "以下のブロックに時間を設定してください", 12 | "scheduledAt": "リマインダー時間", 13 | "remind": "リマインド", 14 | "scheduleSetSuccess": "リマインダー設定成功", 15 | "schedule": "リマインダー設定", 16 | "btnAddADay": "+1日", 17 | "addBookmark": "読書ポイントを設定", 18 | "addBookmarkWithoutENV": "読書ポイントを設定(環境なし)", 19 | "removeBrokenCards": "無効なスマートカードをすべてクリーンアップ", 20 | "addFlashCard": "単一リスト、リストからカード作成、カード作成キャンセル", 21 | "removedBrokenCards": "削除された無効なスマートカード:", 22 | "thereIsNoInvalidCards": "無効なスマートカードはありません!", 23 | "deleteBlocks": "大量の連続した内容ブロックを一括削除", 24 | "moveBlocks": "大量の連続した内容ブロックを一括移動", 25 | "copyBlocks": "大量の連続した内容ブロックを一括コピー", 26 | "deleteBlocksHelp": "一括削除のヘルプ:

処理する内容をaacc1とaacc2の2行で囲んでください。

aacc1
今日はいい天気ですね1!
今日はいい天気ですね2!
...
今日はいい天気ですね3!
aacc2
", 27 | "moveBlocksHelp": "一括移動コピーのヘルプ:

処理する内容をaacc1とaacc2の2行で囲み、ターゲット位置にaacc3を挿入してください。

[ドキュメント1]
aacc1
今日はいい天気ですね1!
今日はいい天気ですね2!
...
今日はいい天気ですね3!
aacc2
[ドキュメント2]
...
aacc3
...
(ドキュメント1とドキュメント2は同じドキュメントでも可)
", 28 | "topBarTitleShowContents": "コンテンツページ/ブックマークページを開く", 29 | "thereIsNoBookmark": ":ブックマークはありません", 30 | "showBookmarks": "読書ポイントを表示", 31 | "lookingForTheList": "リストを検索中……", 32 | "reindex": "カード作成のためのリストが見つかりませんでした。カーソルをリストの項目内に置いて何度か試した場合は、インデックスを再構築することを試みてください。", 33 | "wait4finish": "前の操作が完了するまで待ってください!", 34 | "bilink": "双方向リンク", 35 | "bilinkSelectBlock": "双方向リンク:ブロックを選択", 36 | "bilinkCreateLnk": "双方向リンク:往復リンクを作成", 37 | "backlink": "バックリンク", 38 | "bottombacklink": "バックリンクをページ下部に挿入#bottomBacklink", 39 | "bottomMention": "ページ下部にメンションを挿入#bottomMention", 40 | "addPicOverlay": "画像オーバーレイを追加", 41 | "delCard": "復習時に現在のスマートカードを削除", 42 | "skipCard": "復習時に現在のスマートカードをスキップ", 43 | "moveBlock2today": "コンテンツをデイリーノートに移動", 44 | "previousNote": "前のノート", 45 | "nextNote": "次のノート", 46 | "cardPrioritySet": "ドキュメントとサブドキュメントのスマートカードの優先順位", 47 | "setCardPriority": "スマートカードの優先順位を設定", 48 | "uncheckAll": "現在のドキュメントで完了したすべてのTODOタスクのチェックを解除", 49 | "delAllchecked": "現在のドキュメントで完了したすべてのTODOタスクを削除", 50 | "refreshVirRef": "仮想リファレンスを更新", 51 | "removeDocCards": "現在のドキュメント内のすべてのスマートカードを削除", 52 | "hotMenu": "ホットメニュー", 53 | "spaceRepeat": "スペースリピート", 54 | "locateDoc": "ドキュメントのグローバルな位置指定", 55 | "baiduAI": "選択した内容を文心一言4に送信", 56 | "addTODOBookmark": "🚩ブックマークを追加", 57 | "deleteAllTODOBookmarks": "すべての🚩ブックマークを削除", 58 | "txt2ref": "スペースで区切られたすべての内容をリファレンスに変換(##の後の内容は無視)", 59 | "noteBox": "写真での閃き", 60 | "noteBoxGlobal": "写真での閃き(グローバル)", 61 | "gotoBlockID": "クリップボードのブロックIDにジャンプ", 62 | "deleteBookmark": "現在のドキュメントの読書ポイントを削除", 63 | "gotoBookmark": "現在のドキュメントの読書ポイントにジャンプ" 64 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/zh_CHT.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "番茄鐘", 3 | "takeARestPlease": "😊休息一下吧!", 4 | "hasWorkedMinutes": "分鐘已到", 5 | "takeARestAfterMinutes": "分鐘後休息", 6 | "startCountdown": "開始計時", 7 | "cancelCountdown": "取消計時", 8 | "cancelLastCountdown": "取消上次的計時", 9 | "clickOneBlockFirst": "請先點擊一個內容塊", 10 | "setDate": "設置時間", 11 | "setDateTitle": "請為以下塊設置時間", 12 | "scheduledAt": "提醒時間", 13 | "remind": "提醒", 14 | "scheduleSetSuccess": "提醒設置成功", 15 | "schedule": "設置提醒", 16 | "btnAddADay": "+1日", 17 | "addBookmark": "設置閱讀點", 18 | "addBookmarkWithoutENV": "設置閱讀點(無環境)", 19 | "removeBrokenCards": "清理所有失效閃卡cleanCards", 20 | "addFlashCard": "單項列表、列表制卡、取消制卡", 21 | "removedBrokenCards": "已經刪除的失效閃卡:", 22 | "thereIsNoInvalidCards": "無失效閃卡!", 23 | "deleteBlocks": "批量刪除大量連續內容塊deleteBlocks", 24 | "moveBlocks": "批量移動大量連續內容塊moveBlocks", 25 | "copyBlocks": "批量複製大量連續內容塊copyBlocks", 26 | "deleteBlocksHelp": "批量刪除幫助:

請分別用 aacc1 與 aacc2 兩行把要處理的內容包裹起來。

aacc1
今天有個好天氣1!
今天有個好天氣2!
...
今天有個好天氣3!
aacc2
", 27 | "moveBlocksHelp": "批量移動複製幫助:

請分別用 aacc1 與 aacc2 兩行把要處理的內容包裹起來。再到目標位置插入一行 aacc3。

[文檔1]
aacc1
今天有個好天氣1!
今天有個好天氣2!
...
今天有個好天氣3!
aacc2
[文檔2]
...
aacc3
...
(文檔1與文檔2可以是同一個文檔)
", 28 | "topBarTitleShowContents": "打開目錄頁/書籤頁", 29 | "thereIsNoBookmark": ":找不到任何書籤", 30 | "showBookmarks": "查看閱讀點", 31 | "lookingForTheList": "正在查找列表……", 32 | "reindex": "無法找到要制卡的列表,如果你確實是將光標放到列表的某個列表項內嘗試多次,你可以嘗試重建索引。", 33 | "wait4finish": "請等待上個操作完成!", 34 | "bilink": "雙向互鏈", 35 | "bilinkSelectBlock": "雙向互鏈:選擇塊", 36 | "bilinkCreateLnk": "雙向互鏈:創建往返鏈", 37 | "backlink": "反鏈backlink", 38 | "bottombacklink": "插入底部反鏈#bottomBacklink", 39 | "bottomMention": "插入底部提及#bottomMention", 40 | "addPicOverlay": "添加圖片遮擋層", 41 | "delCard": "複習時刪除當前閃卡delete current card", 42 | "skipCard": "複習時跳過當前閃卡skip current card", 43 | "moveBlock2today": "移動內容到 daily note", 44 | "previousNote": "上一個日誌", 45 | "nextNote": "下一個日誌", 46 | "cardPrioritySet": "文檔與子文檔閃卡優先級", 47 | "setCardPriority": "設置閃卡優先級", 48 | "uncheckAll": "取消勾選當前文檔所有已完成的todo任務", 49 | "delAllchecked": "刪除當前文檔所有已完成的todo任務", 50 | "refreshVirRef": "刷新虛擬引用", 51 | "removeDocCards": "取消當前文檔內所有閃卡removeCardsInDoc", 52 | "hotMenu": "快捷菜單", 53 | "spaceRepeat": "間隔重複", 54 | "locateDoc": "全局定位文檔", 55 | "baiduAI": "選中內容發給文心一言4", 56 | "addTODOBookmark": "添加一個🚩書籤", 57 | "deleteAllTODOBookmarks": "刪除所有🚩書籤", 58 | "txt2ref": "空格隔開的所有內容都轉為引用(忽略##後的內容)", 59 | "noteBox": "拍照閃念", 60 | "noteBoxGlobal": "拍照閃念(全局)", 61 | "gotoBlockID": "跳轉到剪貼板中的塊ID(gotoBlockID)", 62 | "deleteBookmark": "刪除當前文檔的閱讀點rp", 63 | "gotoBookmark": "跳到當前文檔的閱讀點rp" 64 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/i18n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "番茄钟", 3 | "takeARestPlease": "😊休息一会儿吧!", 4 | "hasWorkedMinutes": "分钟已到", 5 | "takeARestAfterMinutes": "分钟后休息", 6 | "startCountdown": "开始计时", 7 | "cancelCountdown": "取消计时", 8 | "cancelLastCountdown": "取消上次的计时", 9 | "clickOneBlockFirst": "请先点击一个内容块", 10 | "setDate": "设置时间", 11 | "setDateTitle": "请为以下块设置时间", 12 | "scheduledAt": "提醒时间", 13 | "remind": "提醒", 14 | "scheduleSetSuccess": "提醒设置成功", 15 | "schedule": "设置提醒", 16 | "btnAddADay": "+1日", 17 | "addBookmark": "设置阅读点", 18 | "addBookmarkWithoutENV": "设置阅读点(无环境)", 19 | "removeBrokenCards": "清理所有失效闪卡cleanCards", 20 | "addFlashCard": "单项列表、列表制卡、取消制卡", 21 | "removedBrokenCards": "已经删除的失效闪卡:", 22 | "thereIsNoInvalidCards": "无失效闪卡!", 23 | "deleteBlocks": "批量删除大量连续内容块deleteBlocks", 24 | "moveBlocks": "批量移动大量连续内容块moveBlocks", 25 | "copyBlocks": "批量复制大量连续内容块copyBlocks", 26 | "deleteBlocksHelp": "批量删除帮助:

请分别用 aacc1 与 aacc2 两行把要处理的内容包裹起来。

aacc1
今天有个好天气1!
今天有个好天气2!
...
今天有个好天气3!
aacc2
", 27 | "moveBlocksHelp": "批量移动复制帮助:

请分别用 aacc1 与 aacc2 两行把要处理的内容包裹起来。再到目标位置插入一行 aacc3。

[文档1]
aacc1
今天有个好天气1!
今天有个好天气2!
...
今天有个好天气3!
aacc2
[文档2]
...
aacc3
...
(文档1与文档2可以是同一个文档)
", 28 | "topBarTitleShowContents": "打开目录页/书签页", 29 | "thereIsNoBookmark": ":找不到任何书签", 30 | "showBookmarks": "查看阅读点", 31 | "lookingForTheList": "正在查找列表……", 32 | "reindex": "无法找到要制卡的列表,如果你确实是将光标放到列表的某个列表项内尝试多次,你可以尝试重建索引。", 33 | "wait4finish": "请等待上个操作完成!", 34 | "bilink": "双向互链", 35 | "bilinkSelectBlock": "双向互链:选择块", 36 | "bilinkCreateLnk": "双向互链:创建往返链", 37 | "backlink": "反链backlink", 38 | "bottombacklink": "插入底部反链#bottomBacklink", 39 | "bottomMention": "插入底部提及#bottomMention", 40 | "addPicOverlay": "添加图片遮挡层", 41 | "delCard": "复习时删除当前闪卡delete current card", 42 | "skipCard": "复习时跳过当前闪卡skip current card", 43 | "moveBlock2today": "移动内容到 daily note", 44 | "previousNote": "上一个日志", 45 | "nextNote": "下一个日志", 46 | "cardPrioritySet": "文档与子文档闪卡优先级", 47 | "setCardPriority": "设置闪卡优先级", 48 | "uncheckAll": "取消勾选当前文档所有已完成的todo任务", 49 | "delAllchecked": "删除当前文档所有已完成的todo任务", 50 | "refreshVirRef": "刷新虚拟引用", 51 | "removeDocCards": "取消当前文档内所有闪卡removeCardsInDoc", 52 | "hotMenu": "快捷菜单", 53 | "spaceRepeat": "间隔重复", 54 | "locateDoc": "全局定位文档", 55 | "baiduAI": "选中内容发给文心一言4", 56 | "addTODOBookmark": "添加一个🚩书签", 57 | "deleteAllTODOBookmarks": "删除所有🚩书签", 58 | "txt2ref": "空格隔开的所有内容都转为引用(忽略##后的内容)", 59 | "noteBox": "拍照闪念", 60 | "noteBoxGlobal": "拍照闪念(全局)", 61 | "gotoBlockID": "跳转到剪贴板中的块ID(gotoBlockID)", 62 | "deleteBookmark": "删除当前文档的阅读点rp", 63 | "gotoBookmark": "跳到当前文档的阅读点rp" 64 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/BaseTomatoPlugin.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "siyuan"; 2 | import { newID } from "./utils"; 3 | 4 | export class BaseTomatoPlugin extends Plugin { 5 | constructor(options: any) { 6 | super(options) 7 | } 8 | loadProgStore: (p: BaseTomatoPlugin) => void; 9 | loadStore: (p: BaseTomatoPlugin) => void; 10 | id = newID(); 11 | taskCfg: Promise; 12 | settingCfg: TomatoSettings; 13 | pluginSpec: PluginSpec; 14 | readonly global: TomatoGlobal = globalThis as any; 15 | initCfg() { 16 | const cfg = this.global?.tomato_zZmqus5PtYRi?.pluginConfig; 17 | if (cfg != null) { 18 | console.debug("load cfg from global: pluginID: " + this.id); 19 | this.settingCfg = cfg; 20 | if (this.loadStore) this.loadStore(this); 21 | return true; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/DialogText.ts: -------------------------------------------------------------------------------- 1 | import { newID } from "./utils"; 2 | import DialogTextSv from "./DialogTextSv.svelte"; 3 | import { Dialog } from "siyuan"; 4 | import { DestroyManager } from "./destroyer"; 5 | import { events } from "./Events"; 6 | 7 | export class DialogTextArea { 8 | private title: string; 9 | private defaultValue: string; 10 | 11 | constructor(title: string, defaultValue: string, callback: (s: string) => Promise) { 12 | this.title = title; 13 | this.defaultValue = defaultValue; 14 | this.open(callback); 15 | } 16 | 17 | private open(callback: Func) { 18 | const id = newID(); 19 | const dm = new DestroyManager(); 20 | 21 | const dialog = new Dialog({ 22 | title: this.title, 23 | content: `
`, 24 | width: events.isMobile ? "90vw" : null, 25 | height: events.isMobile ? null : null, 26 | destroyCallback() { 27 | dm.destroyBy("dialog"); 28 | }, 29 | }); 30 | dm.add("dialog", () => dialog.destroy()); 31 | 32 | const svelte = new DialogTextSv({ 33 | target: dialog.element.querySelector("#" + id), 34 | props: { 35 | dm, 36 | callback, 37 | defaultValue: this.defaultValue, 38 | alwaysConfirm: true, 39 | useTextArea: true, 40 | } 41 | }); 42 | dm.add("svelte", () => svelte.$destroy()); 43 | } 44 | } 45 | 46 | export class DialogText { 47 | private title: string; 48 | private defaultValue: string; 49 | private description: string; 50 | private alwaysConfirm: boolean; 51 | 52 | constructor(title: string, defaultValue: string, callback: Func, alwaysConfirm = false, description = "") { 53 | this.alwaysConfirm = alwaysConfirm; 54 | this.title = title; 55 | this.defaultValue = defaultValue; 56 | this.description = description; 57 | this.open(callback); 58 | } 59 | 60 | private open(callback: Func) { 61 | const id = newID(); 62 | const dm = new DestroyManager(); 63 | 64 | const dialog = new Dialog({ 65 | title: this.title, 66 | content: `
`, 67 | width: events.isMobile ? "90vw" : null, 68 | height: events.isMobile ? null : null, 69 | destroyCallback() { 70 | dm.destroyBy("dialog"); 71 | }, 72 | }); 73 | dm.add("dialog", () => dialog.destroy()); 74 | 75 | const svelte = new DialogTextSv({ 76 | target: dialog.element.querySelector("#" + id), 77 | props: { 78 | dm, 79 | callback, 80 | defaultValue: this.defaultValue, 81 | alwaysConfirm: this.alwaysConfirm, 82 | description: this.description, 83 | } 84 | }); 85 | dm.add("svelte", () => svelte.$destroy()); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/DialogTextSv.svelte: -------------------------------------------------------------------------------- 1 | 47 | 48 | 49 |
50 |
51 |
52 | {description} 53 |
54 | {#if useTextArea} 55 | 74 | {:else} 75 | input.select()} 78 | placeholder={defaultValue} 79 | type="text" 80 | class="b3-text-field" 81 | bind:value={inputText} 82 | on:keypress={(event) => { 83 | if (event instanceof KeyboardEvent) { 84 | if (event.key === "Enter") { 85 | btnClick(); 86 | } 87 | } 88 | }} 89 | /> 90 | 91 | {/if} 92 |
93 |
94 | 95 | 105 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/EnumUtils.ts: -------------------------------------------------------------------------------- 1 | export type EnumItem = { key: string, value: string, idx: number, text: string } 2 | /** 3 | * enum must be like: 4 | * enum InsertPlace { 5 | here = "0#当前位置", 6 | dailynote = "1#今日笔记", 7 | subdoc = "2#子文档", 8 | } 9 | */ 10 | export class EnumUtils { 11 | private enumType: any; 12 | private _map: Map; 13 | public get map(): Map { 14 | return this._map; 15 | } 16 | private set map(value: Map) { 17 | this._map = value; 18 | } 19 | constructor(enumType: any) { 20 | this.enumType = enumType; 21 | this.map = Object.keys(this.enumType).map(key => { 22 | const value: string = enumType[key]; 23 | const parts = value.split("#"); 24 | return { 25 | key, 26 | value, 27 | idx: Number(parts[0]), 28 | text: parts[1], 29 | }; 30 | }).reduce((m, i) => { 31 | m.set(i.idx, i); 32 | return m; 33 | }, new Map()); 34 | } 35 | 36 | getItem(enumValue: string) { 37 | const parts = enumValue.split("#"); 38 | return this.map.get(Number(parts[0])); 39 | } 40 | } 41 | 42 | export function getAllEnumValues(enumObj: T): T[keyof T][] { 43 | return Object.keys(enumObj) 44 | .map(key => enumObj[key as keyof typeof enumObj]); 45 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/SelectionML.ts: -------------------------------------------------------------------------------- 1 | import { events } from "./Events"; 2 | import { PROTYLE_WYSIWYG_SELECT } from "./gconst"; 3 | import { getAttribute } from "./utils"; 4 | 5 | export class SelectionML { 6 | private selected: HTMLElement[] = []; 7 | private topElement: HTMLElement; 8 | private bottomElement: HTMLElement; 9 | private firstElement: HTMLElement; 10 | private trace: string[] = []; 11 | 12 | constructor(s: Awaited>) { 13 | this.selected = s.selected; 14 | this.firstElement = this.selected.at(0); 15 | this.topElement = this.selected.at(0); 16 | this.bottomElement = this.selected.at(-1); 17 | } 18 | 19 | private traceElement(e: Element) { 20 | e.classList.add(PROTYLE_WYSIWYG_SELECT); 21 | const id: string = getAttribute(e, "data-node-id"); 22 | if (!this.trace.includes(id)) this.trace.push(id); 23 | } 24 | 25 | private untraceElement(e: Element) { 26 | const id: string = getAttribute(e, "data-node-id"); 27 | const idx = this.trace.findIndex(i => i == id) 28 | if (idx >= 0) { 29 | this.trace.splice(idx, 1) 30 | } 31 | } 32 | 33 | private unselect(d: Element) { 34 | d.querySelectorAll("." + PROTYLE_WYSIWYG_SELECT).forEach((e) => { 35 | e.classList.remove(PROTYLE_WYSIWYG_SELECT); 36 | this.untraceElement(e); 37 | }); 38 | } 39 | 40 | private scrollIntoView(d: Element) { 41 | d.scrollIntoView({ 42 | behavior: "smooth", 43 | block: "center", 44 | }); 45 | } 46 | 47 | private selectDivUp(d: Element) { 48 | const id = getAttribute(d, "data-node-id"); 49 | if (id) { 50 | this.scrollIntoView(d); 51 | this.topElement = d as HTMLElement; 52 | this.traceElement(this.topElement) 53 | return true; 54 | } 55 | } 56 | 57 | selectUp() { 58 | if (this.trace.length == 0) this.traceElement(this.topElement) 59 | if (!this.selectDivUp(this.topElement.previousElementSibling)) { 60 | if (this.selectDivUp(this.topElement.parentElement)) { 61 | this.bottomElement = this.topElement; 62 | this.unselect(this.topElement.parentElement); 63 | this.traceElement(this.topElement) 64 | } 65 | } 66 | } 67 | 68 | private selectDivDown(d: Element) { 69 | const id = getAttribute(d, "data-node-id"); 70 | if (id) { 71 | this.scrollIntoView(d); 72 | this.bottomElement = d as HTMLElement; 73 | this.traceElement(this.bottomElement) 74 | return true; 75 | } 76 | } 77 | 78 | selectDown() { 79 | if (this.trace.length == 0) this.traceElement(this.bottomElement) 80 | if (!this.selectDivDown(this.bottomElement.nextElementSibling)) { 81 | if (this.selectDivDown(this.bottomElement.parentElement)) { 82 | this.topElement = this.bottomElement; 83 | this.unselect(this.bottomElement.parentElement); 84 | this.traceElement(this.bottomElement) 85 | } 86 | } 87 | } 88 | 89 | cancelLast() { 90 | const id = this.trace.pop(); 91 | if (id) { 92 | const e = document.querySelector(`div[data-node-id="${id}"]`) 93 | if (e) { 94 | this.scrollIntoView(e); 95 | e.classList.remove(PROTYLE_WYSIWYG_SELECT) 96 | } 97 | } 98 | 99 | if (this.trace.length == 0) { 100 | this.topElement = this.firstElement 101 | this.bottomElement = this.firstElement 102 | this.scrollIntoView(this.firstElement); 103 | this.traceElement(this.firstElement); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/bookmark.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "siyuan"; 2 | import { siyuan } from "./utils"; 3 | import { READINGPOINT } from "./gconst"; 4 | import { tomatoI18n } from "../tomatoI18n"; 5 | import { OpenSyFile2 } from "./docUtils"; 6 | 7 | export async function gotoBookmark(docID: string, plugin: Plugin) { 8 | const rows = await siyuan.sqlAttr(`select * from attributes where name='${READINGPOINT}' and root_id='${docID}'`); 9 | for (const row of rows) { 10 | await OpenSyFile2(plugin, row.block_id); 11 | break; 12 | } 13 | if (rows.length == 0) await siyuan.pushMsg(tomatoI18n.当前文档无书签, 2000); 14 | } 15 | 16 | export async function removeReadingPoint(docID: string) { 17 | const rows = await siyuan.sqlAttr(`select * from attributes where name='${READINGPOINT}' and root_id='${docID}'`); 18 | await siyuan.deleteBlocks(rows.map(row => row.block_id)); 19 | await siyuan.removeRiffCards(rows.map(row => row.block_id)); 20 | } 21 | 22 | export async function rmTodoBookmark(docID: string) { 23 | const rows = await siyuan.sqlAttr(`select * from attributes where name='bookmark' and value='🚩' and root_id='${docID}'`); 24 | await siyuan.batchSetBlockAttrs(rows.map(row => { 25 | return { id: row.block_id, attrs: { bookmark: "" } as AttrType }; 26 | })); 27 | } 28 | 29 | export async function addTodoBookmark(ids: string[]) { 30 | for (const id of ids) { 31 | const attr = await siyuan.getBlockAttrs(id); 32 | if (attr.bookmark == "🚩") 33 | await siyuan.setBlockAttrs(id, { bookmark: "" } as AttrType); 34 | else if (!attr.bookmark) 35 | await siyuan.setBlockAttrs(id, { bookmark: "🚩" } as AttrType); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/cardUtils.ts: -------------------------------------------------------------------------------- 1 | import { tomatoI18n } from "../tomatoI18n"; 2 | import { events } from "./Events"; 3 | import { CUSTOM_RIFF_DECKS } from "./gconst"; 4 | import { getAttribute, isValidNumber, siyuan, timeUtil } from "./utils"; 5 | 6 | export async function removeDocCards(docID: string) { 7 | if (!docID) return; 8 | const ids = (await siyuan.sql(`select block_id as id from attributes 9 | where name="${CUSTOM_RIFF_DECKS}" 10 | and root_id="${docID}" 11 | limit 30000 12 | `)).map(row => row.id); 13 | await siyuan.removeRiffCards(ids); 14 | } 15 | 16 | export async function doStopCards(days: string, blocks: GetCardRetBlock[], spread = false) { 17 | if (!(blocks && blocks.length)) return; 18 | const numDays = Number(days); 19 | if (isValidNumber(numDays)) { 20 | function spreadByDays(idx: number) { 21 | return (idx + 1) * (numDays / blocks.length) 22 | } 23 | await siyuan.pushMsg(tomatoI18n.开始执行) 24 | await siyuan.batchSetBlockAttrs(blocks.map((b, idx) => { 25 | const newAttrs = {} as AttrType; 26 | if (numDays <= 0) { 27 | newAttrs["custom-card-priority-stop"] = ""; 28 | newAttrs.bookmark = ""; 29 | } else { 30 | let datetimeStr: string; 31 | if (spread) { 32 | datetimeStr = timeUtil.dateFormat(timeUtil.now(spreadByDays(idx) * 24 * 60 * 60)); 33 | } else { 34 | datetimeStr = timeUtil.dateFormat(timeUtil.now(numDays * 24 * 60 * 60)); 35 | } 36 | newAttrs["custom-card-priority-stop"] = datetimeStr; 37 | newAttrs.bookmark = "🛑 Suspended Cards"; 38 | } 39 | newAttrs["custom-card-priority-id"] = b.ial.id; 40 | return { id: b.ial.id, attrs: newAttrs }; 41 | })); 42 | 43 | await siyuan.batchSetRiffCardsDueTimeByBlockID(blocks.map((b, idx) => { 44 | let due: string; 45 | if (spread) { 46 | due = timeUtil.getYYYYMMDDHHmmss(timeUtil.nowts(spreadByDays(idx) * 24 * 60 * 60)); 47 | } else { 48 | due = timeUtil.getYYYYMMDDHHmmss(timeUtil.nowts(numDays * 24 * 60 * 60)); 49 | } 50 | return { 51 | id: b.ial.id, 52 | due, 53 | }; 54 | })); 55 | 56 | setTimeout(() => { 57 | events.protyleReload(); 58 | }, 500); 59 | await siyuan.pushMsg(tomatoI18n.推迟x个闪卡y天(blocks.length, days)); 60 | } 61 | } 62 | 63 | export function showCardAnswer() { 64 | const btnSpace = document.body.querySelector('div.card__action:not(.fn__none) > button[data-type="-1"]') as HTMLButtonElement; 65 | if (btnSpace) { 66 | btnSpace.click(); 67 | return true; 68 | } 69 | return false; 70 | } 71 | 72 | export function pressSkip() { 73 | const btnSkip = document.body.querySelector('button[data-type="-3"]') as HTMLButtonElement; 74 | if (btnSkip) { 75 | btnSkip.click(); 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | export async function getIDFromCard() { 82 | const blockInDocCard = document.querySelector(`div.card__main div[data-doc-type="NodeDocument"][custom-riff-decks] > div[data-node-id]`); 83 | const subBlockID = getAttribute(blockInDocCard as any, "data-node-id"); 84 | let cardID = await siyuan.getDocIDByBlockID(subBlockID); 85 | 86 | if (!cardID) { 87 | const card = document.querySelector(`div.card__main div[data-node-id][custom-riff-decks]`); 88 | cardID = getAttribute(card as any, "data-node-id"); 89 | } 90 | return cardID; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/cozeAI.ts: -------------------------------------------------------------------------------- 1 | import { tomatoI18n } from "../tomatoI18n"; 2 | import { cozeSearchKnowledgeID, cozeSearchOauthTokenID } from "./stores"; 3 | import { chunks, getMarkdownsByTrees, siyuan } from "./utils"; 4 | 5 | async function postData(url: string, data = {}, headers = {}) { 6 | return fetch('https://api.coze.cn' + url, { 7 | method: 'POST', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | 'Authorization': 'Bearer ' + cozeSearchOauthTokenID.get(), 11 | 'Agw-Js-Conv': 'str', 12 | ...headers, 13 | }, 14 | body: JSON.stringify(data), 15 | }); 16 | } 17 | 18 | async function postGetJson(url: string, data = {}, headers = {}) { 19 | return postData(url, data, headers).then(r => r.json()) 20 | } 21 | 22 | export async function cozeAddDocTree(docID: string, boxID = "") { 23 | const rows = await getMarkdownsByTrees([docID], boxID) 24 | let name: string; 25 | if (!boxID) { 26 | for (const r of rows) { 27 | if (r.id === docID) { 28 | name = getCozeName(r.content, r.id) 29 | break 30 | } 31 | } 32 | } else { 33 | const nb = await siyuan.getNotebookConf(boxID) 34 | name = getCozeName(nb.name, boxID) 35 | } 36 | await coze_big_file(rows, name); 37 | siyuan.pushMsg(tomatoI18n.更新所有文档成功) 38 | } 39 | 40 | export function getCozeName(name: string, id: string) { 41 | return name?.replaceAll(".", "")?.slice(0, 20) + "." + id 42 | } 43 | 44 | async function coze_big_file(rows: Block[], name: string) { 45 | await cozeDeleteFromKnowledgeByName(name); 46 | const payload: any = { 47 | dataset_id: cozeSearchKnowledgeID.get(), 48 | chunk_strategy: { 49 | remove_extra_spaces: true, 50 | remove_urls_emails: true, 51 | chunk_type: 0 52 | }, 53 | format_type: 0, 54 | document_bases: [ 55 | { 56 | source_info: { 57 | file_type: "md", 58 | file_base64: encodeToBase64(rows.map(r => r.markdown).join("\n\n")), 59 | }, 60 | name, 61 | } 62 | ] 63 | }; 64 | await postGetJson("/open_api/knowledge/document/create", payload); 65 | } 66 | 67 | export async function cozeDeleteFromKnowledgeByName(name: string) { 68 | const all = await coze_get_all_files() 69 | for (const f of all) { 70 | if (f.name === name) { 71 | await postGetJson("/open_api/knowledge/document/delete", { document_ids: [f.document_id] }); 72 | } 73 | } 74 | } 75 | 76 | export async function cleanCozeDocs() { 77 | const document_ids = await coze_get_all_files().then(fs => fs.map(f => f.document_id)) 78 | for (const ids of chunks(document_ids, 10)) { 79 | await postGetJson("/open_api/knowledge/document/delete", { document_ids: ids }); 80 | } 81 | } 82 | 83 | // https://app.quicktype.io/?l=ts 84 | export async function coze_get_all_files(size = 100) { 85 | const all = [] as CozeDocumentInfo[] 86 | let page = 1; 87 | while (true) { 88 | const ret = await postGetJson("/open_api/knowledge/document/list", { 89 | "dataset_id": cozeSearchKnowledgeID.get(), 90 | "page": page++, 91 | size, 92 | }) as CozeListDoc; 93 | if (ret.document_infos) all.push(...ret.document_infos) 94 | if (all.length >= ret.total) break; 95 | if (ret.code != 0) break; 96 | } 97 | return all; 98 | } 99 | 100 | function encodeToBase64(str: string): string { 101 | const utf8Bytes = new TextEncoder().encode(str); 102 | const binaryArray = []; 103 | for (const byte of utf8Bytes) { 104 | binaryArray.push(String.fromCharCode(byte)); 105 | } 106 | const binaryString = binaryArray.join(''); 107 | return btoa(binaryString); 108 | } 109 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/destroyer.ts: -------------------------------------------------------------------------------- 1 | export class DestroyManager { 2 | private destroied = false; 3 | private cbs = new Map(); 4 | private actions: Func[] = []; 5 | private data = new Map(); 6 | private showMsg: boolean; 7 | private prefix: string; 8 | constructor(showMsg = false, prefix: string = "DestroyManager") { 9 | this.prefix = prefix; 10 | this.showMsg = showMsg; 11 | } 12 | setData(key: string, value: any) { 13 | this.data.set(key, value); 14 | } 15 | getData(key: string) { 16 | return this.data.get(key) as T; 17 | } 18 | action(cb: Func) { 19 | this.actions.push(cb); 20 | } 21 | run() { 22 | this.actions.forEach(i => i()); 23 | } 24 | add(name: string, cb: Func) { 25 | this.cbs.set(name.trim(), cb); 26 | } 27 | destroyBy(name: string = null) { 28 | if (!this.destroied) { 29 | this.destroied = true; 30 | const lst = [...this.cbs.entries()]; 31 | if (name == null) { 32 | lst.forEach(([k, v]) => { 33 | if (this.showMsg) console.info(`[${this.prefix}] DESTROY [${k}] BY NONE`); 34 | v(); 35 | }); 36 | } else { 37 | name = name.trim(); 38 | lst.filter(([k]) => k !== name).forEach(([k, v]) => { 39 | if (this.showMsg) console.info(`[${this.prefix}] DESTROY [${k}] BY [${name}]`); 40 | v(); 41 | }); 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/focusUtils.ts: -------------------------------------------------------------------------------- 1 | import { events } from "./Events"; 2 | import { awaysExitFocusStore } from "./stores"; 3 | import { isCardByUpLook } from "./utils"; 4 | 5 | export function autoExitFocus() { 6 | if (awaysExitFocusStore.get() && !events.isMobile) { 7 | setTimeout(() => { 8 | findExitFocus(); 9 | }, 1200); 10 | } 11 | } 12 | 13 | function findExitFocus() { 14 | const elements = document.querySelectorAll(`button[data-type="exit-focus"]`) as unknown as HTMLElement[]; 15 | for (const e of elements) { 16 | if (!e.classList.contains("fn__none") && !isCardByUpLook(e)) { 17 | e.click(); 18 | setTimeout(() => { 19 | doUnpin(e); 20 | }, 1000); 21 | } 22 | } 23 | } 24 | 25 | function doUnpin(e: HTMLElement) { 26 | const popover = findUpuntilPopover(e); 27 | const pinElement = popover?.querySelector("span[data-type='pin']"); 28 | if (pinElement instanceof HTMLElement) { 29 | pinElement.click(); 30 | } 31 | } 32 | 33 | function findUpuntilPopover(e: HTMLElement) { 34 | while (e) { 35 | if (e.classList.contains("block__popover--open")) { 36 | return e; 37 | } 38 | e = e.parentElement as HTMLElement; 39 | } 40 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/functional.ts: -------------------------------------------------------------------------------- 1 | export function zipNways(...arrays: T): Array<{ [K in keyof T]: T[K][number] }> { 2 | // if T[K] is string[], then T[K][number] would be string 3 | // this is equivalent to saying "give me the type of the elements inside each of the arrays in T 4 | const maxLength = Math.max(...arrays.map(arr => { 5 | if (!arr) arr = [] 6 | return arr.length 7 | })); 8 | const zipped = Array.from({ length: maxLength }, (_, rowIdx) => ( 9 | arrays.map((_, arrIdx) => arrays[arrIdx][rowIdx]) as { [K in keyof T]: T[K][number] })); 10 | return zipped; 11 | } 12 | 13 | export function flatChunkMap(array: any[], num: number, map: (ts: any[]) => M) { 14 | array = array.flat(); 15 | const newArr: M[] = []; 16 | for (let i = 0; i < array.length; i += num) { 17 | const part = array.slice(i, i + num); 18 | if (part.length > 0) { 19 | newArr.push(map(part)); 20 | } 21 | } 22 | return newArr; 23 | } 24 | 25 | export async function aFlatChunkMap(array: any[], num: number, map: (ts: any[]) => M) { 26 | return flatChunkMap(await Promise.all(array.flat()), num, map); 27 | } 28 | 29 | export function isIterable(obj: any): boolean { 30 | if (obj == null) return obj; 31 | 32 | // Check if the object has the Symbol.iterator property 33 | if (typeof obj[Symbol.iterator] === "function") { 34 | return true; 35 | } 36 | 37 | // Check if the object has the @@iterator method 38 | if (typeof obj["@@iterator"] === "function") { 39 | return true; 40 | } 41 | 42 | // If neither is present, the object is not iterable 43 | return false; 44 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/globalUtils.ts: -------------------------------------------------------------------------------- 1 | 2 | const prefix = "DaUaeWLNBpAf5CWCSZwZ4eEt3D78" 3 | 4 | export function getGlobal(key: string): T { 5 | return globalThis[prefix + key] 6 | } 7 | 8 | export function setGlobal(key: string, v: T): T { 9 | const old = globalThis[prefix + key]; 10 | globalThis[prefix + key] = v 11 | return old; 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/hash.ts: -------------------------------------------------------------------------------- 1 | export async function sha1(message: string) { 2 | const msgBuffer = new TextEncoder().encode(message); // 编码为UTF-8 3 | const hashBuffer = await crypto.subtle.digest('SHA-1', msgBuffer); // 哈希 4 | const hashArray = Array.from(new Uint8Array(hashBuffer)); // 转换为字节数组 5 | const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // 转换为十六进制 6 | return hashHex; 7 | } 8 | 9 | /** 10 | * 左移循环(32位) 11 | */ 12 | function rotl32(x: number, r: number): number { 13 | return (x << r) | (x >>> (32 - r)); 14 | } 15 | 16 | /** 17 | * 最终混音步骤 18 | */ 19 | function mixmur3(h: number): number { 20 | h = h ^ (h >>> 16); 21 | h = (h * 0x85ebca6b) >>> 0; 22 | h = h ^ (h >>> 13); 23 | h = (h * 0xc2b2ae35) >>> 0; 24 | h = h ^ (h >>> 16); 25 | return h; 26 | } 27 | 28 | /** 29 | * MurmurHash3 32位版本简化实现 30 | * @param input 字符串或字节数组 31 | * @param seed 初始种子值,默认为 0x1BD11DBA 32 | * @returns 32位无符号整数哈希值 33 | */ 34 | export function murmurHash3(input: string | Uint8Array, seed: number = 0x1BD11DBA): number { 35 | let data: Uint8Array; 36 | 37 | // 将字符串转换为 UTF-8 编码的 Uint8Array 38 | if (typeof input === 'string') { 39 | data = new TextEncoder().encode(input); 40 | } else { 41 | data = input; 42 | } 43 | 44 | let h1 = seed; 45 | const len = data.length; 46 | const nblocks = Math.floor(len / 4); // 每 4 字节为一块 47 | 48 | const c1 = 0xcc9e2d51; 49 | const c2 = 0x1b873593; 50 | 51 | // 处理每一块(4 字节) 52 | for (let i = 0; i < nblocks; i++) { 53 | const i4 = i * 4; 54 | let k1 = data[i4] | (data[i4 + 1] << 8) | (data[i4 + 2] << 16) | (data[i4 + 3] << 24); 55 | 56 | k1 = (k1 * c1) >>> 0; 57 | k1 = rotl32(k1, 15); 58 | k1 = (k1 * c2) >>> 0; 59 | 60 | h1 ^= k1; 61 | h1 = rotl32(h1, 13); 62 | h1 = (h1 * 5 + 0xe6546b64) >>> 0; 63 | } 64 | 65 | // 处理剩余部分(不足 4 字节) 66 | const remaining = len % 4; 67 | let k1 = 0; 68 | 69 | if (remaining > 0) { 70 | switch (remaining) { 71 | case 3: 72 | k1 ^= (data[len - 3] << 16) >>> 0; 73 | k1 ^= (data[len - 2] << 8) >>> 0; 74 | k1 ^= data[len - 1]; 75 | break; 76 | case 2: 77 | k1 ^= (data[len - 2] << 8) >>> 0; 78 | k1 ^= data[len - 1]; 79 | break; 80 | case 1: 81 | k1 ^= data[len - 1]; 82 | break; 83 | } 84 | 85 | k1 = (k1 * c1) >>> 0; 86 | k1 = rotl32(k1, 15); 87 | k1 = (k1 * c2) >>> 0; 88 | 89 | h1 ^= k1; 90 | } 91 | 92 | // 最终混音 93 | h1 ^= len; 94 | h1 = mixmur3(h1); 95 | 96 | return h1 >>> 0; // 返回 32 位无符号整数 97 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/ial.ts: -------------------------------------------------------------------------------- 1 | enum ParseState { 2 | Start, // 等待开始标记 3 | InTag, // 已进入标签 4 | AttrKey, // 正在读取属性名 5 | PreValue, // 等待等号后的引号 6 | AttrValue, // 正在读取属性值 7 | AfterValue // 值读取完成后的状态 8 | } 9 | 10 | interface ParseResult { 11 | [key: string]: string; 12 | } 13 | 14 | export function parseCustomTag(s: string): ParseResult { 15 | let state: ParseState = ParseState.Start; 16 | const result: ParseResult = {}; 17 | let currentKey = ''; 18 | let currentValue = ''; 19 | let quoteChar: '"' | "'" | null = null; 20 | const stack: string[] = []; // 用于检测标签边界 21 | 22 | for (const c of s) { 23 | switch (state) { 24 | case ParseState.Start: 25 | if (c === '{') { 26 | stack.push(c); 27 | } else if (stack.length > 0 && c === ':' && stack[stack.length - 1] === '{') { 28 | state = ParseState.InTag; 29 | stack.length = 0; // 清空栈 30 | } 31 | break; 32 | 33 | case ParseState.InTag: 34 | if (c === '}') { 35 | if (stack.length > 0 && stack[stack.length - 1] === ':') { 36 | stack.pop(); 37 | return result; // 提前结束解析 38 | } 39 | } else if (c === ':') { 40 | stack.push(c); 41 | } else if (!/\s/.test(c)) { // 非空白字符开始新属性 42 | state = ParseState.AttrKey; 43 | currentKey = c; 44 | } 45 | break; 46 | 47 | case ParseState.AttrKey: 48 | if (c === '=' || /\s/.test(c)) { 49 | state = ParseState.PreValue; 50 | } else { 51 | currentKey += c; 52 | } 53 | break; 54 | 55 | case ParseState.PreValue: 56 | if (c === '"' || c === "'") { 57 | quoteChar = c; 58 | state = ParseState.AttrValue; 59 | currentValue = ''; 60 | } 61 | break; 62 | 63 | case ParseState.AttrValue: 64 | if (c === quoteChar) { 65 | result[currentKey.trim()] = currentValue; 66 | currentKey = ''; 67 | state = ParseState.AfterValue; 68 | } else { 69 | currentValue += c; 70 | } 71 | break; 72 | 73 | case ParseState.AfterValue: 74 | if (c === '}') { 75 | if (stack.length > 0 && stack[stack.length - 1] === ':') { 76 | return result; 77 | } 78 | } else if (/\s/.test(c)) { 79 | state = ParseState.InTag; // 准备读取下一个属性 80 | } else if (c === ':') { 81 | stack.push(c); 82 | } 83 | break; 84 | } 85 | } 86 | 87 | return result; 88 | } 89 | 90 | 91 | // 测试用例 92 | // const testStr = '{: custom-tomatoUpdated="1748308949028" id="20250526082838-qq7xnww" title="2025-05-26-周一" }'; 93 | // console.log(parseCustomTag(testStr)); 94 | /* 输出: 95 | { 96 | "custom-tomatoUpdated": "1748308949028", 97 | "id": "20250526082838-qq7xnww", 98 | "title": "2025-05-26-周一" 99 | } 100 | */ 101 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/keyboard.ts: -------------------------------------------------------------------------------- 1 | export function escOnElement(e: HTMLElement) { 2 | if (e) { 3 | const escEvent = new KeyboardEvent("keydown", { 4 | key: "Escape", 5 | code: "Escape", 6 | charCode: 27, 7 | keyCode: 27, 8 | view: window, 9 | bubbles: true, 10 | }); 11 | e.dispatchEvent(escEvent); 12 | } 13 | } 14 | 15 | export function closeAllDialog() { 16 | document.querySelectorAll(`svg.b3-dialog__close`).forEach(e => click(e)); 17 | } 18 | 19 | export function click(e: Node) { 20 | if (!e?.dispatchEvent) return; 21 | e.dispatchEvent(new MouseEvent('click', { 22 | bubbles: true, 23 | cancelable: true, 24 | view: window 25 | })); 26 | } 27 | 28 | export function preventKeyboard(event: KeyboardEvent) { 29 | // $autoRefreshChecked = false; 30 | if (event.defaultPrevented) { 31 | return; 32 | } 33 | if (event.ctrlKey && event.key == "c") { 34 | return; 35 | } 36 | event.preventDefault(); 37 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/openAI.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from 'openai'; 2 | import { cancelSuperBlock, NewNodeID, Siyuan, siyuan, } from './utils'; 3 | import { Stream } from 'openai/streaming'; 4 | import { ChatCompletionChunk, ChatCompletionMessageParam } from 'openai/resources/chat/completions'; 5 | 6 | export class OpenAIClient { 7 | private openai: OpenAI; 8 | constructor(apiKey: string, baseURL: string) { 9 | this.openai = new OpenAI({ 10 | apiKey, 11 | baseURL, 12 | dangerouslyAllowBrowser: true, 13 | }); 14 | } 15 | 16 | static async getModel(key: string, baseURL: string, model: string, noSup = false) { 17 | const openAI = new OpenAIClient(key, baseURL); 18 | return (prompt: string, anchorID = "") => { 19 | return openAI.do_completions(model, prompt, anchorID, noSup) 20 | }; 21 | } 22 | 23 | static getOfficalModel(noSup = false) { 24 | const aiCfg = Siyuan.config?.ai?.openAI; 25 | if (aiCfg.apiBaseURL && aiCfg.apiModel) { 26 | const openAI = new OpenAIClient(aiCfg.apiKey, aiCfg.apiBaseURL); 27 | return (prompt: string, anchorID = "") => { 28 | return openAI.do_completions(Siyuan.config.ai.openAI.apiModel, prompt, anchorID, noSup) 29 | }; 30 | } 31 | } 32 | 33 | private async do_completions(model: string, useInputTxt: string, anchorID: string, noSup: boolean) { 34 | let aiRespTxt: string; 35 | let texts: string[] = []; 36 | let reasoning_texts: string[] = []; 37 | let stream: Stream; 38 | const messages: ChatCompletionMessageParam[] = [{ role: "user", content: useInputTxt }] 39 | try { 40 | stream = await this.openai.chat.completions.create({ 41 | model, 42 | messages, 43 | stream: true, 44 | }); 45 | } catch (e) { 46 | console.error(e, messages) 47 | return; 48 | } 49 | 50 | let targetID = ""; 51 | if (anchorID) { 52 | targetID = NewNodeID(); 53 | await siyuan.insertBlockAfter(`{: id="${targetID}"}`, anchorID); 54 | } 55 | 56 | const write = () => { 57 | if (targetID) { 58 | return siyuan.safeUpdateBlock( 59 | targetID, 60 | `{{{row\n\n${aiRespTxt}\n\n}}}\n{: id="${targetID}" custom-ai-response="1"}`, 61 | ); 62 | } 63 | } 64 | 65 | let i = 0; 66 | for await (const chunk of stream) { 67 | const delta = chunk.choices?.at(0)?.delta; 68 | texts.push(delta?.content ?? ""); 69 | reasoning_texts.push((delta as any)?.reasoning_content ?? ""); 70 | aiRespTxt = texts.join("").trim(); 71 | if (!aiRespTxt) { 72 | const reasoning = reasoning_texts.join("").trim(); 73 | if (reasoning) { 74 | aiRespTxt = reasoning; 75 | } else { 76 | aiRespTxt = `thinking ${i}...` 77 | } 78 | } 79 | if (i++ % 50 === 0) await write(); 80 | } 81 | 82 | if (aiRespTxt.startsWith("")) { 83 | const div = document.createElement("div") 84 | div.innerHTML = aiRespTxt; 85 | const t = div.querySelector("think") 86 | div.removeChild(t); 87 | aiRespTxt = div.innerHTML; 88 | } 89 | 90 | await write(); 91 | if (noSup && targetID) { 92 | await cancelSuperBlock(targetID); 93 | } 94 | return { targetID, aiRespTxt }; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/progressive.ts: -------------------------------------------------------------------------------- 1 | import { TEMP_CONTENT } from "./gconst"; 2 | import { siyuan } from "./utils"; 3 | 4 | export async function getBookIDByBlock(blockID: string) { 5 | const docRow = await siyuan.getDocRowByBlockID(blockID); 6 | return getBookID(docRow?.id); 7 | } 8 | 9 | export async function getBookID(docID: string): Promise<{ bookID: string, pieceNum: number }> { 10 | const ret = { bookID: "", pieceNum: NaN } as Awaited>; 11 | if (docID) { 12 | const attrs = await siyuan.getBlockAttrs(docID); 13 | let mark = attrs["custom-progmark"]; 14 | const writing = attrs["custom-book-writing"] 15 | if (mark) { 16 | mark = mark.split(TEMP_CONTENT).pop(); 17 | const last = mark.split("#").pop(); 18 | const parts = last.split(","); 19 | ret.bookID = parts[0]; 20 | ret.pieceNum = Number(parts[1]); 21 | } else if (writing) { 22 | const parts = writing.split("#"); 23 | ret.bookID = parts[0] 24 | ret.pieceNum = parseInt(parts.pop(), 10); 25 | } 26 | } 27 | return ret; 28 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/search.ts: -------------------------------------------------------------------------------- 1 | enum SearchEngineConditionTypeOr { 2 | include = "inc", 3 | exclude = "exc", 4 | } 5 | enum SearchEngineConditionType { 6 | include = "inc", 7 | or = "or", 8 | exclude = "exc", 9 | } 10 | 11 | type SearchEngineConditionOr = { type: SearchEngineConditionTypeOr, value: string } 12 | type SearchEngineCondition = { type: SearchEngineConditionType, value: string, values: SearchEngineConditionOr[] } 13 | 14 | export class SearchEngine { 15 | private conditions: SearchEngineCondition[] = []; 16 | private isCaseInsensitive: boolean; 17 | 18 | constructor(isCaseInsensitive: boolean) { 19 | this.isCaseInsensitive = isCaseInsensitive; 20 | } 21 | 22 | setQuery(query: string) { 23 | if (this.isCaseInsensitive) 24 | query = query.toLowerCase(); 25 | this.conditions = query.trim().replace(/[!!]+/g, "!").replace(/\s+/, " ") 26 | .replace(/ ?\| ?/g, "|").split(" ").filter(c => c.length > 0) 27 | .filter(c => c != "!").filter(c => c != "|").map(c => { 28 | const con = c.split("|").map(c => c.trim()).filter(c => c.length > 0); 29 | const ret = {} as SearchEngineCondition; 30 | if (con.length == 1) { 31 | const s = con[0]; 32 | if (s[0] == "!") { 33 | ret.type = SearchEngineConditionType.exclude; 34 | ret.value = s.slice(1); 35 | } else { 36 | ret.type = SearchEngineConditionType.include; 37 | ret.value = s; 38 | } 39 | } else { 40 | ret.type = SearchEngineConditionType.or; 41 | ret.values = con.map(c => { 42 | const ret = {} as SearchEngineConditionOr; 43 | if (c[0] == "!") { 44 | ret.type = SearchEngineConditionTypeOr.exclude; 45 | ret.value = c.slice(1); 46 | } else { 47 | ret.type = SearchEngineConditionTypeOr.include; 48 | ret.value = c; 49 | } 50 | return ret; 51 | }); 52 | } 53 | return ret; 54 | }).filter(c => { 55 | if (c.type == SearchEngineConditionType.or) { 56 | if (c.values.length == 0) return false; 57 | } 58 | return true; 59 | }); 60 | } 61 | 62 | jsonCon() { 63 | return JSON.stringify(this.conditions); 64 | } 65 | 66 | match(text: string): boolean { 67 | if (this.isCaseInsensitive) 68 | text = text.toLowerCase(); 69 | for (const con of this.conditions) { 70 | if (con.type == SearchEngineConditionType.include) { 71 | if (!text.includes(con.value)) return false; 72 | } else if (con.type == SearchEngineConditionType.exclude) { 73 | if (text.includes(con.value)) return false; 74 | } else if (con.type == SearchEngineConditionType.or) { 75 | let flag = false; 76 | for (const subCon of con.values) { 77 | if (subCon.type == SearchEngineConditionTypeOr.exclude) { 78 | if (!text.includes(subCon.value)) { 79 | flag = true; 80 | break; 81 | } 82 | } else if (subCon.type == SearchEngineConditionTypeOr.include) { 83 | if (text.includes(subCon.value)) { 84 | flag = true; 85 | break; 86 | } 87 | } 88 | } 89 | if (!flag) return false; 90 | } 91 | } 92 | return true; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/switchDraft.ts: -------------------------------------------------------------------------------- 1 | import { IProtyle, Plugin } from "siyuan"; 2 | import { OpenSyFile2, isReadonly } from "./docUtils"; 3 | import { events } from "./Events"; 4 | import { storeNoteBox_fastnote, fastNoteBoxDelAfterCreating, fastNoteBoxAdd2Flashcard } from "./stores"; 5 | import { verifyKeyTomato } from "./user"; 6 | import { siyuan, getContextPath, cloneCleanDiv, NewLute, NewNodeID, timeUtil } from "./utils"; 7 | 8 | export async function switchDraft(plugin: Plugin, protyle: IProtyle) { 9 | const docID = protyle?.block?.rootID; 10 | if (!docID) return; 11 | const title = protyle.title?.editElement?.textContent 12 | const bt = `backside-${title}`; 13 | const attrs = await siyuan.getBlockAttrs(docID); 14 | let draftID = attrs["custom-fastdraft"]; 15 | let isFastNote = !!attrs["custom-fastnote"]; 16 | if (await siyuan.checkBlockExist(draftID)) { 17 | await OpenSyFile2(plugin, draftID); 18 | if (isFastNote) { 19 | //close docID 20 | // document.querySelectorAll("span.item__text").forEach((e: HTMLElement) => { 21 | // if (e.textContent === title) { 22 | // const s = e.nextElementSibling as HTMLButtonElement; 23 | // if (s?.click) s.click(); 24 | // } 25 | // }); 26 | } else { 27 | await siyuan.setBlockAttrs(draftID, { title: bt }) 28 | } 29 | } else { 30 | const newID = await createNote(plugin, protyle, false, { 31 | "custom-fastdraft": docID, 32 | "custom-off-tomatobacklink": "1", 33 | }, bt) 34 | await siyuan.setBlockAttrs(docID, { "custom-fastdraft": newID }); 35 | } 36 | } 37 | 38 | 39 | export async function createNote(plugin: Plugin, protyle: IProtyle, allowFlashcard = true, attrs: AttrType = {}, title = "") { 40 | let boxID = storeNoteBox_fastnote.getOr(); 41 | if (!boxID || !protyle) return; 42 | const { selected, ids, cursorOnly } = await events.selectedDivs(protyle); 43 | if (ids.length <= 0) return; 44 | 45 | const { getPathMd } = await getContextPath(ids[0]); 46 | const path = `${getPathMd()}\n{: id="${NewNodeID()}"}\n` 47 | const lute = NewLute(); 48 | const content = selected.map(d => { 49 | d = cloneCleanDiv(d).div 50 | return lute.BlockDOM2Md(d.outerHTML); 51 | }); 52 | const taskRo = isReadonly(protyle) 53 | const id = await createAndOpenFastNote(boxID, plugin, attrs, title, path + content.join("\n")); 54 | if (await verifyKeyTomato() && fastNoteBoxDelAfterCreating.get() && await taskRo === "false" && !cursorOnly) await siyuan.transactions(siyuan.transDeleteBlocks(ids)); 55 | if (fastNoteBoxAdd2Flashcard.get() && allowFlashcard) { 56 | setTimeout(() => { 57 | siyuan.addRiffCards([id]) 58 | }, 800); 59 | } 60 | return id; 61 | } 62 | 63 | export async function createAndOpenFastNote(boxID: string, plugin: Plugin, attrs: AttrType = {}, title: string = "", md = "") { 64 | const { y, M, d, h, m, s } = timeUtil.nowYMDStrPad(); 65 | if (!title) title = `f${y}-${M}-${d} ${h}:${m}:${s}`; 66 | const hpath = `/fast note/f${y}/f${y}-${M}/${title}`; 67 | const id = await siyuan.createDocWithMdIfNotExists(boxID, hpath, md, { ...attrs, "custom-fastnote": y + M + d + h + m + s }); 68 | await OpenSyFile2(plugin, id); 69 | return id; 70 | } 71 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/text11.ts: -------------------------------------------------------------------------------- 1 | import { TomatoI18nABCMAX } from "./gconst"; 2 | 3 | export abstract class TomatoI18nABC11 extends TomatoI18nABCMAX { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/timer.ts: -------------------------------------------------------------------------------- 1 | export function measureTime(func: Func, name = "Function"): number { 2 | const start = performance.now(); 3 | func(); 4 | const end = performance.now(); 5 | const elapsedTime = end - start 6 | console.info(`${name} took ${elapsedTime} milliseconds to run.`); 7 | return elapsedTime; 8 | } 9 | 10 | // console.time('myFunction'); 11 | // myFunction(); 12 | // console.timeEnd('myFunction'); 13 | 14 | /** 15 | const timer = new Timer(); 16 | myFunction(); 17 | const elapsedTime = timer.stop(); 18 | */ 19 | export class Timer { 20 | private startTime: number; 21 | private name: string; 22 | 23 | constructor(name = "Function") { 24 | this.startTime = performance.now(); 25 | this.name = name; 26 | } 27 | 28 | public stop(): number { 29 | const endTime = performance.now(); 30 | const elapsedTime = endTime - this.startTime 31 | console.info(`${this.name} took ${elapsedTime} milliseconds to run.`); 32 | return elapsedTime; 33 | } 34 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/tools.ts: -------------------------------------------------------------------------------- 1 | import { siyuan } from "./utils"; 2 | 3 | export function calcAge(age: string, blockID: string) { 4 | const { years, months, days } = calculateAge(age); 5 | siyuan.insertBlockAfter(`${years}岁${months}月${days}天`, blockID) 6 | } 7 | 8 | function calculateAge(birthday: string): { years: number, months: number, days: number } { 9 | // Parse the birthday string into Date object 10 | const birthDate = new Date(`${birthday.substring(0, 4)}-${birthday.substring(4, 6)}-${birthday.substring(6, 8)}`); 11 | 12 | // Check if the birthDate is valid 13 | if (isNaN(birthDate.getTime())) { 14 | throw new Error('Invalid birthday format'); 15 | } 16 | 17 | // Get today's date 18 | const today = new Date(); 19 | 20 | // Calculate the difference in years, months, and days 21 | let years = today.getFullYear() - birthDate.getFullYear(); 22 | let months = today.getMonth() - birthDate.getMonth(); 23 | let days = today.getDate() - birthDate.getDate(); 24 | 25 | // Adjust the values if necessary 26 | if (days < 0) { 27 | // Borrow a month 28 | months -= 1; 29 | // Get the last day of the previous month 30 | const lastDayOfPrevMonth = new Date(today.getFullYear(), today.getMonth(), 0).getDate(); 31 | days += lastDayOfPrevMonth; 32 | } 33 | 34 | if (months < 0) { 35 | // Borrow a year 36 | years -= 1; 37 | months += 12; 38 | } 39 | 40 | return { years, months, days }; 41 | } 42 | 43 | export function getDirectTextContent(element: Element) { 44 | const text = new Str(); 45 | for (let child of element.childNodes) { 46 | if (child.nodeType === Node.TEXT_NODE) { 47 | text.add(child.textContent) 48 | } 49 | } 50 | return text.join() 51 | } 52 | 53 | export class Str { 54 | private data: T[]; 55 | constructor(data: T[] = []) { 56 | this.data = data; 57 | } 58 | add(...items: T[]): void { 59 | this.data.push(...items); 60 | } 61 | join(separator: string = ''): string { 62 | return this.data.join(separator); 63 | } 64 | static safeJoin(arr: T[] | null | undefined, separator: string = ''): string { 65 | if (arr == null) return ''; 66 | return Array.isArray(arr) ? arr.join(separator) : ''; 67 | } 68 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/types.ts: -------------------------------------------------------------------------------- 1 | export function isSortType(value: any): value is SortType { 2 | return Object.values(SortType).includes(value); 3 | } 4 | 5 | export enum SortType { 6 | NameASC = "0", // 0:文件名字母升序 7 | NameDESC = "1", // 1:文件名字母降序 8 | UpdatedASC = "2", // 2:文件更新时间升序 9 | UpdatedDESC = "3", // 3:文件更新时间降序 10 | AlphanumASC = "4", // 4:文件名自然数升序 11 | AlphanumDESC = "5", // 5:文件名自然数降序 12 | Custom = "6", // 6:自定义排序 13 | RefCountASC = "7", // 7:引用数升序 14 | RefCountDESC = "8", // 8:引用数降序 15 | CreatedASC = "9", // 9:文件创建时间升序 16 | CreatedDESC = "10", // 10:文件创建时间降序 17 | SizeASC = "11", // 11:文件大小升序 18 | SizeDESC = "12", // 12:文件大小降序 19 | SubDocCountASC = "13", // 13:子文档数升序 20 | SubDocCountDESC = "14", // 14:子文档数降序 21 | FileTree = "15", // 15:使用文档树排序规则 22 | Unassigned = "256", // 256:未指定排序规则,按照笔记本优先于文档树获取排序规则 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/libs/user.ts: -------------------------------------------------------------------------------- 1 | import { ec as EC } from 'elliptic'; 2 | import { getMd5, siyuan, Siyuan, timeUtil } from './utils'; 3 | import { userID, userToken, writableWithGet } from './stores'; 4 | 5 | const MY_PUBKEY = "044ad3bfb46f3b89979dd551a5dada23f8502f8a0c54d247e1f8d31e5d7705a978df1ef30ba5a4b5206f0b0f573c8f76feada715f949430187f62f5640ca144aa7"; 6 | const ec = new EC('secp256k1'); 7 | const keyPair = ec.keyFromPublic(MY_PUBKEY, 'hex') 8 | let _isValid: boolean = null; 9 | 10 | export function lastVerifyResult(): boolean { 11 | return _isValid; 12 | } 13 | 14 | export const expStore = writableWithGet("") 15 | 16 | export function getUserCodeExp(_exp: string) { 17 | if (!_exp) return "" 18 | return `${_exp.slice(0, 4)} / ${_exp.slice(4, 6)} / ${_exp.slice(6)}` 19 | } 20 | 21 | export function isMe() { 22 | return Siyuan?.user?.userId === "1656951563417"; 23 | } 24 | 25 | export function resetKey() { 26 | _isValid = null; 27 | } 28 | 29 | export async function verifyKeyTomato() { 30 | return verifyKey("_siyuanTomatoCode_") 31 | } 32 | 33 | export async function verifyKeyProgressive() { 34 | return verifyKey("_siyuanProgressiveCode_") 35 | } 36 | 37 | async function verifyKey(included: string) { 38 | if (_isValid != null) return _isValid; 39 | 40 | let v = await verifyUserSign(userToken.get(), included); 41 | if (!v.valid) { 42 | const FREE_KEY = "freeze7XSGUQr_20250531_name_siyuanTomatoCode_30450221009c482f5a144f605dca52c5c9991501eb98d281755435d6316e666820c718f7ad02207e175822e94fc88fd397bd14f497d123815b91c7d43935a683e26d6bc99c1f76"; 43 | userToken.set(FREE_KEY); 44 | v = await verifyUserSign(FREE_KEY, "_siyuanTomatoCode_"); 45 | } 46 | _isValid = v.valid; 47 | return _isValid; 48 | } 49 | 50 | async function verifyUserSign(tokenSign: string, included: string) { 51 | let signValid = false; 52 | let userPart = ""; 53 | let userPartShort = ""; 54 | let exp = ""; 55 | let ldID = ""; 56 | let name = ""; 57 | { 58 | // 1656951563417_22240101_ldID_siyuanTomatoCode_30qqqqqqqqqqqqqq.. 59 | const parts = tokenSign?.split(included); 60 | if (parts?.length === 2) { 61 | userPartShort = parts[0]; 62 | userPart = userPartShort + included; 63 | const sign = parts[1]; 64 | try { 65 | const msgHash = getMd5(userPart) 66 | signValid = keyPair.verify(msgHash, sign); 67 | } catch { 68 | signValid = false; 69 | } 70 | } 71 | } 72 | { 73 | // freecbly0fNG4_20241206_name 74 | // 1656951563417_22240101_ldID 75 | const ps = userPartShort.split("_") 76 | if (ps.length === 3) { 77 | exp = ps[1]; 78 | if (ps[2] === "ldID") { 79 | ldID = ps[0]; 80 | } else if (ps[2] === "name") { 81 | name = ps[0]; 82 | } 83 | } 84 | } 85 | if (signValid) { 86 | signValid = await checkUserID(ldID, name, exp); 87 | } 88 | 89 | if ([ 90 | "", 91 | // "402f82671ae66425e07eaa0a47c5128723383ff0", 92 | // "9d07cd325209e7739fe04da41b2b7887e097b268", 93 | // "5f6df12238cfea797f8c73309dfcf3445fd99d28", 94 | // "1e4b90d2e70cc02b29ad5232094d6ca6a4853366", 95 | ].includes(getMd5(userPartShort))) signValid = false; 96 | 97 | if (included && !tokenSign.includes(included)) signValid = false; 98 | return { exp, valid: signValid }; 99 | } 100 | 101 | async function checkUserID(ldID: string, name: string, exp: string) { 102 | const ms = await siyuan.currentTimeMs(); 103 | const { y, M, d } = timeUtil.nowYMDStrPad(new Date(ms)); 104 | const nowStr = y + M + d; 105 | expStore.set(getUserCodeExp(exp)); 106 | if (nowStr <= exp) { 107 | if (ldID) { 108 | return ldID === userID.get(); 109 | } else if (name) { 110 | return true; 111 | } 112 | } 113 | return false; 114 | } 115 | -------------------------------------------------------------------------------- /sy-tomato-plugin/src/types/baidu.d.ts: -------------------------------------------------------------------------------- 1 | // https://app.quicktype.io/?l=ts 2 | 3 | interface AIResponse { 4 | id: string; 5 | object: string; 6 | created: number; 7 | result: string; 8 | sentence_id: number; 9 | is_end: boolean; 10 | is_truncated: boolean; 11 | need_clear_history: boolean; 12 | finish_reason: string; 13 | usage: Usage; 14 | } 15 | 16 | interface Usage { 17 | prompt_tokens: number; 18 | completion_tokens: number; 19 | total_tokens: number; 20 | } 21 | 22 | interface CalcTokensResponse { 23 | id: string; 24 | object: string; 25 | created: number; 26 | usage: CalcTokenUsage; 27 | } 28 | 29 | interface CalcTokenUsage { 30 | prompt_tokens: number; 31 | total_tokens: number; 32 | } 33 | 34 | type ChatRole = "user" | "assistant" 35 | type Chat = { role: ChatRole, content: string, tokens: number } 36 | 37 | interface AppConversationRunsResp { 38 | request_id: string; 39 | date: Date; 40 | answer: string; 41 | conversation_id: string; 42 | message_id: string; 43 | is_completion: null; 44 | content: AppConversationRunsContent[]; 45 | } 46 | 47 | interface AppConversationRunsContent { 48 | result_type: string; 49 | event_code: number; 50 | event_message: string; 51 | event_type: string; 52 | event_id: string; 53 | event_status: string; 54 | content_type: string; 55 | visible_scope: string; 56 | outputs: AppConversationRunsContentOutputs; 57 | usage?: AppConversationRunsContentUsage; 58 | } 59 | 60 | interface AppConversationRunsContentOutputs { 61 | text?: AppConversationRunsContentTextClass | string; 62 | name_cn?: string; 63 | references?: AppConversationRunsContentReference[]; 64 | } 65 | 66 | interface AppConversationRunsContentReference { 67 | id: string; 68 | content: string; 69 | type: string; 70 | from: string; 71 | title: string; 72 | segment_id: string; 73 | document_id: string; 74 | document_name: string; 75 | dataset_name: string; 76 | dataset_id: string; 77 | } 78 | 79 | interface AppConversationRunsContentTextClass { 80 | arguments: AppConversationRunsContentArguments; 81 | component_code: string; 82 | component_name: string; 83 | } 84 | 85 | interface AppConversationRunsContentArguments { 86 | origin_query: string; 87 | } 88 | 89 | interface AppConversationRunsContentUsage { 90 | prompt_tokens: number; 91 | completion_tokens: number; 92 | total_tokens: number; 93 | name: string; 94 | type: string; 95 | } 96 | 97 | interface DescribeDocumentsResp { 98 | requestId: string; 99 | marker: string; 100 | isTruncated: boolean; 101 | nextMarker: string; 102 | maxKeys: number; 103 | data: DescribeDocumentsDocument[]; 104 | } 105 | 106 | interface DescribeDocumentsDocument { 107 | id: string; 108 | name: string; 109 | sy_doc_id: string; 110 | sy_exists: boolean; 111 | createdAt: number; 112 | wordCount: number; 113 | enabled: boolean; 114 | meta: DescribeDocumentsMeta; 115 | } 116 | 117 | interface DescribeDocumentsMeta { 118 | source: string; 119 | fileId: string; 120 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | const NoWarns = new Set([ 4 | "a11y-click-events-have-key-events", 5 | "a11y-no-static-element-interactions", 6 | "a11y-no-noninteractive-element-interactions" 7 | ]); 8 | 9 | export default { 10 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 11 | // for more information about preprocessors 12 | preprocess: vitePreprocess(), 13 | onwarn: (warning, handler) => { 14 | // suppress warnings on `vite dev` and `vite build`; but even without this, things still work 15 | if (NoWarns.has(warning.code)) return; 16 | handler(warning); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /sy-tomato-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": [ 7 | "ES2022", 8 | "DOM", 9 | "DOM.Iterable" 10 | ], 11 | "skipLibCheck": true, 12 | /* Bundler mode */ 13 | "moduleResolution": "Node", 14 | // "allowImportingTsExtensions": true, 15 | "allowSyntheticDefaultImports": true, 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "noEmit": true, 19 | "jsx": "preserve", 20 | /* Linting */ 21 | "strict": false, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true, 25 | /* Svelte */ 26 | /** 27 | * Typecheck JS in `.svelte` and `.js` files by default. 28 | * Disable checkJs if you'd like to use dynamic types in JS. 29 | * Note that setting allowJs false does not prevent the use 30 | * of JS in `.svelte` files. 31 | */ 32 | "allowJs": true, 33 | "checkJs": true, 34 | "types": [ 35 | "node", 36 | // "vite/client", 37 | // "svelte" 38 | ], 39 | // "baseUrl": "./src", 40 | // "paths": { 41 | // "@/*": ["./src/*"], 42 | // "@/libs/*": ["./src/libs/*"], 43 | // }, 44 | "typeRoots": [ 45 | "./src/types", 46 | "./node_modules/@types" 47 | ], 48 | }, 49 | "include": [ 50 | "src/**/*.ts", 51 | "src/**/*.d.ts", 52 | "src/**/*.svelte", 53 | ], 54 | "exclude": [ 55 | "node_modules" 56 | ], 57 | "references": [ 58 | { 59 | "path": "./tsconfig.node.json" 60 | } 61 | ], 62 | "root": "." 63 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": [ 10 | "vite.config.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /sy-tomato-plugin/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { defineConfig } from "vite"; 3 | import minimist from "minimist"; 4 | import { viteStaticCopy } from "vite-plugin-static-copy"; 5 | import livereload from "rollup-plugin-livereload"; 6 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 7 | import zipPack from "vite-plugin-zip-pack"; 8 | import fg from "fast-glob"; 9 | 10 | const args = minimist(process.argv.slice(2)); 11 | const isWatch = args.watch || args.w || false; 12 | // const devDistDir = "./dev"; 13 | // const distDir = isWatch ? devDistDir : "./dist"; 14 | // console.info("isWatch=>", isWatch); 15 | // console.info("distDir=>", distDir); 16 | const devDistDir = process.env.SYPLUGINDIR ? process.env.SYPLUGINDIR + "/sy-tomato-plugin" : "build"; 17 | const distDir = devDistDir; 18 | 19 | export default defineConfig({ 20 | resolve: { 21 | alias: { 22 | "@": resolve(__dirname, "src"), 23 | }, 24 | }, 25 | 26 | plugins: [ 27 | svelte(), 28 | viteStaticCopy({ 29 | targets: [ 30 | { 31 | src: "./README*.md", 32 | dest: "./", 33 | }, 34 | { 35 | src: "./icon.png", 36 | dest: "./", 37 | }, 38 | { 39 | src: "./preview.png", 40 | dest: "./", 41 | }, 42 | { 43 | src: "./plugin.json", 44 | dest: "./", 45 | }, 46 | { 47 | src: "./src/i18n/**", 48 | dest: "./i18n/", 49 | }, 50 | ], 51 | }), 52 | ], 53 | 54 | // https://github.com/vitejs/vite/issues/1930 55 | // https://vitejs.dev/guide/env-and-mode.html#env-files 56 | // https://github.com/vitejs/vite/discussions/3058#discussioncomment-2115319 57 | // 在这里自定义变量 58 | define: { 59 | "process.env.DEV_MODE": `"${isWatch}"`, 60 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), 61 | }, 62 | 63 | build: { 64 | // 输出路径 65 | outDir: distDir, 66 | emptyOutDir: false, 67 | 68 | // 构建后是否生成 source map 文件 69 | sourcemap: false, 70 | 71 | // 设置为 false 可以禁用最小化混淆 72 | // 或是用来指定是应用哪种混淆器 73 | // boolean | 'terser' | 'esbuild' 74 | minify: isWatch ? false : "esbuild", 75 | 76 | lib: { 77 | // Could also be a dictionary or array of multiple entry points 78 | entry: resolve(__dirname, "src/index.ts"), 79 | // the proper extensions will be added 80 | fileName: "index", 81 | formats: ["cjs"], 82 | }, 83 | 84 | terserOptions: { 85 | compress: true, // 启用压缩 86 | mangle: true, // 启用变量名混淆 87 | output: { 88 | beautify: false, // 禁用美化输出 89 | comments: false // 移除注释 90 | } 91 | }, 92 | 93 | rollupOptions: { 94 | plugins: [ 95 | ...(isWatch 96 | ? [ 97 | livereload(devDistDir), 98 | { 99 | //监听静态资源文件 100 | name: "watch-external", 101 | async buildStart() { 102 | const files = await fg([ 103 | "src/i18n/*.json", 104 | // "./README*.md", 105 | "./plugin.json", 106 | ]); 107 | for (const file of files) { 108 | this.addWatchFile(file); 109 | } 110 | }, 111 | }, 112 | ] 113 | : [ 114 | // zipPack({ 115 | // inDir: "./dist", 116 | // outDir: "./", 117 | // outFileName: "package.zip", 118 | // }), 119 | ]), 120 | ], 121 | 122 | // make sure to externalize deps that shouldn't be bundled 123 | // into your library 124 | external: ["siyuan", "process"], 125 | 126 | output: { 127 | entryFileNames: "[name].js", 128 | assetFileNames: (assetInfo) => { 129 | if (assetInfo.name === "style.css") { 130 | return "index.css"; 131 | } 132 | return assetInfo.name; 133 | }, 134 | }, 135 | }, 136 | }, 137 | }); 138 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": [ 7 | "ES2022", 8 | "DOM", 9 | "DOM.Iterable" 10 | ], 11 | "skipLibCheck": true, 12 | /* Bundler mode */ 13 | "moduleResolution": "Node", 14 | // "allowImportingTsExtensions": true, 15 | "allowSyntheticDefaultImports": true, 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "noEmit": true, 19 | "jsx": "preserve", 20 | /* Linting */ 21 | "strict": false, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true, 25 | /* Svelte */ 26 | /** 27 | * Typecheck JS in `.svelte` and `.js` files by default. 28 | * Disable checkJs if you'd like to use dynamic types in JS. 29 | * Note that setting allowJs false does not prevent the use 30 | * of JS in `.svelte` files. 31 | */ 32 | "allowJs": true, 33 | "checkJs": true, 34 | "types": [ 35 | "node", 36 | // "vite/client", 37 | // "svelte" 38 | ], 39 | // "baseUrl": "./src", 40 | // "paths": { 41 | // "@/*": ["./src/*"], 42 | // "@/libs/*": ["./src/libs/*"], 43 | // }, 44 | "typeRoots": [ 45 | "./src/types", 46 | "./node_modules/@types" 47 | ], 48 | }, 49 | "include": [ 50 | "src/**/*.ts", 51 | "src/**/*.d.ts", 52 | "src/**/*.svelte", 53 | "../sy-tomato-plugin/src/**/*.ts", 54 | "../sy-tomato-plugin/src/types/**/*.d.ts", 55 | "../sy-tomato-plugin/src/types/**/*.svelte", 56 | ], 57 | "exclude": [ 58 | "node_modules" 59 | ], 60 | "references": [ 61 | { 62 | "path": "./tsconfig.node.json" 63 | } 64 | ], 65 | "root": "." 66 | } -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": [ 10 | "vite.config.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { defineConfig } from "vite"; 3 | import minimist from "minimist"; 4 | import { viteStaticCopy } from "vite-plugin-static-copy"; 5 | import livereload from "rollup-plugin-livereload"; 6 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 7 | import zipPack from "vite-plugin-zip-pack"; 8 | import fg from "fast-glob"; 9 | 10 | const args = minimist(process.argv.slice(2)); 11 | const isWatch = args.watch || args.w || false; 12 | // const devDistDir = "./dev"; 13 | // const distDir = isWatch ? devDistDir : "./dist"; 14 | // console.info("isWatch=>", isWatch); 15 | // console.info("distDir=>", distDir); 16 | const devDistDir = process.env.SYPLUGINDIR + "/sy-progressive-plugin"; 17 | const distDir = devDistDir; 18 | 19 | export default defineConfig({ 20 | resolve: { 21 | alias: { 22 | "@": resolve(__dirname, "src"), 23 | }, 24 | }, 25 | 26 | plugins: [ 27 | svelte(), 28 | viteStaticCopy({ 29 | targets: [ 30 | { 31 | src: "./README*.md", 32 | dest: "./", 33 | }, 34 | { 35 | src: "./icon.png", 36 | dest: "./", 37 | }, 38 | { 39 | src: "./preview.png", 40 | dest: "./", 41 | }, 42 | { 43 | src: "./plugin.json", 44 | dest: "./", 45 | }, 46 | { 47 | src: "./src/i18n/**", 48 | dest: "./i18n/", 49 | }, 50 | ], 51 | }), 52 | ], 53 | 54 | // https://github.com/vitejs/vite/issues/1930 55 | // https://vitejs.dev/guide/env-and-mode.html#env-files 56 | // https://github.com/vitejs/vite/discussions/3058#discussioncomment-2115319 57 | // 在这里自定义变量 58 | define: { 59 | "process.env.DEV_MODE": `"${isWatch}"`, 60 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), 61 | }, 62 | 63 | build: { 64 | // 输出路径 65 | outDir: distDir, 66 | emptyOutDir: false, 67 | 68 | // 构建后是否生成 source map 文件 69 | sourcemap: false, 70 | 71 | // 设置为 false 可以禁用最小化混淆 72 | // 或是用来指定是应用哪种混淆器 73 | // boolean | 'terser' | 'esbuild' 74 | minify: isWatch ? false : "esbuild", // "terser", 75 | 76 | lib: { 77 | // Could also be a dictionary or array of multiple entry points 78 | entry: resolve(__dirname, "src/index.ts"), 79 | // the proper extensions will be added 80 | fileName: "index", 81 | formats: ["cjs"], 82 | }, 83 | 84 | rollupOptions: { 85 | plugins: [ 86 | ...(isWatch 87 | ? [ 88 | livereload(devDistDir), 89 | { 90 | //监听静态资源文件 91 | name: "watch-external", 92 | async buildStart() { 93 | const files = await fg([ 94 | "src/i18n/*.json", 95 | // "./README*.md", 96 | "./plugin.json", 97 | ]); 98 | for (const file of files) { 99 | this.addWatchFile(file); 100 | } 101 | }, 102 | }, 103 | ] 104 | : [ 105 | // zipPack({ 106 | // inDir: "./dist", 107 | // outDir: "./", 108 | // outFileName: "package.zip", 109 | // }), 110 | ]), 111 | ], 112 | 113 | // make sure to externalize deps that shouldn't be bundled 114 | // into your library 115 | external: ["siyuan", "process"], 116 | 117 | output: { 118 | entryFileNames: "[name].js", 119 | assetFileNames: (assetInfo) => { 120 | if (assetInfo.name === "style.css") { 121 | return "index.css"; 122 | } 123 | return assetInfo.name; 124 | }, 125 | }, 126 | }, 127 | }, 128 | }); 129 | --------------------------------------------------------------------------------