mirror of
https://github.com/Ellpeck/ObsidianSimpleTimeTracker.git
synced 2024-11-26 19:18:34 +01:00
Compare commits
No commits in common. "7aa91901c6831d15ad1782a333b8ad36a0115fa6" and "05a4710b8a9de1a3675443872418a791c1844421" have entirely different histories.
7aa91901c6
...
05a4710b8a
11 changed files with 181 additions and 184 deletions
|
@ -4,6 +4,6 @@ root = true
|
|||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "simple-time-tracker",
|
||||
"name": "Super Simple Time Tracker",
|
||||
"version": "0.1.6",
|
||||
"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.6",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Multi-purpose time trackers for your notes!",
|
||||
"author": "Ellpeck",
|
||||
"authorUrl": "https://ellpeck.de",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
|
44
package.json
44
package.json
|
@ -1,24 +1,24 @@
|
|||
{
|
||||
"name": "simple-time-tracker",
|
||||
"version": "0.1.6",
|
||||
"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.6",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
|
48
src/main.ts
48
src/main.ts
|
@ -1,37 +1,37 @@
|
|||
import { Plugin } 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 {
|
||||
|
||||
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: Tracker = loadTracker(s);
|
||||
e.empty();
|
||||
displayTracker(tracker, e, () => i.getSectionInfo(e), this.settings);
|
||||
});
|
||||
this.registerMarkdownCodeBlockProcessor("simple-time-tracker", (s, e, i) => {
|
||||
let 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(): Promise<void> {
|
||||
this.settings = Object.assign({}, defaultSettings, await this.loadData());
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, defaultSettings, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings(): Promise<void> {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,11 +42,8 @@ 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" });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -266,14 +266,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) {
|
||||
|
|
46
styles.css
46
styles.css
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
"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"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"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",
|
||||
"0.1.6": "0.15.0"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue