Startzeitpunkt manipulierbar
This commit is contained in:
parent
35659829c9
commit
d63f8cb7b2
@ -85,6 +85,33 @@ export class TimerService {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public updateActiveStart(startedAtEpochMs: number): TrackerState {
|
||||
const active = this.state.activeTimer;
|
||||
if (!active) {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
if (!Number.isFinite(startedAtEpochMs)) {
|
||||
throw new Error("Invalid start timestamp.");
|
||||
}
|
||||
|
||||
const now = nowMs();
|
||||
if (startedAtEpochMs > now) {
|
||||
throw new Error("Start must be less than or equal to now.");
|
||||
}
|
||||
|
||||
this.state = {
|
||||
...this.state,
|
||||
activeTimer: {
|
||||
...active,
|
||||
startedAtEpochMs
|
||||
}
|
||||
};
|
||||
|
||||
this.persist();
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public switchToPage(page: PageRef): TrackerState {
|
||||
if (this.state.activeTimer?.pageUuid === page.uuid) {
|
||||
return this.state;
|
||||
|
||||
83
src/ui.ts
83
src/ui.ts
@ -54,6 +54,8 @@ export class TimetrackerUi {
|
||||
private readonly listPages: () => Promise<PageRef[]>;
|
||||
private intervalId: number | null = null;
|
||||
private editDraft: EditDraft | null = null;
|
||||
private activeStartDraft: string | null = null;
|
||||
private isEditingActiveStart = false;
|
||||
private pageOptions: PageRef[] = [];
|
||||
|
||||
constructor(
|
||||
@ -71,8 +73,8 @@ export class TimetrackerUi {
|
||||
this.bindEvents();
|
||||
this.render();
|
||||
this.intervalId = window.setInterval(() => {
|
||||
// Keep focus stable while an entry is being edited.
|
||||
if (this.editDraft) {
|
||||
// Keep focus stable while any form field is being edited.
|
||||
if (this.editDraft || this.isEditingActiveStart) {
|
||||
return;
|
||||
}
|
||||
this.render();
|
||||
@ -90,7 +92,13 @@ export class TimetrackerUi {
|
||||
const app = this.ensureContainer();
|
||||
const state = this.service.getState();
|
||||
const active = state.activeTimer;
|
||||
const activeDuration = active ? Date.now() - active.startedAtEpochMs : 0;
|
||||
const activeDuration = active ? Math.max(0, Date.now() - active.startedAtEpochMs) : 0;
|
||||
|
||||
if (!active && this.activeStartDraft !== null) {
|
||||
this.activeStartDraft = null;
|
||||
}
|
||||
|
||||
const activeStartValue = active ? this.activeStartDraft ?? toIsoLocalInput(active.startedAtEpochMs) : "";
|
||||
|
||||
const daySummaries = computeDaySummaries(state.entries);
|
||||
const weekSummaries = computeWeekSummaries(state.entries);
|
||||
@ -139,6 +147,20 @@ export class TimetrackerUi {
|
||||
<button id="tt-stop">Stop active</button>
|
||||
<button id="tt-export">Export JSON</button>
|
||||
</div>
|
||||
${active
|
||||
? `<div class="tt-edit-panel">
|
||||
<strong>Active timer</strong>
|
||||
<div class="tt-edit-grid">
|
||||
<label>
|
||||
<span>Start</span>
|
||||
<input id="tt-active-start" type="datetime-local" value="${this.escapeAttribute(activeStartValue)}" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="tt-actions">
|
||||
<button id="tt-active-start-save">Save active start</button>
|
||||
</div>
|
||||
</div>`
|
||||
: ""}
|
||||
${this.editDraft ? this.renderEditPanel() : ""}
|
||||
<table>
|
||||
<thead>
|
||||
@ -250,6 +272,11 @@ export class TimetrackerUi {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.id === "tt-active-start-save") {
|
||||
this.saveActiveStartDraft();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.id === "tt-edit-save") {
|
||||
this.saveEditDraft();
|
||||
return;
|
||||
@ -274,7 +301,15 @@ export class TimetrackerUi {
|
||||
|
||||
document.addEventListener("input", (event) => {
|
||||
const target = event.target as HTMLInputElement | HTMLTextAreaElement | null;
|
||||
if (!target || !this.editDraft) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.id === "tt-active-start") {
|
||||
this.activeStartDraft = target.value;
|
||||
}
|
||||
|
||||
if (!this.editDraft) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,6 +326,20 @@ export class TimetrackerUi {
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("focusin", (event) => {
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.id === "tt-active-start") {
|
||||
this.isEditingActiveStart = true;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("focusout", (event) => {
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.id === "tt-active-start") {
|
||||
this.isEditingActiveStart = false;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
if (this.editDraft) {
|
||||
@ -377,6 +426,32 @@ export class TimetrackerUi {
|
||||
}
|
||||
}
|
||||
|
||||
private saveActiveStartDraft(): void {
|
||||
const active = this.service.getState().activeTimer;
|
||||
if (!active) {
|
||||
this.activeStartDraft = null;
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
const rawInput = this.activeStartDraft ?? toIsoLocalInput(active.startedAtEpochMs);
|
||||
const startedAtEpochMs = parseLocalInput(rawInput);
|
||||
|
||||
if (!Number.isFinite(startedAtEpochMs)) {
|
||||
logseq.App.showMsg("Invalid date format.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.service.updateActiveStart(startedAtEpochMs);
|
||||
this.activeStartDraft = null;
|
||||
this.render();
|
||||
logseq.App.showMsg("Active start updated.", "success");
|
||||
} catch (error) {
|
||||
logseq.App.showMsg((error as Error).message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
private escapeHtml(value: string): string {
|
||||
return value
|
||||
.replace(/&/g, "&")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user