Skip to content

Commit 9c65479

Browse files
committed
chore: bump version [release-beta]
1 parent 6ee8855 commit 9c65479

File tree

7 files changed

+286
-11031
lines changed

7 files changed

+286
-11031
lines changed

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-task-progress-bar",
33
"name": "Task Genius",
4-
"version": "9.1.0-beta.5",
4+
"version": "9.1.0-beta.6",
55
"minAppVersion": "0.15.2",
66
"description": "Comprehensive task management that includes progress bars, task status cycling, and advanced task tracking features.",
77
"author": "Boninall",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "task-genius",
3-
"version": "9.1.0-beta.5",
3+
"version": "9.1.0-beta.6",
44
"description": "Comprehensive task management plugin for Obsidian with progress bars, task status cycling, and advanced task tracking features.",
55
"main": "main.js",
66
"scripts": {

src/components/settings/TaskStatusSettingsTab.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ export function renderTaskStatusSettingsTab(
280280
settingTab.plugin.settings.taskStatuses.completed =
281281
value || DEFAULT_SETTINGS.taskStatuses.completed;
282282
settingTab.applySettingsUpdate();
283+
284+
// Update Task Genius Icon Manager
285+
if (settingTab.plugin.taskGeniusIconManager) {
286+
settingTab.plugin.taskGeniusIconManager.update();
287+
}
283288
})
284289
);
285290

@@ -319,6 +324,11 @@ export function renderTaskStatusSettingsTab(
319324
settingTab.plugin.settings.taskStatuses.planned =
320325
value || DEFAULT_SETTINGS.taskStatuses.planned;
321326
settingTab.applySettingsUpdate();
327+
328+
// Update Task Genius Icon Manager
329+
if (settingTab.plugin.taskGeniusIconManager) {
330+
settingTab.plugin.taskGeniusIconManager.update();
331+
}
322332
})
323333
);
324334

@@ -358,6 +368,11 @@ export function renderTaskStatusSettingsTab(
358368
settingTab.plugin.settings.taskStatuses.inProgress =
359369
value || DEFAULT_SETTINGS.taskStatuses.inProgress;
360370
settingTab.applySettingsUpdate();
371+
372+
// Update Task Genius Icon Manager
373+
if (settingTab.plugin.taskGeniusIconManager) {
374+
settingTab.plugin.taskGeniusIconManager.update();
375+
}
361376
})
362377
);
363378

@@ -398,6 +413,11 @@ export function renderTaskStatusSettingsTab(
398413
settingTab.plugin.settings.taskStatuses.abandoned =
399414
value || DEFAULT_SETTINGS.taskStatuses.abandoned;
400415
settingTab.applySettingsUpdate();
416+
417+
// Update Task Genius Icon Manager
418+
if (settingTab.plugin.taskGeniusIconManager) {
419+
settingTab.plugin.taskGeniusIconManager.update();
420+
}
401421
})
402422
);
403423

@@ -438,6 +458,11 @@ export function renderTaskStatusSettingsTab(
438458
settingTab.plugin.settings.taskStatuses.notStarted =
439459
value || DEFAULT_SETTINGS.taskStatuses.notStarted;
440460
settingTab.applySettingsUpdate();
461+
462+
// Update Task Genius Icon Manager
463+
if (settingTab.plugin.taskGeniusIconManager) {
464+
settingTab.plugin.taskGeniusIconManager.update();
465+
}
441466
})
442467
);
443468

@@ -918,7 +943,9 @@ export function renderTaskStatusSettingsTab(
918943
// Auto Date Manager Settings
919944
new Setting(containerEl)
920945
.setName(t("Auto Date Manager"))
921-
.setDesc(t("Automatically manage dates based on checkbox status changes"))
946+
.setDesc(
947+
t("Automatically manage dates based on checkbox status changes")
948+
)
922949
.setHeading();
923950

924951
new Setting(containerEl)
@@ -1003,18 +1030,22 @@ export function renderTaskStatusSettingsTab(
10031030
}
10041031

10051032
// Use Task Genius icons
1006-
new Setting(containerEl)
1007-
.setName(t("Other settings"))
1008-
.setHeading();
1033+
new Setting(containerEl).setName(t("Other settings")).setHeading();
10091034

10101035
new Setting(containerEl)
10111036
.setName(t("Use Task Genius icons"))
10121037
.setDesc(t("Use Task Genius icons for task statuses"))
10131038
.addToggle((toggle) =>
1014-
toggle.setValue(settingTab.plugin.settings.enableTaskGeniusIcons)
1015-
.onChange(async (value) => {
1016-
settingTab.plugin.settings.enableTaskGeniusIcons = value;
1017-
settingTab.applySettingsUpdate();
1018-
})
1039+
toggle
1040+
.setValue(settingTab.plugin.settings.enableTaskGeniusIcons)
1041+
.onChange(async (value) => {
1042+
settingTab.plugin.settings.enableTaskGeniusIcons = value;
1043+
settingTab.applySettingsUpdate();
1044+
1045+
// Update Task Genius Icon Manager
1046+
if (settingTab.plugin.taskGeniusIconManager) {
1047+
settingTab.plugin.taskGeniusIconManager.update();
1048+
}
1049+
})
10191050
);
10201051
}

