mirror of
https://github.com/Ellpeck/ObsidianSimpleTimeTracker.git
synced 2024-05-18 00:08:44 +02:00
Compare commits
17 commits
Author | SHA1 | Date | |
---|---|---|---|
Ell | 3186f1ba4d | ||
Ell | ea04e198d9 | ||
bf9ac5636c | |||
Ell | 6823de48a0 | ||
70cb1594ef | |||
Ell | 66eb45d253 | ||
Ell | 4b6abebe61 | ||
Ell | 4c88c3282d | ||
739e51326f | |||
Ell | 48d576aaa2 | ||
Ell | 701be28601 | ||
Ell | 1d90a17e69 | ||
Ell | 7633ac8144 | ||
Ell | 7e108a85cb | ||
Ell | 5bd9fefe60 | ||
Ell | 3469232d3b | ||
Ell | 92b2a287aa |
10
README.md
10
README.md
|
@ -8,16 +8,16 @@ To get started tracking your time with Super Simple Time Tracker, open up the no
|
|||
|
||||
When switching to live preview or reading mode, you will now see the time tracker you just inserted! Now, simply name the first segment (or leave the box empty if you don't want to name it) and press the **Start** button. Once you're done with the thing you were doing, simply press the **End** button and the time you spent will be saved and displayed to you in the table.
|
||||
|
||||
Need help using the plugin? Feel free to join the Discord server!
|
||||
|
||||
[![Join the Discord server](https://ellpeck.de/res/discord-wide.png)](https://link.ellpeck.de/discordweb)
|
||||
|
||||
# 👀 What it does
|
||||
A time tracker is really just a special code block that stores information about the times you pressed the Start and End buttons on. Since time is tracked solely through timestamps, you can switch notes, close Obsidian or even shut down your device completely while the tracker is running! Once you come back, your time tracker will still be running.
|
||||
|
||||
The tracker's information is stored in the code block as JSON data. The names, start times and end times of each segment are stored. They're displayed neatly in the code block in preview or reading mode.
|
||||
|
||||
# 🛣️ Roadmap
|
||||
Super Simple Time Tracker is still in its early stages! There are a lot of plans for it, including:
|
||||
- A setting to link segments to corresponding daily notes automatically
|
||||
|
||||
# 🙏 Acknowledgements
|
||||
If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!
|
||||
|
||||
[![Support me (if you want), via Patreon, Ko-fi or GitHub Sponsors](https://ellpeck.de/res/generalsupport.png)](https://ellpeck.de/support)
|
||||
[![Support me (if you want), via Patreon, Ko-fi or GitHub Sponsors](https://ellpeck.de/res/generalsupport-wide.png)](https://ellpeck.de/support)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "simple-time-tracker",
|
||||
"name": "Super Simple Time Tracker",
|
||||
"version": "0.1.8",
|
||||
"version": "0.2.1",
|
||||
"minAppVersion": "1.2.8",
|
||||
"description": "Multi-purpose time trackers for your notes!",
|
||||
"author": "Ellpeck",
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "simple-time-tracker",
|
||||
"version": "0.1.7",
|
||||
"version": "0.2.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "simple-time-tracker",
|
||||
"version": "0.1.7",
|
||||
"version": "0.2.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "simple-time-tracker",
|
||||
"version": "0.1.8",
|
||||
"version": "0.2.1",
|
||||
"description": "Multi-purpose time trackers for your notes!",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
27
src/main.ts
27
src/main.ts
|
@ -1,7 +1,7 @@
|
|||
import { Plugin } from "obsidian";
|
||||
import {MarkdownRenderChild, Plugin, TFile} from "obsidian";
|
||||
import { defaultSettings, SimpleTimeTrackerSettings } from "./settings";
|
||||
import { SimpleTimeTrackerSettingsTab } from "./settings-tab";
|
||||
import { displayTracker, loadTracker, Tracker } from "./tracker";
|
||||
import { displayTracker, loadTracker } from "./tracker";
|
||||
|
||||
export default class SimpleTimeTrackerPlugin extends Plugin {
|
||||
|
||||
|
@ -13,9 +13,28 @@ export default class SimpleTimeTrackerPlugin extends Plugin {
|
|||
this.addSettingTab(new SimpleTimeTrackerSettingsTab(this.app, this));
|
||||
|
||||
this.registerMarkdownCodeBlockProcessor("simple-time-tracker", (s, e, i) => {
|
||||
let tracker: Tracker = loadTracker(s);
|
||||
e.empty();
|
||||
displayTracker(tracker, e, i.sourcePath, () => i.getSectionInfo(e), this.settings);
|
||||
let component = new MarkdownRenderChild(e)
|
||||
let tracker = loadTracker(s);
|
||||
|
||||
// Initial file name
|
||||
let filePath = i.sourcePath;
|
||||
|
||||
// Getter passed to displayTracker since the file name can change
|
||||
const getFile = () => filePath;
|
||||
|
||||
// Hook rename events to update the file path
|
||||
const renameEventRef = this.app.vault.on("rename", (file, oldPath) => {
|
||||
if (file instanceof TFile && oldPath === filePath) {
|
||||
filePath = file.path;
|
||||
}
|
||||
})
|
||||
|
||||
// Register the event to remove on unload
|
||||
component.registerEvent(renameEventRef);
|
||||
|
||||
displayTracker(tracker, e, getFile, () => i.getSectionInfo(e), this.settings, component);
|
||||
i.addChild(component)
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
import {App, PluginSettingTab, Setting} from "obsidian";
|
||||
import SimpleTimeTrackerPlugin from "./main";
|
||||
import { defaultSettings } from "./settings";
|
||||
import {defaultSettings} from "./settings";
|
||||
|
||||
export class SimpleTimeTrackerSettingsTab extends PluginSettingTab {
|
||||
|
||||
|
@ -52,6 +52,28 @@ export class SimpleTimeTrackerSettingsTab extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName("Timestamp Durations")
|
||||
.setDesc("Whether durations should be displayed in a timestamp format (12:15:01) rather than the default duration format (12h 15m 1s).")
|
||||
.addToggle(t => {
|
||||
t.setValue(this.plugin.settings.timestampDurations);
|
||||
t.onChange(async v => {
|
||||
this.plugin.settings.timestampDurations = v;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName("Display Segments in Reverse Order")
|
||||
.setDesc("Whether older tracker segments should be displayed towards the bottom of the tracker, rather than the top.")
|
||||
.addToggle(t => {
|
||||
t.setValue(this.plugin.settings.reverseSegmentOrder);
|
||||
t.onChange(async v => {
|
||||
this.plugin.settings.reverseSegmentOrder = v;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
this.containerEl.createEl("hr");
|
||||
this.containerEl.createEl("p", {text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!"});
|
||||
this.containerEl.createEl("a", {href: "https://ellpeck.de/support"})
|
||||
|
|
|
@ -2,7 +2,9 @@ export const defaultSettings: SimpleTimeTrackerSettings = {
|
|||
timestampFormat: "YY-MM-DD HH:mm:ss",
|
||||
editableTimestampFormat: "YYYY-MM-DD HH:mm:ss",
|
||||
csvDelimiter: ",",
|
||||
fineGrainedDurations: true
|
||||
fineGrainedDurations: true,
|
||||
reverseSegmentOrder: false,
|
||||
timestampDurations: false
|
||||
};
|
||||
|
||||
export interface SimpleTimeTrackerSettings {
|
||||
|
@ -11,5 +13,7 @@ export interface SimpleTimeTrackerSettings {
|
|||
editableTimestampFormat: string;
|
||||
csvDelimiter: string;
|
||||
fineGrainedDurations: boolean;
|
||||
reverseSegmentOrder: boolean;
|
||||
timestampDurations: boolean;
|
||||
|
||||
}
|
||||
|
|
203
src/tracker.ts
203
src/tracker.ts
|
@ -1,4 +1,4 @@
|
|||
import {moment, App, MarkdownSectionInformation, ButtonComponent, TextComponent, TFile} from "obsidian";
|
||||
import {moment, App, MarkdownSectionInformation, ButtonComponent, TextComponent, TFile, MarkdownRenderer, Component, MarkdownRenderChild} from "obsidian";
|
||||
import {SimpleTimeTrackerSettings} from "./settings";
|
||||
|
||||
export interface Tracker {
|
||||
|
@ -41,8 +41,11 @@ export function loadTracker(json: string): Tracker {
|
|||
return {entries: []};
|
||||
}
|
||||
|
||||
export function displayTracker(tracker: Tracker, element: HTMLElement, file: string, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings): void {
|
||||
element.classList.add("simple-time-tracker-container");
|
||||
type GetFile = () => string;
|
||||
|
||||
export function displayTracker(tracker: Tracker, element: HTMLElement, getFile: GetFile, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings, component: MarkdownRenderChild): void {
|
||||
|
||||
element.addClass("simple-time-tracker-container");
|
||||
// add start/stop controls
|
||||
let running = isRunning(tracker);
|
||||
let btn = new ButtonComponent(element)
|
||||
|
@ -55,7 +58,7 @@ export function displayTracker(tracker: Tracker, element: HTMLElement, file: str
|
|||
} else {
|
||||
startNewEntry(tracker, newSegmentNameBox.getValue());
|
||||
}
|
||||
await saveTracker(tracker, this.app, file, getSectionInfo());
|
||||
await saveTracker(tracker, this.app, getFile(), getSectionInfo());
|
||||
});
|
||||
btn.buttonEl.addClass("simple-time-tracker-btn");
|
||||
let newSegmentNameBox = new TextComponent(element)
|
||||
|
@ -82,8 +85,8 @@ export function displayTracker(tracker: Tracker, element: HTMLElement, file: str
|
|||
createEl("th", {text: "Duration"}),
|
||||
createEl("th"));
|
||||
|
||||
for (let entry of tracker.entries)
|
||||
addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, file, getSectionInfo, settings, 0);
|
||||
for (let entry of orderedEntries(tracker.entries, settings))
|
||||
addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, getFile, getSectionInfo, settings, 0, component);
|
||||
|
||||
// add copy buttons
|
||||
let buttons = element.createEl("div", {cls: "simple-time-tracker-bottom"});
|
||||
|
@ -215,29 +218,37 @@ function unformatEditableTimestamp(formatted: string, settings: SimpleTimeTracke
|
|||
function formatDuration(totalTime: number, settings: SimpleTimeTrackerSettings): string {
|
||||
let ret = "";
|
||||
let duration = moment.duration(totalTime);
|
||||
let hours: number;
|
||||
if (settings.fineGrainedDurations) {
|
||||
if (duration.years() > 0)
|
||||
ret += duration.years() + "y ";
|
||||
if (duration.months() > 0)
|
||||
ret += duration.months() + "M ";
|
||||
if (duration.days() > 0)
|
||||
ret += duration.days() + "d ";
|
||||
hours = duration.hours();
|
||||
let hours = settings.fineGrainedDurations ? duration.hours() : Math.floor(duration.asHours());
|
||||
|
||||
if (settings.timestampDurations) {
|
||||
if (settings.fineGrainedDurations) {
|
||||
let days = Math.floor(duration.asDays());
|
||||
if (days > 0)
|
||||
ret += days + ".";
|
||||
}
|
||||
ret += `${hours.toString().padStart(2, "0")}:${duration.minutes().toString().padStart(2, "0")}:${duration.seconds().toString().padStart(2, "0")}`;
|
||||
} else {
|
||||
hours = Math.floor(duration.asHours());
|
||||
if (settings.fineGrainedDurations) {
|
||||
let years = Math.floor(duration.asYears());
|
||||
if (years > 0)
|
||||
ret += years + "y ";
|
||||
if (duration.months() > 0)
|
||||
ret += duration.months() + "M ";
|
||||
if (duration.days() > 0)
|
||||
ret += duration.days() + "d ";
|
||||
}
|
||||
if (hours > 0)
|
||||
ret += hours + "h ";
|
||||
if (duration.minutes() > 0)
|
||||
ret += duration.minutes() + "m ";
|
||||
ret += duration.seconds() + "s";
|
||||
}
|
||||
if (hours > 0)
|
||||
ret += hours + "h ";
|
||||
if (duration.minutes() > 0)
|
||||
ret += duration.minutes() + "m ";
|
||||
ret += duration.seconds() + "s";
|
||||
return ret;
|
||||
}
|
||||
|
||||
function fixLegacyTimestamps(entries: Entry[]): void {
|
||||
for (let entry of entries) {
|
||||
if (!isNaN(+entry.startTime))
|
||||
if (entry.startTime && !isNaN(+entry.startTime))
|
||||
entry.startTime = moment.unix(+entry.startTime).toISOString();
|
||||
if (entry.endTime && !isNaN(+entry.endTime))
|
||||
entry.endTime = moment.unix(+entry.endTime).toISOString();
|
||||
|
@ -249,7 +260,7 @@ function fixLegacyTimestamps(entries: Entry[]): void {
|
|||
|
||||
function createMarkdownTable(tracker: Tracker, settings: SimpleTimeTrackerSettings): string {
|
||||
let table = [["Segment", "Start time", "End time", "Duration"]];
|
||||
for (let entry of tracker.entries)
|
||||
for (let entry of orderedEntries(tracker.entries, settings))
|
||||
table.push(...createTableSection(entry, settings));
|
||||
table.push(["**Total**", "", "", `**${formatDuration(getTotalDuration(tracker.entries), settings)}**`]);
|
||||
|
||||
|
@ -271,7 +282,7 @@ function createMarkdownTable(tracker: Tracker, settings: SimpleTimeTrackerSettin
|
|||
|
||||
function createCsv(tracker: Tracker, settings: SimpleTimeTrackerSettings): string {
|
||||
let ret = "";
|
||||
for (let entry of tracker.entries) {
|
||||
for (let entry of orderedEntries(tracker.entries, settings)) {
|
||||
for (let row of createTableSection(entry, settings))
|
||||
ret += row.join(settings.csvDelimiter) + "\n";
|
||||
}
|
||||
|
@ -285,12 +296,93 @@ function createTableSection(entry: Entry, settings: SimpleTimeTrackerSettings):
|
|||
entry.endTime ? formatTimestamp(entry.endTime, settings) : "",
|
||||
entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""]];
|
||||
if (entry.subEntries) {
|
||||
for (let sub of entry.subEntries)
|
||||
for (let sub of orderedEntries(entry.subEntries, settings))
|
||||
ret.push(...createTableSection(sub, settings));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function orderedEntries(entries: Entry[], settings: SimpleTimeTrackerSettings): Entry[] {
|
||||
return settings.reverseSegmentOrder ? entries.slice().reverse() : entries;
|
||||
}
|
||||
|
||||
function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableElement, newSegmentNameBox: TextComponent, trackerRunning: boolean, getFile: GetFile, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings, indent: number, component: MarkdownRenderChild): void {
|
||||
let entryRunning = getRunningEntry(tracker.entries) == entry;
|
||||
let row = table.createEl("tr");
|
||||
|
||||
let nameField = new EditableField(row, indent, entry.name);
|
||||
let startField = new EditableTimestampField(row, (entry.startTime), settings);
|
||||
let endField = new EditableTimestampField(row, (entry.endTime), settings);
|
||||
|
||||
row.createEl("td", {text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""});
|
||||
|
||||
renderNameAsMarkdown(nameField.label, getFile, component);
|
||||
|
||||
let entryButtons = row.createEl("td");
|
||||
entryButtons.addClass("simple-time-tracker-table-buttons");
|
||||
new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setIcon(`lucide-play`)
|
||||
.setTooltip("Continue")
|
||||
.setDisabled(trackerRunning)
|
||||
.onClick(async () => {
|
||||
startSubEntry(entry, newSegmentNameBox.getValue());
|
||||
await saveTracker(tracker, this.app, getFile(), getSectionInfo());
|
||||
});
|
||||
let editButton = new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Edit")
|
||||
.setIcon("lucide-pencil")
|
||||
.onClick(async () => {
|
||||
if (nameField.editing()) {
|
||||
entry.name = nameField.endEdit();
|
||||
startField.endEdit();
|
||||
entry.startTime = startField.getTimestamp();
|
||||
if (!entryRunning) {
|
||||
endField.endEdit();
|
||||
entry.endTime = endField.getTimestamp();
|
||||
}
|
||||
await saveTracker(tracker, this.app, getFile(), getSectionInfo());
|
||||
editButton.setIcon("lucide-pencil");
|
||||
|
||||
renderNameAsMarkdown(nameField.label, getFile, component);
|
||||
} else {
|
||||
nameField.beginEdit(entry.name);
|
||||
// only allow editing start and end times if we don't have sub entries
|
||||
if (!entry.subEntries) {
|
||||
startField.beginEdit(entry.startTime);
|
||||
if (!entryRunning)
|
||||
endField.beginEdit(entry.endTime);
|
||||
}
|
||||
editButton.setIcon("lucide-check");
|
||||
}
|
||||
});
|
||||
new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Remove")
|
||||
.setIcon("lucide-trash")
|
||||
.setDisabled(entryRunning)
|
||||
.onClick(async () => {
|
||||
if (!confirm("Are you sure you want to delete this entry?")) {
|
||||
return;
|
||||
}
|
||||
removeEntry(tracker.entries, entry);
|
||||
await saveTracker(tracker, this.app, getFile(), getSectionInfo());
|
||||
});
|
||||
|
||||
if (entry.subEntries) {
|
||||
for (let sub of orderedEntries(entry.subEntries, settings))
|
||||
addEditableTableRow(tracker, sub, table, newSegmentNameBox, trackerRunning, getFile, getSectionInfo, settings, indent + 1, component);
|
||||
}
|
||||
}
|
||||
|
||||
function renderNameAsMarkdown(label: HTMLSpanElement, getFile: GetFile, component: Component): void {
|
||||
void MarkdownRenderer.renderMarkdown(label.innerHTML, label, getFile(), component);
|
||||
// rendering wraps it in a paragraph
|
||||
label.innerHTML = label.querySelector("p").innerHTML;
|
||||
}
|
||||
|
||||
|
||||
class EditableField {
|
||||
cell: HTMLTableCellElement;
|
||||
label: HTMLSpanElement;
|
||||
|
@ -301,7 +393,7 @@ class EditableField {
|
|||
this.label = this.cell.createEl("span", {text: value});
|
||||
this.label.style.marginLeft = `${indent}em`;
|
||||
this.box = new TextComponent(this.cell).setValue(value);
|
||||
this.box.inputEl.classList.add("simple-time-tracker-input");
|
||||
this.box.inputEl.addClass("simple-time-tracker-input");
|
||||
this.box.inputEl.hide();
|
||||
}
|
||||
|
||||
|
@ -327,8 +419,8 @@ class EditableField {
|
|||
class EditableTimestampField extends EditableField {
|
||||
settings: SimpleTimeTrackerSettings;
|
||||
|
||||
constructor(row: HTMLTableRowElement, indent: number, value: string, settings: SimpleTimeTrackerSettings) {
|
||||
super(row, indent, value ? formatTimestamp(value, settings) : "");
|
||||
constructor(row: HTMLTableRowElement, value: string, settings: SimpleTimeTrackerSettings) {
|
||||
super(row, 0, value ? formatTimestamp(value, settings) : "");
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
|
@ -357,58 +449,3 @@ class EditableTimestampField extends EditableField {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableElement, newSegmentNameBox: TextComponent, running: boolean, file: string, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings, indent: number): void {
|
||||
let row = table.createEl("tr");
|
||||
|
||||
let nameField = new EditableField(row, indent, entry.name);
|
||||
let startField = new EditableTimestampField(row, indent, (entry.startTime), settings);
|
||||
let endField = new EditableTimestampField(row, indent, (entry.endTime), settings);
|
||||
|
||||
row.createEl("td", {text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry), settings) : ""});
|
||||
|
||||
let entryButtons = row.createEl("td");
|
||||
if (!running) {
|
||||
new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setIcon(`lucide-play`)
|
||||
.setTooltip("Continue")
|
||||
.onClick(async () => {
|
||||
startSubEntry(entry, newSegmentNameBox.getValue());
|
||||
await saveTracker(tracker, this.app, file, getSectionInfo());
|
||||
});
|
||||
}
|
||||
let editButton = new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Edit")
|
||||
.setIcon("lucide-pencil")
|
||||
.onClick(async () => {
|
||||
if (nameField.editing()) {
|
||||
entry.name = nameField.endEdit();
|
||||
startField.endEdit();
|
||||
entry.startTime = startField.getTimestamp();
|
||||
endField.endEdit();
|
||||
entry.endTime = endField.getTimestamp();
|
||||
await saveTracker(tracker, this.app, file, getSectionInfo());
|
||||
editButton.setIcon("lucide-pencil");
|
||||
} else {
|
||||
nameField.beginEdit(entry.name);
|
||||
startField.beginEdit((entry.startTime));
|
||||
endField.beginEdit((entry.endTime));
|
||||
editButton.setIcon("lucide-check");
|
||||
}
|
||||
});
|
||||
new ButtonComponent(entryButtons)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Remove")
|
||||
.setIcon("lucide-trash")
|
||||
.onClick(async () => {
|
||||
removeEntry(tracker.entries, entry);
|
||||
await saveTracker(tracker, this.app, file, getSectionInfo());
|
||||
});
|
||||
|
||||
if (entry.subEntries) {
|
||||
for (let sub of entry.subEntries)
|
||||
addEditableTableRow(tracker, sub, table, newSegmentNameBox, running, file, getSectionInfo, settings, indent + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
.simple-time-tracker-table td,
|
||||
.simple-time-tracker-table th {
|
||||
vertical-align: middle;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
@ -71,3 +72,11 @@
|
|||
max-width: 150px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.simple-time-tracker-table-buttons {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
.simple-time-tracker-table tr:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"timestampFormat": "YY-MM-DD hh:mm:ss",
|
||||
"editableTimestampFormat": "YYYY-MM-DD HH:mm:ss",
|
||||
"csvDelimiter": ",",
|
||||
"fineGrainedDurations": false
|
||||
"fineGrainedDurations": true,
|
||||
"reverseSegmentOrder": false,
|
||||
"timestampDurations": true
|
||||
}
|
|
@ -2,5 +2,9 @@
|
|||
More notes for my cool project! This note shows that we can correctly display accumulated time that lasts longer than a 24 hour day!
|
||||
|
||||
```simple-time-tracker
|
||||
{"entries":[{"name":"test","startTime":1596265200,"endTime":1627887600,"subEntries":null},{"name":"test","startTime":1627801200,"endTime":1633158000,"subEntries":null},{"name":"test","startTime":1659337200,"endTime":1659423600,"subEntries":null},{"name":"test","startTime":1664627410,"endTime":1664631605,"subEntries":null},{"name":"Segment 5","startTime":1684858616,"endTime":1684858619,"subEntries":null}]}
|
||||
{"entries":[{"name":"test","startTime":"2020-08-01T07:00:00.000Z","endTime":"2021-08-02T07:00:00.000Z","subEntries":null},{"name":"test","startTime":"2021-08-01T07:00:00.000Z","endTime":"2021-10-02T07:00:00.000Z","subEntries":null},{"name":"test","startTime":"1970-01-01T00:00:00.000Z","endTime":null,"subEntries":[{"name":"Part 1","startTime":"2022-08-01T07:00:00.000Z","endTime":"2022-08-02T07:00:00.000Z","subEntries":null},{"name":"Part 2","startTime":"2024-02-26T13:19:40.629Z","endTime":"2024-02-26T13:19:43.713Z","subEntries":null},{"name":"Part 3","startTime":"1970-01-01T00:00:00.000Z","endTime":null,"subEntries":[{"name":"Part 1","startTime":"2024-02-26T13:23:51.939Z","endTime":"2024-02-26T13:23:54.232Z","subEntries":null},{"name":"Part 2","startTime":"2024-02-26T13:27:34.397Z","endTime":"2024-02-26T13:27:49.282Z","subEntries":null}]},{"name":"Part 4","startTime":"2024-02-26T13:29:06.983Z","endTime":"2024-02-26T13:29:20.770Z","subEntries":null}]},{"name":"test","startTime":"2022-10-01T12:30:10.000Z","endTime":"2022-10-01T13:40:05.000Z","subEntries":null},{"name":"Segment 5","startTime":"1970-01-01T00:00:00.000Z","endTime":null,"subEntries":[{"name":"Part 1","startTime":"2023-05-23T16:16:56.000Z","endTime":"2023-05-23T16:16:59.000Z","subEntries":null},{"name":"Part 2","startTime":"1970-01-01T00:00:00.000Z","endTime":null,"subEntries":[{"name":"Part 1","startTime":"2024-02-26T13:30:39.632Z","endTime":"2024-02-26T13:30:56.290Z","subEntries":null},{"name":"Part 2","startTime":"2024-02-26T13:30:57.000Z","endTime":"2024-02-26T13:31:00.000Z","subEntries":null}]},{"name":"Part 3","startTime":"2024-02-26T13:34:18.537Z","endTime":"2024-02-26T13:34:21.169Z","subEntries":null}]}]}
|
||||
```
|
||||
|
||||
```simple-time-tracker
|
||||
{"entries":[{"name":"Segment 1","startTime":null,"endTime":null,"subEntries":[{"name":"Part 1","startTime":null,"endTime":null,"subEntries":[{"name":"Part 1","startTime":"2024-02-26T13:37:59.292Z","endTime":"2024-02-26T13:38:01.437Z","subEntries":null},{"name":"Part 2","startTime":"2024-02-26T14:04:14.156Z","endTime":"2024-02-26T14:04:30.576Z","subEntries":null}]},{"name":"Part 2","startTime":"2024-02-26T13:38:16.235Z","endTime":"2024-02-26T13:38:18.895Z","subEntries":null}]}]}
|
||||
```
|
||||
|
|
4
test-vault/test-markdown.md
Normal file
4
test-vault/test-markdown.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
Tested for #tag, *italic*, [link](test2), etc:
|
||||
```simple-time-tracker
|
||||
{"entries":[{"name":"`Segment 1`","startTime":"2022-09-27T19:51:18.000Z","endTime":"2022-09-27T19:51:24.000Z"},{"name":"Segment 2","startTime":"2022-09-27T19:51:25.000Z","endTime":"2022-09-27T19:51:26.000Z"},{"name":"#tag Seqment 3 *add* #tag1 text","startTime":null,"endTime":null,"subEntries":[{"name":"Part 1 #tagp1","startTime":"2024-03-17T11:16:00.382Z","endTime":"2024-03-17T11:16:15.966Z","subEntries":null},{"name":"Part 3","startTime":"2024-03-17T11:17:08.000Z","endTime":"2024-03-17T11:17:24.000Z","subEntries":null}]},{"name":"#tag3 Segment 4","startTime":null,"endTime":null,"subEntries":[{"name":"Part 1 #tag4","startTime":"2024-03-17T12:22:04.000Z","endTime":"2024-03-17T12:22:16.000Z","subEntries":null},{"name":"#tag5 Part 2 *italic*","startTime":"2024-03-17T12:22:20.000Z","endTime":"2024-03-17T12:22:24.000Z","subEntries":null}]},{"name":"*italic* Segment 5 #tag6 [test2](test2)","startTime":"2024-03-17T12:40:37.000Z","endTime":"2024-03-17T12:40:45.000Z","subEntries":null},{"name":"Segment 6","startTime":"2024-03-27T13:20:56.000Z","endTime":null,"subEntries":null}]}
|
||||
```
|
|
@ -8,5 +8,7 @@
|
|||
"0.1.5": "0.15.0",
|
||||
"0.1.6": "0.15.0",
|
||||
"0.1.7": "1.2.8",
|
||||
"0.1.8": "1.3.0"
|
||||
"0.1.8": "1.3.0",
|
||||
"0.2.0": "1.3.0",
|
||||
"0.2.1": "1.3.0"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue