diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..7fb504f --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,24 @@ +name: Publish to NPM + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + - run: npm ci + - run: npm test + - run: npm run build + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..a037218 --- /dev/null +++ b/.npmignore @@ -0,0 +1,8 @@ +src/ +test/ +.github/ +docs/ +.gitignore +.npmignore +jest.config.js +package-lock.json diff --git a/README.md b/README.md index c205f5f..4d3e526 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Docsify Interactive Checkboxes Plugin [![GitHub Pages](https://github.com/andreferra/docsify-plugin-interactive-checkboxes/actions/workflows/deploy.yml/badge.svg)](https://github.com/andreferra/docsify-plugin-interactive-checkboxes/actions/workflows/deploy.yml) +[![npm version](https://badge.fury.io/js/docsify-interactive-checkboxes.svg)](https://badge.fury.io/js/docsify-interactive-checkboxes) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A lightweight Docsify plugin that transforms standard markdown checkboxes into interactive, persistent task lists. diff --git a/docs/plugin.min.js b/docs/plugin.min.js index 8c8af24..03c1595 100644 --- a/docs/plugin.min.js +++ b/docs/plugin.min.js @@ -5,6 +5,6 @@ * * @author Andrea Ferrario * @license MIT - * @version 2.0.0 + * @version 2.0.1 */ -!function(){"use strict";const t={storagePrefix:"docsify-checkbox-",strikethroughCompleted:!0,fadeCompleted:!0,fadeOpacity:.6,cleanOrphanedStates:!0};function e(e,o){const c=Object.assign({},t,window.$docsify?.interactiveCheckboxes||{});function n(){return c.storagePrefix+(o.route.path||"index")}function r(){const t=n();try{const e=localStorage.getItem(t);return e?JSON.parse(e):{}}catch(t){return console.warn("Docsify Interactive Checkboxes: Error loading states",t),{}}}function i(t){const e=n();try{localStorage.setItem(e,JSON.stringify(t))}catch(t){console.warn("Docsify Interactive Checkboxes: Error saving states",t)}}function s(t,e){const o=t.closest("li");if(!o)return"checkbox-"+e;const c=o.cloneNode(!0),n=c.querySelector('input[type="checkbox"]');n&&n.remove();return`cb-${function(t){let e=0;for(let o=0;ot.checked).length;return{total:e,checked:o,percentage:e>0?Math.round(o/e*100):0}}e.doneEach(function(){const t=document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]');if(0===t.length)return;const e=r(),n=[];t.forEach((t,c)=>{const h=s(t,c);n.push(h),t.id=h,t.setAttribute("data-checkbox-id",h),t.removeAttribute("disabled"),t.style.cursor="pointer";const d=t.closest("li");if(!d)return;const u=e[h];void 0!==u&&(t.checked=u),a(d,t.checked),t.hasAttribute("data-listener-attached")||(t.setAttribute("data-listener-attached","true"),t.addEventListener("change",function(t){const e=t.target.checked,c=t.target.closest("li");c&&a(c,e);const n=r();n[h]=e,i(n),document.dispatchEvent(new CustomEvent("docsify-checkbox-change",{detail:{checkboxId:h,checked:e,page:o.route.path,progress:l()}}))}))}),function(t){if(!c.cleanOrphanedStates)return;const e=r(),o=new Set(t),n={};let s=!1;Object.keys(e).forEach(t=>{o.has(t)?n[t]=e[t]:s=!0}),s&&i(n)}(n)})}window.clearAllDocsifyCheckboxes=function(e){const o=e||t.storagePrefix,c=[];for(let t=0;tlocalStorage.removeItem(t)),location.reload()},window.getDocsifyCheckboxProgress=function(){const t=document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]'),e=t.length,o=Array.from(t).filter(t=>t.checked).length;return{total:e,checked:o,percentage:e>0?Math.round(o/e*100):0}},window.exportDocsifyCheckboxStates=function(){const e=t.storagePrefix,o={};for(let t=0;t{localStorage.setItem(e,JSON.stringify(t[e]))}),location.reload(),!0}catch(t){return console.error("Error importing states:",t),!1}},window.$docsify?(window.$docsify.plugins=window.$docsify.plugins||[],window.$docsify.plugins.push(e)):window.DocsifyInteractiveCheckboxes=e}(); \ No newline at end of file +!function () { "use strict"; const t = { storagePrefix: "docsify-checkbox-", strikethroughCompleted: !0, fadeCompleted: !0, fadeOpacity: .6, cleanOrphanedStates: !0 }; function e(e, o) { const c = Object.assign({}, t, window.$docsify?.interactiveCheckboxes || {}); function n() { return c.storagePrefix + (o.route.path || "index") } function r() { const t = n(); try { const e = localStorage.getItem(t); return e ? JSON.parse(e) : {} } catch (t) { return console.warn("Docsify Interactive Checkboxes: Error loading states", t), {} } } function i(t) { const e = n(); try { localStorage.setItem(e, JSON.stringify(t)) } catch (t) { console.warn("Docsify Interactive Checkboxes: Error saving states", t) } } function s(t, e) { const o = t.closest("li"); if (!o) return "checkbox-" + e; const c = o.cloneNode(!0), n = c.querySelector('input[type="checkbox"]'); n && n.remove(); return `cb-${function (t) { let e = 0; for (let o = 0; o < t.length; o++)e = (e << 5) - e + t.charCodeAt(o), e &= e; return Math.abs(e).toString(36) }(c.textContent.trim().slice(0, 50))}-${e}` } function a(t, e) { e ? (t.classList.add("checked"), c.strikethroughCompleted && (t.style.textDecoration = "line-through"), c.fadeCompleted && (t.style.opacity = c.fadeOpacity)) : (t.classList.remove("checked"), t.style.textDecoration = "", c.fadeCompleted && (t.style.opacity = "")) } function l() { const t = document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]'), e = t.length, o = Array.from(t).filter(t => t.checked).length; return { total: e, checked: o, percentage: e > 0 ? Math.round(o / e * 100) : 0 } } e.doneEach(function () { const t = document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]'); if (0 === t.length) return; const e = r(), n = []; t.forEach((t, c) => { const h = s(t, c); n.push(h), t.id = h, t.setAttribute("data-checkbox-id", h), t.removeAttribute("disabled"), t.style.cursor = "pointer"; const d = t.closest("li"); if (!d) return; const u = e[h]; void 0 !== u && (t.checked = u), a(d, t.checked), t.hasAttribute("data-listener-attached") || (t.setAttribute("data-listener-attached", "true"), t.addEventListener("change", function (t) { const e = t.target.checked, c = t.target.closest("li"); c && a(c, e); const n = r(); n[h] = e, i(n), document.dispatchEvent(new CustomEvent("docsify-checkbox-change", { detail: { checkboxId: h, checked: e, page: o.route.path, progress: l() } })) })) }), function (t) { if (!c.cleanOrphanedStates) return; const e = r(), o = new Set(t), n = {}; let s = !1; Object.keys(e).forEach(t => { o.has(t) ? n[t] = e[t] : s = !0 }), s && i(n) }(n) }) } window.clearAllDocsifyCheckboxes = function (e) { const o = e || t.storagePrefix, c = []; for (let t = 0; t < localStorage.length; t++) { const e = localStorage.key(t); e && e.startsWith(o) && c.push(e) } c.forEach(t => localStorage.removeItem(t)), location.reload() }, window.getDocsifyCheckboxProgress = function () { const t = document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]'), e = t.length, o = Array.from(t).filter(t => t.checked).length; return { total: e, checked: o, percentage: e > 0 ? Math.round(o / e * 100) : 0 } }, window.exportDocsifyCheckboxStates = function () { const e = t.storagePrefix, o = {}; for (let t = 0; t < localStorage.length; t++) { const c = localStorage.key(t); if (c && c.startsWith(e)) try { o[c] = JSON.parse(localStorage.getItem(c)) } catch (t) { console.warn("Error exporting key:", c, t) } } return o }, window.importDocsifyCheckboxStates = function (t) { try { return Object.keys(t).forEach(e => { localStorage.setItem(e, JSON.stringify(t[e])) }), location.reload(), !0 } catch (t) { return console.error("Error importing states:", t), !1 } }, window.$docsify ? (window.$docsify.plugins = window.$docsify.plugins || [], window.$docsify.plugins.push(e)) : window.DocsifyInteractiveCheckboxes = e }(); \ No newline at end of file diff --git a/package.json b/package.json index 4d2e8f5..de0d9b5 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,15 @@ { "name": "docsify-interactive-checkboxes", - "version": "1.0.0", + "version": "2.0.1", "description": "A lightweight Docsify plugin that transforms standard markdown checkboxes into interactive, persistent task lists", "main": "src/plugin.js", "unpkg": "dist/plugin.min.js", "jsdelivr": "dist/plugin.min.js", "files": [ "src", - "dist" + "dist", + "README.md", + "LICENSE" ], "scripts": { "build": "terser src/plugin.js -o dist/plugin.min.js -c -m", @@ -21,15 +23,16 @@ }, "keywords": [ "docsify", - "plugin", + "docsify-plugin", "checkbox", "interactive", "todo", "task-list", "markdown", - "persistent" + "persistent", + "localstorage" ], - "author": "Andrea Ferrario", + "author": "Andrea Ferrario ", "license": "MIT", "bugs": { "url": "https://github.com/andreferra/docsify-plugin-interactive-checkboxes/issues" @@ -39,5 +42,8 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "terser": "^5.31.0" + }, + "publishConfig": { + "access": "public" } } \ No newline at end of file diff --git a/src/plugin.js b/src/plugin.js index 9ef3abb..63b2dad 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -5,7 +5,7 @@ * * @author Andrea Ferrario * @license MIT - * @version 2.0.0 + * @version 2.0.1 */ (function () {