Compare commits

...

3 commits
0.7.0 ... main

Author SHA1 Message Date
Emberleif
99e4918b90 Update versions.json 2026-06-16 11:24:28 -05:00
Emberleif
fdefeae8d4 Manifest Change
0.7.1 fix
2026-06-16 11:22:47 -05:00
Emberleif
3ed7063cf8 0.7.1
Bug fixes for persistent help files
2026-06-16 11:02:11 -05:00
4 changed files with 33 additions and 149 deletions

171
main.js
View file

@ -52,12 +52,10 @@ const DEFAULT_SETTINGS = {
colorProperty: "timeboardColor", colorProperty: "timeboardColor",
subtitleProperty: "timeboardSubtitle", subtitleProperty: "timeboardSubtitle",
highlightColor: "", highlightColor: "",
forceDarkTextOnColored: false, forceDarkTextOnColored: false
lastSeenVersion: ""
}; };
const GUIDE_NOTE_PATH = "Getting Started With Chronoboard.md"; const GUIDE_NOTE_PATH = "Getting Started With Chronoboard.md";
const CHANGELOG_NOTE_PATH = "Chronoboard - Changelog.md";
function normalizeStatus(value) { function normalizeStatus(value) {
return String(value || "").trim().toLowerCase(); return String(value || "").trim().toLowerCase();
@ -1345,12 +1343,12 @@ class ChronoboardView extends ItemView {
helpTrigger.setAttr("aria-label", "Open Chronoboard guide"); helpTrigger.setAttr("aria-label", "Open Chronoboard guide");
helpTrigger.setAttr("title", "Open Chronoboard guide"); helpTrigger.setAttr("title", "Open Chronoboard guide");
helpTrigger.addEventListener("click", async () => { helpTrigger.addEventListener("click", async () => {
await this.plugin.openManagedNote(GUIDE_NOTE_PATH, true); await this.plugin.openGuideNote();
}); });
helpTrigger.addEventListener("keydown", async (event) => { helpTrigger.addEventListener("keydown", async (event) => {
if (event.key === "Enter" || event.key === " ") { if (event.key === "Enter" || event.key === " ") {
event.preventDefault(); event.preventDefault();
await this.plugin.openManagedNote(GUIDE_NOTE_PATH, true); await this.plugin.openGuideNote();
} }
}); });
@ -1453,12 +1451,12 @@ class ChronoboardView extends ItemView {
helpTrigger.setAttr("aria-label", "Open Chronoboard guide"); helpTrigger.setAttr("aria-label", "Open Chronoboard guide");
helpTrigger.setAttr("title", "Open Chronoboard guide"); helpTrigger.setAttr("title", "Open Chronoboard guide");
helpTrigger.addEventListener("click", async () => { helpTrigger.addEventListener("click", async () => {
await this.plugin.openManagedNote(GUIDE_NOTE_PATH, true); await this.plugin.openGuideNote();
}); });
helpTrigger.addEventListener("keydown", async (event) => { helpTrigger.addEventListener("keydown", async (event) => {
if (event.key === "Enter" || event.key === " ") { if (event.key === "Enter" || event.key === " ") {
event.preventDefault(); event.preventDefault();
await this.plugin.openManagedNote(GUIDE_NOTE_PATH, true); await this.plugin.openGuideNote();
} }
}); });
const list = panel.createDiv({ cls: "chronoboard-mobile-task-list" }); const list = panel.createDiv({ cls: "chronoboard-mobile-task-list" });
@ -2914,13 +2912,7 @@ module.exports = class ChronoboardPlugin extends Plugin {
this.addCommand({ this.addCommand({
id: "open-chronoboard-guide", id: "open-chronoboard-guide",
name: "Open Chronoboard guide", name: "Open Chronoboard guide",
callback: async () => this.openManagedNote(GUIDE_NOTE_PATH, true) callback: async () => this.openGuideNote()
});
this.addCommand({
id: "open-chronoboard-changelog",
name: "Open Chronoboard changelog",
callback: async () => this.openManagedNote(CHANGELOG_NOTE_PATH, true)
}); });
this.addCommand({ this.addCommand({
@ -2944,7 +2936,6 @@ module.exports = class ChronoboardPlugin extends Plugin {
this.registerEvent(this.app.vault.on("rename", () => this.refreshAllViews())); this.registerEvent(this.app.vault.on("rename", () => this.refreshAllViews()));
this.registerEvent(this.app.vault.on("delete", () => this.refreshAllViews())); this.registerEvent(this.app.vault.on("delete", () => this.refreshAllViews()));
this.registerDomEvent(document, "keydown", (event) => this.handleUndoKeydown(event)); this.registerDomEvent(document, "keydown", (event) => this.handleUndoKeydown(event));
await this.initializeManagedNotes();
} }
async onunload() { async onunload() {
@ -2960,88 +2951,17 @@ module.exports = class ChronoboardPlugin extends Plugin {
await this.saveData(this.settings); await this.saveData(this.settings);
} }
async initializeManagedNotes() { async openGuideNote() {
await this.ensureManagedNote(GUIDE_NOTE_PATH, this.buildGuideNoteContent()); const existing = this.app.vault.getAbstractFileByPath(GUIDE_NOTE_PATH);
await this.ensureChangelogNote(); let file = existing instanceof TFile ? existing : null;
if (!file) {
const currentVersion = this.manifest.version; file = await this.app.vault.create(GUIDE_NOTE_PATH, this.buildGuideNoteContent());
const previousVersion = String(this.settings.lastSeenVersion || "").trim();
const isFirstRun = !previousVersion;
const isUpdate = Boolean(previousVersion) && previousVersion !== currentVersion;
if (this.settings.lastSeenVersion !== currentVersion) {
this.settings.lastSeenVersion = currentVersion;
await this.saveSettings();
} }
await this.app.workspace.getLeaf("tab").openFile(file);
if (isFirstRun) {
await this.openManagedNote(GUIDE_NOTE_PATH, false);
return;
}
if (isUpdate) {
await this.openManagedNote(CHANGELOG_NOTE_PATH, false);
}
}
async ensureManagedNote(path, content) {
const existing = this.app.vault.getAbstractFileByPath(path);
if (existing instanceof TFile) {
const current = await this.app.vault.cachedRead(existing);
if (current !== content) {
await this.app.vault.modify(existing, content);
}
return existing;
}
return this.app.vault.create(path, content);
}
async openManagedNote(path, ensureFirst = false) {
if (ensureFirst) {
if (path === GUIDE_NOTE_PATH) {
await this.ensureManagedNote(path, this.buildGuideNoteContent());
} else if (path === CHANGELOG_NOTE_PATH) {
await this.ensureChangelogNote();
}
}
const file = this.app.vault.getAbstractFileByPath(path);
if (file instanceof TFile) {
await this.app.workspace.getLeaf("tab").openFile(file);
}
}
async ensureChangelogNote() {
const versionHeading = `## ${this.manifest.version}`;
const releaseSection = this.buildCurrentReleaseSection();
const existing = this.app.vault.getAbstractFileByPath(CHANGELOG_NOTE_PATH);
if (!(existing instanceof TFile)) {
return this.app.vault.create(CHANGELOG_NOTE_PATH, `${this.buildChangelogHeader()}\n\n${releaseSection}\n`);
}
const current = await this.app.vault.cachedRead(existing);
if (current.includes(versionHeading)) {
return existing;
}
const bodyWithoutHeader = current
.replace(/^# Chronoboard Changelog\s*/m, "")
.replace(/^This note is managed by Chronoboard and records release highlights, commands, fixes, and workflow clarifications\.\s*/m, "")
.trim();
const updated = `${this.buildChangelogHeader()}\n\n${releaseSection}${bodyWithoutHeader ? `\n\n${bodyWithoutHeader}` : ""}\n`;
await this.app.vault.modify(existing, updated);
return existing;
}
buildChangelogHeader() {
return [
"# Chronoboard Changelog",
"",
"This note is managed by Chronoboard and records release highlights, commands, fixes, and workflow clarifications."
].join("\n");
} }
buildGuideNoteContent() { buildGuideNoteContent() {
return [ return [
"# Getting Started With Chronoboard",
"",
"> [!info] What Chronoboard Is", "> [!info] What Chronoboard Is",
"> Chronoboard is a task-native timeboard for Obsidian. It lets you pull tasks from a configured folder and place time visually in day, week, and month views.", "> Chronoboard is a task-native timeboard for Obsidian. It lets you pull tasks from a configured folder and place time visually in day, week, and month views.",
"", "",
@ -3049,17 +2969,26 @@ module.exports = class ChronoboardPlugin extends Plugin {
"", "",
"> [!tip] Task setup", "> [!tip] Task setup",
"> Tasks should usually have your configured status frontmatter, `Status` by default. That is what makes them available in the add-task pool unless they are explicitly included through `Always include tasks`.", "> Tasks should usually have your configured status frontmatter, `Status` by default. That is what makes them available in the add-task pool unless they are explicitly included through `Always include tasks`.",
"",
"- Add tasks into the left task pool with `Add task to Chronoboard` or the `+ Add task` slot.", "- Add tasks into the left task pool with `Add task to Chronoboard` or the `+ Add task` slot.",
"- Make sure the task file has the configured status frontmatter property before expecting it to appear in the task pool.", "- Make sure the task file has the configured status frontmatter property before expecting it to appear in the task pool.",
"- Click a task in the left pool to select it, then click and drag in the board to create a time block.", "- Click a task in the left pool to select it, then click and drag in the board to create a time block.",
"- Hold and drag an existing time block to move it.", "- Hold and drag an existing time block to move it.",
"- Double click a time block to remove it.", "- Double click a time block to remove it.",
"- Use `Ctrl+Z` or `Cmd+Z` to undo adding or removing a time block.", "- Use `Ctrl+Z` or `Cmd+Z` to undo adding or removing a time block.",
"## Status frontmatter values",
"- Use these values in the configured `Status` frontmatter property.",
"",
"| Value | Color | Notes |",
"| --------------------------------------------------------------- | ------------------- | -------------------------------------------------------------------------- |",
"| <span style=\"color:#4ea0ff;font-weight:700;\">In Progress</span> | `#4ea0ff` | Highest-priority active work |",
"| <span style=\"color:#2fb859;font-weight:700;\">Ongoing</span> | `#2fb859` | Continuous or recurring work |",
"| <span style=\"color:#d29119;font-weight:700;\">On Hold</span> | `#d29119` | Paused work |",
"| <span style=\"color:#9f63f2;font-weight:700;\">Upcoming</span> | `#9f63f2` | Planned work not yet started |",
"| `Finished` | excluded by default | Hidden from the add-task picker when `Excluded values` contains `finished` |",
"", "",
"## Right click on a time block", "## Right click on a time block",
"", "",
"> [!example] Why this matters", "> [!example] Why subtitles help",
"> Task subtitles are useful when your main task name is a short identifier such as `ABC-123` and you still want a readable label on the board.", "> Task subtitles are useful when your main task name is a short identifier such as `ABC-123` and you still want a readable label on the board.",
"", "",
"- `Open task note`: opens the original task file.", "- `Open task note`: opens the original task file.",
@ -3093,7 +3022,6 @@ module.exports = class ChronoboardPlugin extends Plugin {
"- `Open manual time entry`", "- `Open manual time entry`",
"- `Open selected Chronoboard task`", "- `Open selected Chronoboard task`",
"- `Open Chronoboard guide`", "- `Open Chronoboard guide`",
"- `Open Chronoboard changelog`",
"- `Add TaskNotes fields to current task`", "- `Add TaskNotes fields to current task`",
"", "",
"## Settings overview", "## Settings overview",
@ -3107,58 +3035,7 @@ module.exports = class ChronoboardPlugin extends Plugin {
"- `Hide weekends in week and month views`: hides Saturday and Sunday from those timeline views.", "- `Hide weekends in week and month views`: hides Saturday and Sunday from those timeline views.",
"- `Visible start hour` and `Visible end hour`: control the working-day window shown in day and week views.", "- `Visible start hour` and `Visible end hour`: control the working-day window shown in day and week views.",
"- `Highlight color`: changes the accent color used by Chronoboard controls.", "- `Highlight color`: changes the accent color used by Chronoboard controls.",
"- `Force dark text on colored cards`: helps readability on custom light-colored task cards and blocks.", "- `Force dark text on colored cards`: helps readability on custom light-colored task cards and blocks."
"",
"## Status frontmatter values",
"",
"Use these values in the configured `Status` frontmatter property.",
"",
"| Value | Color | Notes |",
"| --- | --- | --- |",
"| <span style=\"color:#4ea0ff;font-weight:700;\">In Progress</span> | `#4ea0ff` | Highest-priority active work |",
"| <span style=\"color:#2fb859;font-weight:700;\">Ongoing</span> | `#2fb859` | Continuous or recurring work |",
"| <span style=\"color:#d29119;font-weight:700;\">On Hold</span> | `#d29119` | Paused work |",
"| <span style=\"color:#9f63f2;font-weight:700;\">Upcoming</span> | `#9f63f2` | Planned work not yet started |",
"| `Finished` | excluded by default | Hidden from the add-task picker when `Excluded values` contains `finished` |"
].join("\n");
}
buildCurrentReleaseSection() {
const version = this.manifest.version;
return [
`## ${version}`,
"",
"### Highlights",
"",
"- Added managed Chronoboard guide and changelog notes inside the vault.",
"- Added command palette actions for opening the guide and changelog.",
"- Added toolbar help access to open the Chronoboard guide quickly.",
"- Added clearer onboarding around status frontmatter, commands, undo, and interaction flow.",
"- Refined totals sorting controls and per-day header totals presentation.",
"- Improved time entry note handling so renamed notes reopen correctly through entry IDs and aliases.",
"- Added template support for time entry notes with Chronoboard-specific fields appended after template frontmatter.",
"",
"### Clarifications",
"",
"- Double click a time block to remove it.",
"- Hold and drag a time block to move it.",
"- Use `Ctrl+Z` or `Cmd+Z` to undo adding or removing a time block.",
"- Removing a task from the left rail does not remove existing time blocks from the board.",
"",
"### Commands",
"",
"- `Open Chronoboard`",
"- `Add task to Chronoboard`",
"- `Open manual time entry`",
"- `Open selected Chronoboard task`",
"- `Open Chronoboard guide`",
"- `Open Chronoboard changelog`",
"",
"### Roadmap",
"",
"- Additional mobile-specific usability improvements.",
"- More documentation and onboarding polish.",
"- Further manual time entry and totals workflow improvements."
].join("\n"); ].join("\n");
} }

View file

@ -1,7 +1,7 @@
{ {
"id": "chronoboard", "id": "chronoboard",
"name": "Chronoboard", "name": "Chronoboard",
"version": "0.7.0", "version": "0.7.1",
"minAppVersion": "1.5.0", "minAppVersion": "1.5.0",
"description": "A Gantt-style timeboard for project-based time tracking across tasks.", "description": "A Gantt-style timeboard for project-based time tracking across tasks.",
"author": "Emberleif", "author": "Emberleif",

View file

@ -1287,6 +1287,12 @@
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
.chronoboard-layout {
grid-template-columns: 180px minmax(0, 1fr) 180px;
}
}
@media (max-width: 900px) {
.chronoboard-layout { .chronoboard-layout {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }

View file

@ -5,5 +5,6 @@
"0.6.0": "1.5.0", "0.6.0": "1.5.0",
"0.6.1": "1.5.0", "0.6.1": "1.5.0",
"0.6.2": "1.5.0", "0.6.2": "1.5.0",
"0.7.0": "1.5.0" "0.7.0": "1.5.0",
"0.7.1": "1.5.0",
} }