├── .gitignore ├── package.json ├── index.html ├── README.md ├── LICENSE.md ├── .github └── workflows │ └── publish.yml ├── wide-eyed.svg └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logseq-wide-eyed", 3 | "version": "1.0.6", 4 | "author": "Mario T. Lanza", 5 | "main": "index.html", 6 | "description": "Toggles the appearance and/or visibility of select blocks", 7 | "license": "MIT", 8 | "browserslist": [ 9 | "chrome 80" 10 | ], 11 | "logseq": { 12 | "id": "logseq-wide-eyed", 13 | "title": "Wide Eyed", 14 | "icon": "wide-eyed.svg" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Logseq Wide Eyed 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logseq Wide Eyed Plugin 2 | 3 | Toggle the visibility of completed and canceled to-dos. 4 | 5 | Version 2 replaced the guts with the internals of [Style Carousel](https://github.com/mlanza/logseq-style-carousel). The prior implementation is no longer supported. The only difference is the icon font set used for the ever-present eye. 6 | 7 | Since Style Carousel and Wide Eyed are internally the same, do not install both. It's one or the other. 8 | 9 | This plugin may eventually be deprecated due to the existence of Style Carousel which has the same default behavior. Furthermore, it [can be customized](https://github.com/mlanza/logseq-style-carousel#using-the-eye-icon-from-wide-eyed) to use the familiar Wide Eyed eye icon. Please consider making the switch before that happens. 10 | 11 | ## License 12 | [MIT](./LICENSE.md) 13 | 14 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 Mario T. Lanza 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 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build plugin 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - "*" # Push events to matching any tag format, i.e. 1.0, 20.15.10 8 | 9 | env: 10 | PLUGIN_NAME: logseq-wide-eyed 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Use Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: "14.x" # You might need to adjust this value to your own version 22 | - name: Build 23 | id: build 24 | run: | 25 | mkdir ${{ env.PLUGIN_NAME }} 26 | cp README.md package.json wide-eyed.svg index.js index.html ${{ env.PLUGIN_NAME }} 27 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }} 28 | ls 29 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)" 30 | 31 | - name: Create Release 32 | uses: ncipollo/release-action@v1 33 | id: create_release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | VERSION: ${{ github.ref }} 37 | with: 38 | allowUpdates: true 39 | draft: false 40 | prerelease: false 41 | 42 | - name: Upload zip file 43 | id: upload_zip 44 | uses: actions/upload-release-asset@v1 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | with: 48 | upload_url: ${{ steps.create_release.outputs.upload_url }} 49 | asset_path: ./${{ env.PLUGIN_NAME }}.zip 50 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip 51 | asset_content_type: application/zip 52 | 53 | - name: Upload package.json 54 | id: upload_metadata 55 | uses: actions/upload-release-asset@v1 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | with: 59 | upload_url: ${{ steps.create_release.outputs.upload_url }} 60 | asset_path: ./package.json 61 | asset_name: package.json 62 | asset_content_type: application/json 63 | 64 | -------------------------------------------------------------------------------- /wide-eyed.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 30 | 50 | 53 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | "buttons": { 3 | "todos": { 4 | "refreshRate": 5, 5 | "hits": ["text-decoration: underline;", ""], 6 | "styles": [{ 7 | "tooltip": "Without closed tasks", 8 | "char": "\\e6ed", 9 | "hits": "div#main-content-container div[data-refs-self*='\"done\"'], div#main-content-container div[data-refs-self*='\"canceled\"']", 10 | "style": "div[data-refs-self*='\"done\"']:not(:focus-within), div[data-refs-self*='\"canceled\"']:not(:focus-within) {display: none;}" 11 | },{ 12 | "tooltip": "With closed tasks", 13 | "char": "\\e600", 14 | "hits": "div#main-content-container div[data-refs-self*='\"done\"'], div#main-content-container div[data-refs-self*='\"canceled\"']", 15 | "style": "div#main-content-container:hover div[data-refs-self*='\"done\"'] span.inline, div#main-content-container:hover div[data-refs-self*='\"canceled\"'] span.inline {text-decoration: underline wavy;}" 16 | }] 17 | } 18 | } 19 | }; 20 | 21 | const state = {}; 22 | 23 | async function getPage(){ 24 | let tries = 30; 25 | return new Promise(function(resolve, reject){ 26 | const iv = setInterval(async function(){ 27 | const page = await logseq.Editor.getCurrentPage(); 28 | if (page || tries <= 0) { 29 | clearInterval(iv); 30 | resolve(page); 31 | } 32 | tries--; 33 | if (tries < 0) { 34 | clearInterval(iv); 35 | reject(page); 36 | } 37 | }, 500); 38 | }); 39 | } 40 | 41 | function setButton(key, char, tooltip, status){ 42 | top.document.body.setAttribute(`data-sc-${key}`, status || ""); 43 | logseq.App.registerUIItem('toolbar', { 44 | key: `button-${key}`, 45 | template: ` 46 | 47 | 48 | 49 | `, 50 | }); 51 | logseq.provideStyle({ 52 | key: `icon-${key}`, 53 | style: ` 54 | .eye[data-key="${key}"] i:before { 55 | content: "${char}"; 56 | }` 57 | }); 58 | } 59 | 60 | async function cycle(el) { 61 | const key = el.dataset.key, 62 | st = state[key], 63 | btn = config.buttons[key]; 64 | st.idx = btn.styles[st.idx + 1] ? st.idx + 1 : 0; 65 | await refresh(key, btn, st); 66 | } 67 | 68 | async function refresh(key, btn, state){ 69 | const {char, tooltip, status, style, hits} = btn.styles[state.idx]; 70 | state.hits = hits; 71 | style && logseq.provideStyle({ 72 | key: `active-${key}`, 73 | style 74 | }); 75 | setButton(key, char, tooltip, status); 76 | detectHits(key, btn, state); 77 | } 78 | 79 | function detectHits(key, config, state){ 80 | if (state.hits) { 81 | const el = top.document.querySelector(state.hits); 82 | const style = el ? config.hits[0] : config.hits[1]; 83 | logseq.provideStyle({ 84 | key: `hits-${key}`, 85 | style: ` 86 | .eye[data-key="${key}"] i:before { 87 | ${style}; 88 | }` 89 | }); 90 | } 91 | } 92 | 93 | function refreshHits(key, config, state){ 94 | (config.refreshRate || 0) > 0 && setInterval(function(){ 95 | detectHits(key, config, state); 96 | }, config.refreshRate * 1000); 97 | } 98 | 99 | function createModel(){ 100 | return {refresh, cycle}; 101 | } 102 | 103 | async function main(){ 104 | Object.assign(config, logseq.settings); 105 | 106 | logseq.provideStyle({ 107 | style: ` 108 | @import url("https://at.alicdn.com/t/font_2409735_haugsknp36e.css"); 109 | .eye { 110 | font-size: 20px; 111 | } 112 | .eye i:before { 113 | font-family: iconfont !important; 114 | font-style: normal; 115 | color: var(--ls-primary-text-color); 116 | }` 117 | }); 118 | 119 | for (let key in config.buttons) { 120 | const btn = config.buttons[key]; 121 | if (btn.disabled) { 122 | delete config.buttons[key]; 123 | } else { 124 | const {char, tooltip, status} = btn.styles[0]; 125 | state[key] = {idx: 0}; 126 | setButton(key, char, tooltip, status); 127 | } 128 | } 129 | 130 | await getPage(); 131 | 132 | for (let key in config.buttons) { 133 | const btn = config.buttons[key], 134 | st = state[key]; 135 | await refresh(key, btn, st); 136 | refreshHits(key, btn, st); 137 | } 138 | 139 | logseq.App.onRouteChanged(async function(e){ 140 | await getPage(); 141 | for (let key in config.buttons) { 142 | refresh(key, config.buttons[key], state[key]); 143 | } 144 | }); 145 | } 146 | 147 | logseq.ready(createModel(), main).catch(console.error.bind(console)); 148 | --------------------------------------------------------------------------------