Skip to content

Commit ed0fb64

Browse files
committed
feat: update docs
Signed-off-by: Andrea Ferrario <andreaferrario02@gmail.com>
1 parent 7115dd3 commit ed0fb64

5 files changed

Lines changed: 53 additions & 167 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ A lightweight Docsify plugin that transforms standard markdown checkboxes into i
77
## ✨ Features
88

99
- 🖱️ **Interactive Checkboxes** - Click to toggle completion
10-
- 💾 **Persistent State** - Saved in localStorage
10+
- 💾 **Persistent State** - Saved in localStorage with **stable IDs** (v2)
1111
- 📄 **Per-Page Storage** - Each page has its own states
1212
- 🎨 **Visual Feedback** - Strikethrough + fade effect
13+
- 📤 **Import/Export** - Backup your progress easily
1314
-**Zero Dependencies** - Pure JavaScript
1415
- 🚀 **Easy Integration** - Drop-in solution
1516

docs/README.md

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66

77
- 🖱️ **Interactive Checkboxes** - Click to toggle task completion
88
- 💾 **Persistent State** - Saved in browser localStorage
9+
- 🛡️ **Stable IDs (v2)** - States persist correctly even when reordering items
910
- 📄 **Per-Page Storage** - Each page maintains its own states
10-
- 🎨 **Visual Feedback** - Completed tasks show strikethrough styling
11+
- 🎨 **Visual Feedback** - Completed tasks show strikethrough + fade
1112
-**Zero Dependencies** - Pure JavaScript
1213
- 🚀 **Easy Integration** - Drop-in solution
1314

@@ -21,62 +22,11 @@ Try clicking these checkboxes - they'll save automatically!
2122

2223
## 📦 Installation
2324

24-
Add the plugin to your `index.html`:
25+
Add the plugin to your `index.html` after Docsify:
2526

2627
```html
27-
<script>
28-
window.$docsify = {
29-
// ... your config
30-
31-
plugins: [
32-
function(hook, vm) {
33-
const STORAGE_PREFIX = 'docsify-checkbox-';
34-
35-
function getStorageKey() {
36-
return STORAGE_PREFIX + (vm.route.path || 'index');
37-
}
38-
39-
function loadCheckboxStates() {
40-
const stored = localStorage.getItem(getStorageKey());
41-
return stored ? JSON.parse(stored) : {};
42-
}
43-
44-
function saveCheckboxStates(states) {
45-
localStorage.setItem(getStorageKey(), JSON.stringify(states));
46-
}
47-
48-
hook.doneEach(function() {
49-
const checkboxes = document.querySelectorAll(
50-
'.task-list-item input[type="checkbox"]'
51-
);
52-
const states = loadCheckboxStates();
53-
54-
checkboxes.forEach((checkbox, index) => {
55-
const id = 'checkbox-' + index;
56-
checkbox.id = id;
57-
checkbox.removeAttribute('disabled');
58-
59-
if (states[id] !== undefined) {
60-
checkbox.checked = states[id];
61-
if (checkbox.checked) {
62-
checkbox.parentElement.classList.add('checked');
63-
}
64-
}
65-
66-
checkbox.addEventListener('change', function(e) {
67-
const isChecked = e.target.checked;
68-
e.target.parentElement.classList.toggle('checked', isChecked);
69-
70-
const currentStates = loadCheckboxStates();
71-
currentStates[id] = isChecked;
72-
saveCheckboxStates(currentStates);
73-
});
74-
});
75-
});
76-
}
77-
]
78-
}
79-
</script>
28+
<!-- Interactive Checkboxes Plugin -->
29+
<script src="https://cdn.jsdelivr.net/gh/andreferra/docsify-plugin-interactive-checkboxes/src/plugin.js"></script>
8030
```
8131

8232
## 🎨 Styling

docs/configuration.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ Configure the plugin in your Docsify config:
77
```javascript
88
window.$docsify = {
99
interactiveCheckboxes: {
10-
storagePrefix: 'docsify-checkbox-', // localStorage key prefix
11-
fadeCompleted: true, // fade completed items
12-
fadeOpacity: 0.6 // opacity for completed items
10+
storagePrefix: 'docsify-checkbox-', // localStorage key prefix
11+
fadeCompleted: true, // fade completed items
12+
fadeOpacity: 0.6, // opacity for completed items
13+
cleanOrphanedStates: true // remove states for deleted checkboxes (v2+)
1314
}
1415
}
1516
```
1617

18+
> [!NOTE]
19+
> **v2.0 Update**: Checkbox IDs are now generated based on their content hash. This ensures states are preserved correctly even if you reorder list items!
20+
1721
## Custom Storage Prefix
1822

