This commit is contained in:
Ell 2023-05-22 20:01:50 +02:00
parent 402b97c799
commit 70ade8ada0
11 changed files with 184 additions and 181 deletions

View file

@ -4,6 +4,6 @@ root = true
[*]
charset = utf-8
insert_final_newline = true
indent_style = tab
indent_style = space
indent_size = 4
tab_width = 4

View file

@ -9,7 +9,7 @@ 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.
# 👀 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.
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.

View file

@ -11,50 +11,50 @@ if you want to view the source, please visit the github repository of this plugi
const prod = (process.argv[2] === 'production');
esbuild.build({
banner: {
js: banner,
},
entryPoints: ['src/main.ts'],
bundle: true,
external: [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/closebrackets',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/comment',
'@codemirror/fold',
'@codemirror/gutter',
'@codemirror/highlight',
'@codemirror/history',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/matchbrackets',
'@codemirror/panel',
'@codemirror/rangeset',
'@codemirror/rectangular-selection',
'@codemirror/search',
'@codemirror/state',
'@codemirror/stream-parser',
'@codemirror/text',
'@codemirror/tooltip',
'@codemirror/view',
...builtins
],
plugins: [
copy({
assets: [{
from: ["./manifest.json", "./main.js", "./styles.css"],
to: ["./test-vault/.obsidian/plugins/simple-time-tracker/."]
}]
}),
],
format: 'cjs',
watch: !prod,
target: 'es2016',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
banner: {
js: banner,
},
entryPoints: ['src/main.ts'],
bundle: true,
external: [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/closebrackets',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/comment',
'@codemirror/fold',
'@codemirror/gutter',
'@codemirror/highlight',
'@codemirror/history',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/matchbrackets',
'@codemirror/panel',
'@codemirror/rangeset',
'@codemirror/rectangular-selection',
'@codemirror/search',
'@codemirror/state',
'@codemirror/stream-parser',
'@codemirror/text',
'@codemirror/tooltip',
'@codemirror/view',
...builtins
],
plugins: [
copy({
assets: [{
from: ["./manifest.json", "./main.js", "./styles.css"],
to: ["./test-vault/.obsidian/plugins/simple-time-tracker/."]
}]
}),
],
format: 'cjs',
watch: !prod,
target: 'es2016',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
}).catch(() => process.exit(1));

View file

@ -1,10 +1,10 @@
{
"id": "simple-time-tracker",
"name": "Super Simple Time Tracker",
"version": "0.1.5",
"minAppVersion": "0.15.0",
"description": "Multi-purpose time trackers for your notes!",
"author": "Ellpeck",
"authorUrl": "https://ellpeck.de",
"isDesktopOnly": false
"id": "simple-time-tracker",
"name": "Super Simple Time Tracker",
"version": "0.1.5",
"minAppVersion": "0.15.0",
"description": "Multi-purpose time trackers for your notes!",
"author": "Ellpeck",
"authorUrl": "https://ellpeck.de",
"isDesktopOnly": false
}

View file

@ -1,24 +1,24 @@
{
"name": "simple-time-tracker",
"version": "0.1.5",
"description": "Multi-purpose time trackers for your notes!",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "Ellpeck",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
"builtin-modules": "^3.2.0",
"electron": "^13.6.2",
"esbuild": "0.14.0",
"esbuild-plugin-copy": "^1.3.0",
"obsidian": "latest",
"tslib": "2.3.1",
"typescript": "4.4.4"
}
"name": "simple-time-tracker",
"version": "0.1.5",
"description": "Multi-purpose time trackers for your notes!",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "Ellpeck",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
"builtin-modules": "^3.2.0",
"electron": "^13.6.2",
"esbuild": "0.14.0",
"esbuild-plugin-copy": "^1.3.0",
"obsidian": "latest",
"tslib": "2.3.1",
"typescript": "4.4.4"
}
}

View file