src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import {
8585
import { getStatusIcon, getTaskGeniusIcon } from "./icon";
8686
import { RewardManager } from "./utils/RewardManager";
8787
import { HabitManager } from "./utils/HabitManager";
88+
import { TaskGeniusIconManager } from "./utils/TaskGeniusIconManager";
8889
import { monitorTaskCompletedExtension } from "./editor-ext/monitorTaskCompleted";
8990
import { sortTasksInDocument } from "./commands/sortTaskCommands";
9091
import { taskGutterExtension } from "./editor-ext/TaskGutterHandler";
@@ -194,6 +195,9 @@ export default class TaskProgressBarPlugin extends Plugin {
194195
// Setting tab
195196
settingTab: TaskProgressBarSettingTab;
196197

198+
// Task Genius Icon manager instance
199+
taskGeniusIconManager: TaskGeniusIconManager;
200+
197201
async onload() {
198202
await this.loadSettings();
199203

@@ -323,6 +327,10 @@ export default class TaskProgressBarPlugin extends Plugin {
323327
);
324328

325329
this.app.workspace.onLayoutReady(() => {
330+
// Initialize Task Genius Icon Manager
331+
this.taskGeniusIconManager = new TaskGeniusIconManager(this);
332+
this.addChild(this.taskGeniusIconManager);
333+
326334
if (this.settings.autoCompleteParent) {
327335
this.registerEditorExtension([
328336
autoCompleteParentExtension(this.app, this),
@@ -1021,6 +1029,8 @@ export default class TaskProgressBarPlugin extends Plugin {
10211029
if (this.taskManager) {
10221030
this.taskManager.onunload();
10231031
}
1032+
1033+
// Task Genius Icon Manager cleanup is handled automatically by Component system
10241034
}
10251035

10261036
async loadSettings() {

src/utils/TaskGeniusIconManager.ts

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import { Component } from "obsidian";
2+
import TaskProgressBarPlugin from "../index";
3+
import { getStatusIcon } from "../icon";
4+
import { TaskProgressBarSettings } from "../common/setting-definition";
5+
6+
/**
7+
* Manages Task Genius Icons functionality
8+
* Handles CSS style injection, body class management, and cleanup
9+
*/
10+
export class TaskGeniusIconManager extends Component {
11+
private plugin: TaskProgressBarPlugin;
12+
private styleElement: HTMLStyleElement | null = null;
13+
private readonly STYLE_ID = "task-genius-icons-styles";
14+
private readonly BODY_CLASS = "task-genius-checkbox";
15+
16+
constructor(plugin: TaskProgressBarPlugin) {
17+
super();
18+
this.plugin = plugin;
19+
}
20+
21+
async onload() {
22+
// Initialize if enabled
23+
if (this.plugin.settings.enableTaskGeniusIcons) {
24+
this.enable();
25+
}
26+
}
27+
28+
onunload() {
29+
this.disable();
30+
}
31+
32+
/**
33+
* Enable Task Genius Icons functionality
34+
*/
35+
enable() {
36+
try {
37+
this.addBodyClass();
38+
this.injectStyles();
39+
} catch (error) {
40+
console.error("Task Genius: Failed to enable icons:", error);
41+
}
42+
}
43+
44+
/**
45+
* Disable Task Genius Icons functionality
46+
*/
47+
disable() {
48+
try {
49+
this.removeBodyClass();
50+
this.removeStyles();
51+
} catch (error) {
52+
console.error("Task Genius: Failed to disable icons:", error);
53+
}
54+
}
55+
56+
/**
57+
* Update functionality when settings change
58+
*/
59+
update() {
60+
if (this.plugin.settings.enableTaskGeniusIcons) {
61+
this.enable();
62+
} else {
63+
this.disable();
64+
}
65+
}
66+
67+
/**
68+
* Add task-genius-checkbox class to body
69+
*/
70+
private addBodyClass() {
71+
document.body.classList.add(this.BODY_CLASS);
72+
}
73+
74+
/**
75+
* Remove task-genius-checkbox class from body
76+
*/
77+
private removeBodyClass() {
78+
document.body.classList.remove(this.BODY_CLASS);
79+
}
80+
81+
/**
82+
* Inject CSS styles into head
83+
*/
84+
private injectStyles() {
85+
// Remove existing styles first
86+
this.removeStyles();
87+
88+
// Generate CSS content
89+
const cssContent = this.generateCSS();
90+
91+
// Create and inject style element
92+
this.styleElement = document.createElement("style");
93+
this.styleElement.id = this.STYLE_ID;
94+
this.styleElement.textContent = cssContent;
95+
document.head.appendChild(this.styleElement);
96+
}
97+
98+
/**
99+
* Remove injected CSS styles
100+
*/
101+
private removeStyles() {
102+
if (this.styleElement) {
103+
this.styleElement.remove();
104+
this.styleElement = null;
105+
}
106+
107+
// Also remove any existing style element with our ID
108+
const existingStyle = document.getElementById(this.STYLE_ID);
109+
if (existingStyle) {
110+
existingStyle.remove();
111+
}
112+
}
113+
114+
/**
115+
* Generate CSS content based on current settings
116+
*/
117+
private generateCSS(): string {
118+
const settings = this.plugin.settings;
119+
const statusConfigs = this.parseTaskStatuses(settings);
120+
121+
let css = "";
122+
123+
for (const config of statusConfigs) {
124+
const svgIcon = getStatusIcon(config.status);
125+
const encodedSvg = this.encodeSvgForCSS(svgIcon);
126+
127+
for (const char of config.chars) {
128+
css += this.generateCSSRuleForChar(char, encodedSvg);
129+
}
130+
}
131+
132+
return css;
133+
}
134+
135+
/**
136+
* Parse taskStatuses configuration into structured format
137+
*/
138+
private parseTaskStatuses(settings: TaskProgressBarSettings): Array<{
139+
status:
140+
| "notStarted"
141+
| "inProgress"
142+
| "completed"
143+
| "abandoned"
144+
| "planned";
145+
chars: string[];
146+
}> {
147+
const result: Array<{
148+
status:
149+
| "notStarted"
150+
| "inProgress"
151+
| "completed"
152+
| "abandoned"
153+
| "planned";
154+
chars: string[];
155+
}> = [];
156+
157+
const statusMap: Record<
158+
string,
159+
"notStarted" | "inProgress" | "completed" | "abandoned" | "planned"
160+
> = {
161+
notStarted: "notStarted",
162+
inProgress: "inProgress",
163+
completed: "completed",
164+
abandoned: "abandoned",
165+
planned: "planned",
166+
};
167+
168+
for (const [statusKey, charString] of Object.entries(
169+
settings.taskStatuses
170+
)) {
171+
const status = statusMap[statusKey];
172+
if (status) {
173+
const chars = charString.split("|").map((char) => char.trim());
174+
result.push({ status, chars });
175+
}
176+
}
177+
178+
return result;
179+
}
180+
181+
/**
182+
* Encode SVG for use in CSS data URI
183+
*/
184+
private encodeSvgForCSS(svgString: string): string {
185+
try {
186+
// Remove width and height attributes to make it scalable
187+
const cleanSvg = svgString
188+
.replace(/width="[^"]*"/g, "")
189+
.replace(/height="[^"]*"/g, "")
190+
.replace(/\s+/g, " ")
191+
.trim();
192+
193+
// URL encode for data URI
194+
const encoded = encodeURIComponent(cleanSvg);
195+
return `data:image/svg+xml,${encoded}`;
196+
} catch (error) {
197+
console.error("Task Genius: Failed to encode SVG:", error);
198+
return "";
199+
}
200+
}
201+
202+
/**
203+
* Generate CSS rule for a specific character
204+
*/
205+
private generateCSSRuleForChar(char: string, encodedSvg: string): string {
206+
// Escape special characters for CSS selector
207+
const escapedChar = this.escapeCSSSelector(char);
208+
209+
return `
210+
.${this.BODY_CLASS} [data-task="${escapedChar}"] > input[type=checkbox]:checked:after,
211+
.${this.BODY_CLASS} [data-task="${escapedChar}"] > p > input[type=checkbox]:checked:after,
212+
.${this.BODY_CLASS} [data-task="${escapedChar}"][type=checkbox]:checked:after {
213+
--webkit-mask-image: url("${encodedSvg}");
214+
--webkit-mask-size: 20%;
215+
}
216+
`;
217+
}
218+
219+
/**
220+
* Escape special characters for CSS selector
221+
*/
222+
private escapeCSSSelector(char: string): string {
223+
// Handle space character specially
224+
if (char === " ") {
225+
return " ";
226+
}
227+
228+
// Escape special CSS characters
229+
return char.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&");
230+
}
231+
}

0 commit comments

Comments
 (0)