1923
Avoid conflicts with other apps using the same localStorage:
@@ -26,34 +30,54 @@ interactiveCheckboxes: {
2630

2731
## Utility Functions
2832

29-
The plugin exposes these global functions:
33+
The plugin exposes these global functions for managing states:
34+
35+
### 📤 Export/Import States (v2+)
3036

31-
### Clear All Checkboxes
37+
Useful for backing up or transferring progress:
3238

3339
```javascript
34-
// Reset all checkbox states and reload
35-
clearAllDocsifyCheckboxes();
40+
// Export all states as an object
41+
const backup = exportDocsifyCheckboxStates();
42+
console.log(backup);
3643

37-
// With custom prefix
38-
clearAllDocsifyCheckboxes('my-prefix-');
44+
// Import states
45+
importDocsifyCheckboxStates(backup);
3946
```
4047

41-
### Get Progress
48+
### 📊 Get Progress
4249

4350
```javascript
4451
const progress = getDocsifyCheckboxProgress();
4552
console.log(progress);
4653
// { total: 10, checked: 3, percentage: 30 }
4754
```
4855

56+
### 🧹 Clear All Checkboxes
57+
58+
```javascript
59+
// Reset all checkbox states and reload
60+
clearAllDocsifyCheckboxes();
61+
62+
// With custom prefix
63+
clearAllDocsifyCheckboxes('my-prefix-');
64+
```
65+
4966
## Custom Events
5067

5168
Listen to checkbox changes:
5269

5370
```javascript
5471
document.addEventListener('docsify-checkbox-change', function(e) {
5572
console.log('Checkbox changed:', e.detail);
56-
// { checkboxId: 'checkbox-0', checked: true, page: '/demo' }
73+
/* Output:
74+
{
75+
checkboxId: 'cb-k8j29-0',
76+
checked: true,
77+
page: '/demo',
78+
progress: { total: 5, checked: 1, percentage: 20 }
79+
}
80+
*/
5781
});
5882
```
5983

docs/index.html

Lines changed: 1 addition & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -177,106 +177,7 @@
177177
<script src="https://cdn.jsdelivr.net/npm/prismjs@1/components/prism-markup.min.js"></script>
178178

179179
<!-- Interactive Checkboxes Plugin -->
180-
<script>
181-
(function () {
182-
'use strict';
183-
184-
const DEFAULT_CONFIG = {
185-
storagePrefix: 'docsify-checkbox-',
186-
fadeCompleted: true,
187-
fadeOpacity: 0.6
188-
};
189-
190-
function interactiveCheckboxesPlugin(hook, vm) {
191-
const config = Object.assign({}, DEFAULT_CONFIG, window.$docsify?.interactiveCheckboxes || {});
192-
193-
function getStorageKey() {
194-
return config.storagePrefix + (vm.route.path || 'index');
195-
}
196-
197-
function loadCheckboxStates() {
198-
try {
199-
const stored = localStorage.getItem(getStorageKey());
200-
return stored ? JSON.parse(stored) : {};
201-
} catch (e) { return {}; }
202-
}
203-
204-
function saveCheckboxStates(states) {
205-
try {
206-
localStorage.setItem(getStorageKey(), JSON.stringify(states));
207-
} catch (e) { }
208-
}
209-
210-
function applyStyles(listItem, isChecked) {
211-
if (isChecked) {
212-
listItem.classList.add('checked');
213-
if (config.fadeCompleted) listItem.style.opacity = config.fadeOpacity;
214-
} else {
215-
listItem.classList.remove('checked');
216-
if (config.fadeCompleted) listItem.style.opacity = '';
217-
}
218-
}
219-
220-
hook.doneEach(function () {
221-
const checkboxes = document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]');
222-
if (checkboxes.length === 0) return;
223-
224-
const states = loadCheckboxStates();
225-
226-
checkboxes.forEach((checkbox, index) => {
227-
const checkboxId = 'checkbox-' + index;
228-
checkbox.id = checkboxId;
229-
checkbox.removeAttribute('disabled');
230-
checkbox.style.cursor = 'pointer';
231-
232-
if (states[checkboxId] !== undefined) {
233-
checkbox.checked = states[checkboxId];
234-
applyStyles(checkbox.closest('li') || checkbox.parentElement, checkbox.checked);
235-
} else if (checkbox.checked) {
236-
applyStyles(checkbox.closest('li') || checkbox.parentElement, true);
237-
}
238-
239-
const newCheckbox = checkbox.cloneNode(true);
240-
checkbox.parentNode.replaceChild(newCheckbox, checkbox);
241-
242-
newCheckbox.addEventListener('change', function (e) {
243-
const isChecked = e.target.checked;
244-
const listItem = e.target.closest('li') || e.target.parentElement;
245-
applyStyles(listItem, isChecked);
246-
247-
const currentStates = loadCheckboxStates();
248-
currentStates[checkboxId] = isChecked;
249-
saveCheckboxStates(currentStates);
250-
251-
document.dispatchEvent(new CustomEvent('docsify-checkbox-change', {
252-
detail: { checkboxId, checked: isChecked, page: vm.route.path }
253-
}));
254-
});
255-
});
256-
257-
// Trigger progress update
258-
setTimeout(updateProgressBar, 100);
259-
});
260-
}
261-
262-
window.clearAllDocsifyCheckboxes = function (prefix) {
263-
Object.keys(localStorage)
264-
.filter(key => key.startsWith(prefix || DEFAULT_CONFIG.storagePrefix))
265-
.forEach(key => localStorage.removeItem(key));
266-
location.reload();
267-
};
268-
269-
window.getDocsifyCheckboxProgress = function () {
270-
const checkboxes = document.querySelectorAll('.task-list-item input[type="checkbox"], li input[type="checkbox"]');
271-
const total = checkboxes.length;
272-
const checked = Array.from(checkboxes).filter(cb => cb.checked).length;
273-
return { total, checked, percentage: total > 0 ? Math.round((checked / total) * 100) : 0 };
274-
};
275-
276-
window.$docsify.plugins = window.$docsify.plugins || [];
277-
window.$docsify.plugins.push(interactiveCheckboxesPlugin);
278-
})();
279-
</script>
180+
<script src="plugin.min.js"></script>
280181
</body>
281182

282183
</html>

docs/plugin.min.js

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)