@ -1,37 +1,37 @@
import { Plugin } from "obsidian";
import { defaultSettings, SimpleTimeTrackerSettings } from "./settings";
import { SimpleTimeTrackerSettingsTab } from "./settings-tab";
import { displayTracker, loadTracker } from "./tracker";
import { displayTracker, loadTracker, Tracker } from "./tracker";
export default class SimpleTimeTrackerPlugin extends Plugin {
settings: SimpleTimeTrackerSettings;
settings: SimpleTimeTrackerSettings;
async onload(): Promise<void> {
await this.loadSettings();
async onload(): Promise<void> {
await this.loadSettings();
this.addSettingTab(new SimpleTimeTrackerSettingsTab(this.app, this));
this.addSettingTab(new SimpleTimeTrackerSettingsTab(this.app, this));
this.registerMarkdownCodeBlockProcessor("simple-time-tracker", (s, e, i) => {
let tracker = loadTracker(s);
e.empty();
displayTracker(tracker, e, () => i.getSectionInfo(e), this.settings);
});
this.registerMarkdownCodeBlockProcessor("simple-time-tracker", (s, e, i) => {
let tracker: Tracker = loadTracker(s);
e.empty();
displayTracker(tracker, e, () => i.getSectionInfo(e), this.settings);
});
this.addCommand({
id: `insert`,
name: `Insert Time Tracker`,
editorCallback: (e, _) => {
e.replaceSelection("```simple-time-tracker\n```\n");
}
});
}
this.addCommand({
id: `insert`,
name: `Insert Time Tracker`,
editorCallback: (e, _) => {
e.replaceSelection("```simple-time-tracker\n```\n");
}
});
}
async loadSettings() {
this.settings = Object.assign({}, defaultSettings, await this.loadData());
}
async loadSettings(): Promise<void> {
this.settings = Object.assign({}, defaultSettings, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
async saveSettings(): Promise<void> {
await this.saveData(this.settings);
}
}

View file

@ -13,14 +13,14 @@ export class SimpleTimeTrackerSettingsTab extends PluginSettingTab {
display(): void {
this.containerEl.empty();
this.containerEl.createEl("h2", { text: "Super Simple Time Tracker Settings" });
this.containerEl.createEl("h2", {text: "Super Simple Time Tracker Settings"});
new Setting(this.containerEl)
.setName("Timestamp Display Format")
.setDesc(createFragment(f => {
f.createSpan({ text: "The way that timestamps in time tracker tables should be displayed. Uses " });
f.createEl("a", { text: "moment.js", href: "https://momentjs.com/docs/#/parsing/string-format/" });
f.createSpan({ text: " syntax." });
f.createSpan({text: "The way that timestamps in time tracker tables should be displayed. Uses "});
f.createEl("a", {text: "moment.js", href: "https://momentjs.com/docs/#/parsing/string-format/"});
f.createSpan({text: " syntax."});
}))
.addText(t => {
t.setValue(String(this.plugin.settings.timestampFormat));
@ -42,8 +42,11 @@ export class SimpleTimeTrackerSettingsTab extends PluginSettingTab {
});
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" })
.createEl("img", { attr: { src: "https://ellpeck.de/res/generalsupport.png" }, cls: "simple-time-tracker-support" });
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"})
.createEl("img", {
attr: {src: "https://ellpeck.de/res/generalsupport.png"},
cls: "simple-time-tracker-support"
});
}
}

View file

@ -36,7 +36,7 @@ export function loadTracker(json: string): Tracker {
console.log(`Failed to parse Tracker from ${json}`);
}
}
return { entries: [] };
return {entries: []};
}
export function displayTracker(tracker: Tracker, element: HTMLElement, getSectionInfo: () => MarkdownSectionInformation, settings: SimpleTimeTrackerSettings): void {
@ -61,29 +61,29 @@ export function displayTracker(tracker: Tracker, element: HTMLElement, getSectio
newSegmentNameBox.inputEl.addClass("simple-time-tracker-txt");
// add timers
let timer = element.createDiv({ cls: "simple-time-tracker-timers" });
let currentDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" });
let current = currentDiv.createEl("span", { cls: "simple-time-tracker-timer-time" });
currentDiv.createEl("span", { text: "Current" });
let totalDiv = timer.createEl("div", { cls: "simple-time-tracker-timer" });
let total = totalDiv.createEl("span", { cls: "simple-time-tracker-timer-time", text: "0s" });
totalDiv.createEl("span", { text: "Total" });
let timer = element.createDiv({cls: "simple-time-tracker-timers"});
let currentDiv = timer.createEl("div", {cls: "simple-time-tracker-timer"});
let current = currentDiv.createEl("span", {cls: "simple-time-tracker-timer-time"});
currentDiv.createEl("span", {text: "Current"});
let totalDiv = timer.createEl("div", {cls: "simple-time-tracker-timer"});
let total = totalDiv.createEl("span", {cls: "simple-time-tracker-timer-time", text: "0s"});
totalDiv.createEl("span", {text: "Total"});
if (tracker.entries.length > 0) {
// add table
let table = element.createEl("table", { cls: "simple-time-tracker-table" });
let table = element.createEl("table", {cls: "simple-time-tracker-table"});
table.createEl("tr").append(
createEl("th", { text: "Segment" }),
createEl("th", { text: "Start time" }),
createEl("th", { text: "End time" }),
createEl("th", { text: "Duration" }),
createEl("th", {text: "Segment"}),
createEl("th", {text: "Start time"}),
createEl("th", {text: "End time"}),
createEl("th", {text: "Duration"}),
createEl("th"));
for (let entry of tracker.entries)
addEditableTableRow(tracker, entry, table, newSegmentNameBox, running, getSectionInfo, settings, 0);
// add copy buttons
let buttons = element.createEl("div", { cls: "simple-time-tracker-bottom" });
let buttons = element.createEl("div", {cls: "simple-time-tracker-bottom"});
new ButtonComponent(buttons)
.setButtonText("Copy as table")
.onClick(() => navigator.clipboard.writeText(createMarkdownTable(tracker, settings)));
@ -107,22 +107,22 @@ export function displayTracker(tracker: Tracker, element: HTMLElement, getSectio
function startSubEntry(entry: Entry, name: string) {
// if this entry is not split yet, we add its time as a sub-entry instead
if (!entry.subEntries) {
entry.subEntries = [{ ...entry, name: `Part 1` }];
entry.subEntries = [{...entry, name: `Part 1`}];
entry.startTime = null;
entry.endTime = null;
}
if (!name)
name = `Part ${entry.subEntries.length + 1}`;
entry.subEntries.push({ name: name, startTime: moment().unix(), endTime: null, subEntries: null });
entry.subEntries.push({name: name, startTime: moment().unix(), endTime: null, subEntries: null});
}
function startNewEntry(tracker: Tracker, name: string): void {
if (!name)
name = `Segment ${tracker.entries.length + 1}`;
let entry: Entry = { name: name, startTime: moment().unix(), endTime: null, subEntries: null };
let entry: Entry = {name: name, startTime: moment().unix(), endTime: null, subEntries: null};
tracker.entries.push(entry);
};
}
function endRunningEntry(tracker: Tracker): void {
let entry = getRunningEntry(tracker.entries);
@ -260,14 +260,14 @@ function addEditableTableRow(tracker: Tracker, entry: Entry, table: HTMLTableEle
let row = table.createEl("tr");
let name = row.createEl("td");
let namePar = name.createEl("span", { text: entry.name });
let namePar = name.createEl("span", {text: entry.name});
namePar.style.marginLeft = `${indent}em`;
let nameBox = new TextComponent(name).setValue(entry.name);
nameBox.inputEl.hidden = true;
row.createEl("td", { text: entry.startTime ? formatTimestamp(entry.startTime, settings) : "" });
row.createEl("td", { text: entry.endTime ? formatTimestamp(entry.endTime, settings) : "" });
row.createEl("td", { text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry)) : "" });
row.createEl("td", {text: entry.startTime ? formatTimestamp(entry.startTime, settings) : ""});
row.createEl("td", {text: entry.endTime ? formatTimestamp(entry.endTime, settings) : ""});
row.createEl("td", {text: entry.endTime || entry.subEntries ? formatDuration(getDuration(entry)) : ""});
let entryButtons = row.createEl("td");
if (!running) {

View file

@ -1,64 +1,64 @@
.simple-time-tracker-support {
max-width: 50%;
width: 400px;
height: auto;
max-width: 50%;
width: 400px;
height: auto;
}
.simple-time-tracker-btn,
.simple-time-tracker-txt {
display: block;
margin-left: auto;
margin-right: auto;
display: block;
margin-left: auto;
margin-right: auto;
}
.simple-time-tracker-txt {
text-align: center;
text-align: center;
}
.simple-time-tracker-btn {
margin-top: 10px;
margin-bottom: 10px;
margin-top: 10px;
margin-bottom: 10px;
}
.simple-time-tracker-btn svg {
width: 32px;
height: 32px;
width: 32px;
height: 32px;
}
.simple-time-tracker-bottom button {
margin: 10px 5px 10px 5px;
margin: 10px 5px 10px 5px;
}
.simple-time-tracker-timers,
.simple-time-tracker-bottom {
display: flex;
justify-content: center;
text-align: center;
display: flex;
justify-content: center;
text-align: center;
}
.simple-time-tracker-timers span {
display: block;
display: block;
}
.simple-time-tracker-timer {
margin: 20px;
margin: 20px;
}
.simple-time-tracker-timer-time {
font-size: xx-large;
font-weight: bolder;
font-size: xx-large;
font-weight: bolder;
}
.simple-time-tracker-table {
width: 100%;
margin-top: 20px;
width: 100%;
margin-top: 20px;
}
.simple-time-tracker-table td,
.simple-time-tracker-table th {
border: none;
border: none;
}
.simple-time-tracker-table .clickable-icon {
display: inline;
display: inline;
}

View file

@ -1,23 +1,23 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
]
},
"include": [
"**/*.ts"
]
},
"include": [
"**/*.ts"
]
}

View file

@ -1,9 +1,9 @@
{
"0.0.1": "0.15.0",
"0.1.0": "0.15.0",
"0.1.1": "0.15.0",
"0.1.2": "0.15.0",
"0.1.3": "0.15.0",
"0.1.4": "0.15.0",
"0.1.5": "0.15.0"
"0.0.1": "0.15.0",
"0.1.0": "0.15.0",
"0.1.1": "0.15.0",
"0.1.2": "0.15.0",
"0.1.3": "0.15.0",
"0.1.4": "0.15.0",
"0.1.5": "0.15.0"
}