3 Commits

Author SHA1 Message Date
olivier 3df01c6ede 1.2.0 2026-09-07 12:11:03 -04:00
olivier 537198c4f1 Add remaining type aliases, rewrite settings tab as syntax TL;DR
- Add age (birthday), remaining (countdown), elapsed (since) aliases,
  alongside the existing bday/until/difference.
- README: document new aliases in each type's header and the Type
  Aliases section.
- Settings tab rewritten: drop the stale GitHub doc link and hardcoded
  pre-redesign examples (countdown+from, auto-colon labels). Replace
  with a compact syntax TL;DR \u2014 all four types with their aliases,
  fields, and one-line descriptions, plus relative dates, frontmatter
  fallback, and inline/fenced examples \u2014 and link to the README on
  Gitea (was pointing at a stale GitHub URL).

Verified: aliases tested against the real shipped config parser; the
settings tab's actual display() (found via app.setting.pluginTabs) was
invoked live in Obsidian and rendered exactly the intended content with
no errors.
2026-09-07 12:09:55 -04:00
olivier 68e7b3ab04 Syntax redesign: sharpen countdown/diff, symmetric frontmatter, relative dates
- Sharpen countdown vs diff: countdown is now always relative to now and
  no longer accepts a 'from' field (previously identical math to diff
  with a custom from, just different message framing).
- Add symmetric frontmatter fallback to countdown (to/deadline), diff
  (from/start, to/end), and since (since/created) \u2014 previously only
  birthday read frontmatter.
- Add relative date support to parseMoment: today, now, tomorrow,
  yesterday, and +/-N offsets (d/w/mo/y/h/m), always relative to now.
  Fixes diff's main weakness of needing hardcoded, staling dates.
- Make label verbatim everywhere (was auto-appending ': ' for countdown
  only, inconsistent with birthday's verbatim convention).
- Fix silent inline failures: unresolvable type now shows an explicit
  error ('Missing or unrecognized type') instead of rendering nothing,
  matching fenced-block behavior. Also fixes 'from=X' alone (documented
  since-alias) not inferring a type.
- Remove the 'YAML-like' comma-separated inline format from docs \u2014 it
  isn't valid non-flow YAML and silently produced nothing; only
  key=value and {flow-mapping} are documented now.
- README rewritten to match: field references, frontmatter docs per
  type, and a new relative-dates section.

Verified against the real bundled logic (12 behavioral checks) and live
in Obsidian via CDP across both Live Preview and Reading View.
2026-09-07 12:04:35 -04:00
8 changed files with 194 additions and 135 deletions
+45 -77
View File
@@ -2,11 +2,6 @@
An Obsidian plugin that adds dynamic date calculations to your notes using `date-calc` fenced code blocks and inline code. An Obsidian plugin that adds dynamic date calculations to your notes using `date-calc` fenced code blocks and inline code.
## Todo
- [ ] Add custom language (default to Obsidian language, overridable)
## Features ## Features
### Fenced Code Blocks ### Fenced Code Blocks
@@ -18,7 +13,6 @@ type: birthday
birthday: 1992-08-16 birthday: 1992-08-16
``` ```
### Inline Code ### Inline Code
Use inline code for quick calculations: `date-calc: birthday=1992-08-16` Use inline code for quick calculations: `date-calc: birthday=1992-08-16`
@@ -27,16 +21,16 @@ Use inline code for quick calculations: `date-calc: birthday=1992-08-16`
## Supported Calculation Types ## Supported Calculation Types
### Birthday (`birthday`) ### Birthday (`birthday`, `bday`, `age`)
Calculates age and time until next birthday, with an optional custom label and automatic personalization from your note's frontmatter. Calculates age and time until next birthday.
**Fields:** **Fields:**
- `birthday` (or `birthdate`, `date`): Birth date in YYYY-MM-DD format - `birthday` (or `birthdate`, `date`): Birth date
- `label` (optional): Custom label (defaults to "Age:") - `label` (optional): Full prefix text, used verbatim — include your own punctuation (defaults to `Age:`)
**Frontmatter Support:** If not provided in the code block, the plugin reads `birthday`/`birthdate` from the note's frontmatter. If no `label` is set, a frontmatter `name` property becomes the default label automatically (e.g. `name: John` → "John's age:"). **Frontmatter Support:** If not provided in the code block, reads `birthday`/`birthdate` from the note's frontmatter. If no `label` is set, a frontmatter `name` property personalizes the default label automatically (e.g. `name: John` → `John's age:`).
**Examples:** **Examples:**
@@ -51,41 +45,35 @@ birthday: 2000-05-21
label: "John's age:" label: "John's age:"
``` ```
### Countdown (`countdown`, `until`, `remaining`)
### Countdown (`countdown` or `until`) Time remaining until a target date, **always measured from now**. For a comparison between two fixed dates, use `diff` instead.
Shows time remaining until a target date.
**Fields:** **Fields:**
- `to` (or `date`, `until`): Target date/time - `to` (or `date`, `until`): Target date/time
- `from` (optional): Starting date/time (defaults to now) - `label` (optional): Full prefix text, used verbatim (e.g. `label: "New Year:"`)
- `label` (optional): Prefix label for the output
**Examples:** **Frontmatter Support:** If `to` isn't provided in the code block, reads `to`/`deadline` from the note's frontmatter.
**Example:**
```date-calc ```date-calc
type: countdown type: countdown
label: New Year label: "New Year:"
to: 2025-12-31 23:59 to: 2025-12-31 23:59
``` ```
```date-calc ### Since (`since`, `elapsed`)
type: countdown
label: Sprint ends
to: 2025-10-15 17:00
from: 2025-10-01 09:00
```
Time elapsed since an event (or time until, if the event is in the future) — always measured against now.
### Since (`since`)
Shows time elapsed since an event (or time until if the event is in the future).
**Fields:** **Fields:**
- `since` (or `from`, `date`): Event date/time - `since` (or `from`, `date`): Event date/time
**Frontmatter Support:** If not provided in the code block, reads `since`/`created` from the note's frontmatter.
**Example:** **Example:**
```date-calc ```date-calc
@@ -93,16 +81,17 @@ type: since
since: 2024-12-20 since: 2024-12-20
``` ```
### Difference (`diff`, `difference`)
### Difference (`diff`) The time difference between two fixed dates — neither has to be "now". For a countdown relative to the present moment, use `countdown` instead.
Calculates the time difference between two specific dates.
**Fields:** **Fields:**
- `from` (or `start`): Start date/time - `from` (or `start`): Start date/time
- `to` (or `end`): End date/time - `to` (or `end`): End date/time
**Frontmatter Support:** If not provided in the code block, reads `from`/`start` and `to`/`end` from the note's frontmatter.
**Examples:** **Examples:**
```date-calc ```date-calc
@@ -117,25 +106,32 @@ from: 2025-09-19 08:00
to: 2025-09-19 16:30 to: 2025-09-19 16:30
``` ```
## Inline Usage ## Inline Usage
You can use inline code for quick calculations: You can use inline code for quick calculations:
- `date-calc: birthday=1992-08-16` → Birthday summary - `date-calc: birthday=1992-08-16` → Birthday summary
- `date-calc: to=2025-12-31 label="New Year"` → Countdown - `date-calc: to=2025-12-31 label="New Year:"` → Countdown
- `date-calc: since=2024-12-20` → Time since event - `date-calc: since=2024-12-20` → Time since event
- `date-calc: from=2025-09-19 to=2025-09-20` → Date difference - `date-calc: from=2025-09-19 to=2025-09-20` → Date difference
**YAML Format:** Inline code also accepts YAML/inline-map format: **Formats:** Inline code accepts key=value pairs (`birthday=1992-08-16`) or a flow-mapping YAML object (`{type: birthday, birthday: 1992-08-16}`).
`date-calc: {type: birthday, birthday: 1992-08-16}`
**Frontmatter Integration:** For inline birthday calculations, if no date is provided, the plugin will use the note's frontmatter `birthday`/`birthdate` property. **Frontmatter Integration:** Applies to every type, not just birthday — see each type's "Frontmatter Support" above.
## Date Formats ## Date Formats
- **Timezone:** All calculations use your local timezone | Format | Example | Notes |
- **Birthday Calculations:** Normalized to local midnight to avoid timezone inconsistencies | :------------------ | :------------------------------ | :----------------------------------------- |
| Date only | `2026-12-31` | — |
| Date + time | `2026-12-31 23:59` | — |
| ISO 8601 | `2026-12-31T23:59:00` | — |
| Relative keyword | `today`, `now`, `tomorrow`, `yesterday` | Resolved at render time |
| Relative offset | `+7d`, `-3mo`, `+2w`, `-1y` | Units: `d`, `w`, `mo`, `y`, `h`, `m` (minutes) — always relative to now |
All dates use your local timezone. Birthday calculations normalize to midnight to avoid timezone edge cases; `today`/relative keywords resolve to your local time at render.
Relative dates are most useful with `diff`, since `countdown`/`since` are already anchored to now by default — e.g. `type: diff` with `from: today` and `to: +30d` gives a fixed 30-day window that doesn't need updating.
## Configuration Options ## Configuration Options
@@ -158,70 +154,44 @@ verbose: true
- `verbose: true` → "Countdown: 1 year, 2 months, 15 days" - `verbose: true` → "Countdown: 1 year, 2 months, 15 days"
- `verbose: false` → "1y 2mo 15d" - `verbose: false` → "1y 2mo 15d"
### Hide While Editing ### Hide While Editing
Settings → "Hide result while cursor inside" prevents rendered output from showing while you're editing the code, keeping the raw syntax visible. Settings → "Hide result while cursor inside" prevents rendered output from showing while you're editing the code, keeping the raw syntax visible.
## Date Formats
| Format | Example | Use Case |
| :---------- | :-------------------- | :-------------------- |
| Date only | `2026-12-31` | Birthdays, countdowns |
| Date + time | `2026-12-31 23:59` | Precise countdowns |
| ISO 8601 | `2026-12-31T23:59:00` | Also supported |
All dates use your local timezone. Birthday calculations normalize to midnight to avoid timezone edge cases.
## Field Reference ## Field Reference
### Birthday ### Birthday
- `birthday` / `birthdate` / `date` — Birth date - `birthday` / `birthdate` / `date` — Birth date (falls back to frontmatter `birthday`/`birthdate`)
- `verbose` — Override output format (optional) - `label` — Full prefix, verbatim (defaults to `Age:`, or `<frontmatter name>'s age:` if set)
- `verbose` — Override output format
### Countdown ### Countdown
- `to` / `until` / `date` — Target date/time - `to` / `until` / `date` — Target date/time (falls back to frontmatter `to`/`deadline`)
- `from` — Start date (defaults to now) - `label` — Full prefix, verbatim
- `label` — Custom prefix
- `verbose` — Override output format - `verbose` — Override output format
### Since ### Since
- `since` / `from` / `date` — Event date/time - `since` / `from` / `date` — Event date/time (falls back to frontmatter `since`/`created`)
- `verbose` — Override output format - `verbose` — Override output format
### Diff ### Diff
- `from` / `start` — Start date/time - `from` / `start` — Start date/time (falls back to frontmatter `from`/`start`)
- `to` / `end` — End date/time - `to` / `end` — End date/time (falls back to frontmatter `to`/`end`)
- `verbose` — Override output format - `verbose` — Override output format
## Type Aliases ## Type Aliases
For convenience, use these shortcuts: For convenience, use these shortcuts:
- `birthday` = `bday` - `birthday` = `bday` = `age`
- `countdown` = `until` - `countdown` = `until` = `remaining`
- `since` = `elapsed`
- `diff` = `difference` - `diff` = `difference`
## Inline Syntax Formats
All three formats work:
**Key=value:** ```date-calc: birthday=1992-08-16```
**YAML-like:** ```date-calc: type: birthday, birthday: 1992-08-16```
**Compact:** ```date-calc: {type: birthday, birthday: 1992-08-16}```
## Custom Styling ## Custom Styling
Target these CSS classes in your snippets: Target these CSS classes in your snippets:
@@ -241,9 +211,7 @@ Target these CSS classes in your snippets:
} }
``` ```
## Commands ## Commands
- **Toggle debug** — Log decoration activity to console - **Toggle debug** — Log decoration activity to console
- **Toggle verbose** — Switch global verbose mode - **Toggle verbose** — Switch global verbose mode
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "date-calc", "id": "date-calc",
"name": "Date calculator", "name": "Date calculator",
"version": "1.1.0", "version": "1.2.0",
"minAppVersion": "0.15.0", "minAppVersion": "0.15.0",
"description": "Calculate ages, countdowns, and date differences dynamically in your notes using inline code or fenced blocks.", "description": "Calculate ages, countdowns, and date differences dynamically in your notes using inline code or fenced blocks.",
"author": "Olivier Legendre", "author": "Olivier Legendre",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "date-calculator", "name": "date-calculator",
"version": "1.1.0", "version": "1.2.0",
"description": "Calculate ages, countdowns, and date differences dynamically in your notes using inline code or fenced blocks.", "description": "Calculate ages, countdowns, and date differences dynamically in your notes using inline code or fenced blocks.",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
+52 -13
View File
@@ -27,11 +27,11 @@ export function calculateDateResult(
case "birthday": case "birthday":
return calculateBirthday(cfg, app, sourcePath, useVerbose); return calculateBirthday(cfg, app, sourcePath, useVerbose);
case "countdown": case "countdown":
return calculateCountdown(cfg, useVerbose); return calculateCountdown(cfg, app, sourcePath, useVerbose);
case "diff": case "diff":
return calculateDiff(cfg, useVerbose); return calculateDiff(cfg, app, sourcePath, useVerbose);
case "since": case "since":
return calculateSince(cfg, useVerbose); return calculateSince(cfg, app, sourcePath, useVerbose);
default: default:
return { text: "date-calc: Unknown type. Supported: birthday, countdown, diff, since" }; return { text: "date-calc: Unknown type. Supported: birthday, countdown, diff, since" };
} }
@@ -76,17 +76,29 @@ function calculateBirthday(
const ageStr = verbose ? `${age} years old` : `${age}y`; const ageStr = verbose ? `${age} years old` : `${age}y`;
// Custom label > frontmatter-name personalization > plain "Age:" default. // Custom label > frontmatter-name personalization > plain "Age:" default.
// Labels are always used verbatim, including their own trailing punctuation.
const name = frontmatterField(fm, "name"); const name = frontmatterField(fm, "name");
const label = cfg.label ?? (typeof name === "string" ? `${name}'s age:` : "Age:"); const label = cfg.label ?? (typeof name === "string" ? `${name}'s age:` : "Age:");
return { text: `${label} ${ageStr}. ${msg}`, tooltip: bd.format("MMMM Do, YYYY") }; return { text: `${label} ${ageStr}. ${msg}`, tooltip: bd.format("MMMM Do, YYYY") };
} }
function calculateCountdown(cfg: DateCalcConfig, verbose: boolean): DateCalcResult { /** Always relative to now — for a fixed two-point comparison, use `diff`. */
const to = parseMoment(cfg.to ?? cfg.date ?? cfg.until); function calculateCountdown(
cfg: DateCalcConfig,
app: App,
sourcePath: string,
verbose: boolean
): DateCalcResult {
const fm = app.metadataCache.getCache(sourcePath)?.frontmatter;
const to = parseMoment(
cfg.to ?? cfg.date ?? cfg.until ??
frontmatterField(fm, "to") ?? frontmatterField(fm, "deadline")
);
if (!to) return { text: `date-calc: Missing or invalid "to" date.` }; if (!to) return { text: `date-calc: Missing or invalid "to" date.` };
const from = parseMoment(cfg.from) ?? moment(); const from = moment();
const label = cfg.label ? `${cfg.label}: ` : ""; const label = cfg.label ? `${cfg.label} ` : "";
const span = formatSpan(from, to, verbose); const span = formatSpan(from, to, verbose);
const text = !span.isNegative const text = !span.isNegative
@@ -96,9 +108,21 @@ function calculateCountdown(cfg: DateCalcConfig, verbose: boolean): DateCalcResu
return { text }; return { text };
} }
function calculateDiff(cfg: DateCalcConfig, verbose: boolean): DateCalcResult { /** A neutral two-point comparison — for "time until X from now", use `countdown`. */
const from = parseMoment(cfg.from ?? cfg.start); function calculateDiff(
const to = parseMoment(cfg.to ?? cfg.end); cfg: DateCalcConfig,
app: App,
sourcePath: string,
verbose: boolean
): DateCalcResult {
const fm = app.metadataCache.getCache(sourcePath)?.frontmatter;
const from = parseMoment(
cfg.from ?? cfg.start ?? frontmatterField(fm, "from") ?? frontmatterField(fm, "start")
);
const to = parseMoment(
cfg.to ?? cfg.end ?? frontmatterField(fm, "to") ?? frontmatterField(fm, "end")
);
if (!from || !to) return { text: `date-calc: Provide valid "from" and "to" dates.` }; if (!from || !to) return { text: `date-calc: Provide valid "from" and "to" dates.` };
const span = formatSpan(from, to, verbose); const span = formatSpan(from, to, verbose);
@@ -110,8 +134,18 @@ function calculateDiff(cfg: DateCalcConfig, verbose: boolean): DateCalcResult {
return { text }; return { text };
} }
function calculateSince(cfg: DateCalcConfig, verbose: boolean): DateCalcResult { function calculateSince(
const since = parseMoment(cfg.since ?? cfg.from ?? cfg.date); cfg: DateCalcConfig,
app: App,
sourcePath: string,
verbose: boolean
): DateCalcResult {
const fm = app.metadataCache.getCache(sourcePath)?.frontmatter;
const since = parseMoment(
cfg.since ?? cfg.from ?? cfg.date ??
frontmatterField(fm, "since") ?? frontmatterField(fm, "created")
);
if (!since) return { text: `date-calc: Missing or invalid "since" date.` }; if (!since) return { text: `date-calc: Missing or invalid "since" date.` };
const now = moment(); const now = moment();
@@ -137,7 +171,12 @@ export function processInlineCode(
const cfg = parseConfig(paramsRaw); const cfg = parseConfig(paramsRaw);
const norm = normalizeConfig(paramsRaw, cfg); const norm = normalizeConfig(paramsRaw, cfg);
if (!norm.type) return { text: "" }; if (!norm.type) {
// Surface a visible error instead of silently rendering nothing — the
// author clearly meant to invoke date-calc (the prefix matched), so a
// vanished result is far more confusing than an explicit message.
return { text: 'date-calc: Missing or unrecognized "type" (birthday/countdown/diff/since).' };
}
return calculateDateResult(norm.type, norm.cfg, app, sourcePath, settings.verbose); return calculateDateResult(norm.type, norm.cfg, app, sourcePath, settings.verbose);
} }
+4 -3
View File
@@ -84,12 +84,13 @@ export function normalizeConfig(
if (resolved.birthday || resolved.birthdate) type = "birthday"; if (resolved.birthday || resolved.birthdate) type = "birthday";
else if ((resolved.from && resolved.to) || (resolved.start && resolved.end)) type = "diff"; else if ((resolved.from && resolved.to) || (resolved.start && resolved.end)) type = "diff";
else if (resolved.to || resolved.until) type = "countdown"; else if (resolved.to || resolved.until) type = "countdown";
else if (resolved.since) type = "since"; else if (resolved.since || resolved.from) type = "since";
} }
if (type === "bday") type = "birthday"; if (type === "bday" || type === "age") type = "birthday";
if (type === "until") type = "countdown"; if (type === "until" || type === "remaining") type = "countdown";
if (type === "difference") type = "diff"; if (type === "difference") type = "diff";
if (type === "elapsed") type = "since";
return { type, cfg: resolved }; return { type, cfg: resolved };
} }
+29 -2
View File
@@ -1,9 +1,22 @@
import { moment } from "obsidian"; import { moment } from "obsidian";
import type { M } from "./types"; import type { M } from "./types";
/** Relative-offset shorthand: +7d, -3mo, +2w, etc. (always relative to now). */
const RELATIVE_RE = /^([+-]\d+)\s*(d|days?|w|weeks?|mo|months?|y|years?|h|hours?|m|min|minutes?)$/i;
const RELATIVE_UNIT: Record<string, moment.unitOfTime.DurationConstructor> = {
d: "days", day: "days", days: "days",
w: "weeks", week: "weeks", weeks: "weeks",
mo: "months", month: "months", months: "months",
y: "years", year: "years", years: "years",
h: "hours", hour: "hours", hours: "hours",
m: "minutes", min: "minutes", minute: "minutes", minutes: "minutes",
};
/** /**
* Parse a date-ish input (frontmatter Date object, "YYYY-MM-DD" string, or any * Parse a date-ish input (frontmatter Date object, "YYYY-MM-DD" string, a
* moment-parseable string) into a moment. Returns null if unparseable. * relative keyword/offset, or any moment-parseable string) into a moment.
* Returns null if unparseable.
*/ */
export function parseMoment(input: unknown): M | null { export function parseMoment(input: unknown): M | null {
if (input == null || input === "") return null; if (input == null || input === "") return null;
@@ -29,6 +42,20 @@ export function parseMoment(input: unknown): M | null {
} }
const s = String(input).trim(); const s = String(input).trim();
const lower = s.toLowerCase();
if (lower === "now") return moment();
if (lower === "today") return moment().startOf("day");
if (lower === "tomorrow") return moment().add(1, "day").startOf("day");
if (lower === "yesterday") return moment().subtract(1, "day").startOf("day");
const rel = RELATIVE_RE.exec(s);
if (rel) {
const amount = parseInt(rel[1], 10);
const unit = RELATIVE_UNIT[rel[2].toLowerCase()];
return moment().add(amount, unit);
}
const dateOnly = moment(s, "YYYY-MM-DD", true); const dateOnly = moment(s, "YYYY-MM-DD", true);
if (dateOnly.isValid()) return dateOnly.startOf("day"); if (dateOnly.isValid()) return dateOnly.startOf("day");
+60 -37
View File
@@ -1,6 +1,8 @@
import { App, PluginSettingTab, Setting } from "obsidian"; import { App, PluginSettingTab, Setting } from "obsidian";
import type DateCalcPlugin from "../main"; import type DateCalcPlugin from "../main";
const README_URL = "https://gitea.mithrilforge.dev/olivier/date-calculator";
export class DateCalcSettingTab extends PluginSettingTab { export class DateCalcSettingTab extends PluginSettingTab {
constructor(app: App, private plugin: DateCalcPlugin) { constructor(app: App, private plugin: DateCalcPlugin) {
super(app, plugin); super(app, plugin);
@@ -12,14 +14,10 @@ export class DateCalcSettingTab extends PluginSettingTab {
containerEl.createEl("h2", { text: "Date Calc" }); containerEl.createEl("h2", { text: "Date Calc" });
// Documentation link
const docsDiv = containerEl.createDiv({ const docsDiv = containerEl.createDiv({
cls: "setting-item-description date-calc-settings-docs", cls: "setting-item-description date-calc-settings-docs",
}); });
docsDiv.createEl("a", { docsDiv.createEl("a", { text: "📖 Full syntax reference (README)", href: README_URL });
text: "📖 View Full Documentation",
href: "https://github.com/thelegend09/date-calculator",
});
new Setting(containerEl) new Setting(containerEl)
.setName("Debug logging") .setName("Debug logging")
@@ -53,43 +51,68 @@ export class DateCalcSettingTab extends PluginSettingTab {
}) })
); );
// Usage examples section containerEl.createEl("h3", { text: "Syntax at a glance" });
containerEl.createEl("h3", { text: "Usage Examples" }); const tldr = containerEl.createDiv({ cls: "date-calc-examples" });
const examplesDiv = containerEl.createDiv({ cls: "date-calc-examples" }); tldr.createEl("p", {
text: "Use `date-calc: ...` inline, or a fenced ```date-calc block with type: set explicitly (or inferred from which fields you give).",
});
// Inline examples // Types table
examplesDiv.createEl("h4", { text: "Inline Code (single backticks)" }); const typesList = tldr.createEl("ul");
const inlineList = examplesDiv.createEl("ul"); const addType = (name: string, aliases: string, desc: string, fields: string) => {
inlineList.createEl("li").setText("`date-calc: birthday=2003-02-15`"); const li = typesList.createEl("li");
inlineList.createEl("li").setText("`date-calc: countdown to=2026-12-31 label=\"New Year\"`"); li.createEl("strong", { text: name });
inlineList.createEl("li").setText("`date-calc: since=2024-01-01`"); li.appendText(` (${aliases}) — ${desc} `);
inlineList.createEl("li").setText("`date-calc: diff from=2024-01-01 to=2024-12-31`"); li.createEl("br");
inlineList.createEl("li").setText("`date-calc: birthday=1992-08-16 verbose=true`"); li.createEl("code", { text: fields });
};
addType(
"birthday", "bday, age",
"age + days until next birthday.",
"birthday/birthdate/date, label"
);
addType(
"countdown", "until, remaining",
"time until a date, always from now.",
"to/until/date, label"
);
addType(
"since", "elapsed",
"time since a date, always from now.",
"since/from/date"
);
addType(
"diff", "difference",
"time between two fixed dates (neither has to be now).",
"from/start, to/end"
);
// Block examples tldr.createEl("h4", { text: "Relative dates" });
examplesDiv.createEl("h4", { text: "Fenced Blocks (triple backticks)" }); tldr.createEl("p", {
text: "today, now, tomorrow, yesterday, or an offset like +7d / -3mo / +2w (always relative to now).",
});
examplesDiv tldr.createEl("h4", { text: "Frontmatter fallback" });
tldr.createEl("p", {
text: "Every type reads its date(s) from frontmatter if not given inline: birthday/birthdate, to/deadline, since/created, from/start + to/end.",
});
tldr.createEl("h4", { text: "Examples" });
const examplesList = tldr.createEl("ul");
examplesList.createEl("li").createEl("code", { text: "date-calc: birthday=1992-08-16" });
examplesList.createEl("li").createEl("code", { text: "date-calc: to=2026-12-31 label=\"New Year:\"" });
examplesList.createEl("li").createEl("code", { text: "date-calc: since=2024-01-01" });
examplesList.createEl("li").createEl("code", { text: "date-calc: from=2024-01-01 to=today" });
examplesList
.createEl("li")
.createEl("pre", { cls: "date-calc-example-block" }) .createEl("pre", { cls: "date-calc-example-block" })
.setText("```date-calc\ntype: birthday\nbirthday: 1992-08-16\n```"); .setText("```date-calc\ntype: countdown\nto: +30d\nlabel: \"Sprint:\"\nverbose: true\n```");
examplesDiv const fullDocs = tldr.createEl("p");
.createEl("pre", { cls: "date-calc-example-block" }) fullDocs.appendText("Full field reference, custom styling, and more examples: ");
.setText( fullDocs.createEl("a", { text: "README on Gitea", href: README_URL });
"```date-calc\ntype: countdown\nto: 2026-12-31 23:59\nlabel: New Year\nverbose: true\n```" fullDocs.appendText(".");
);
examplesDiv
.createEl("pre", { cls: "date-calc-example-block" })
.setText("```date-calc\ntype: diff\nfrom: 2024-01-01\nto: 2024-12-31\n```");
// Tips section
examplesDiv.createEl("h4", { text: "Tips" });
const tipsList = examplesDiv.createEl("ul");
tipsList.createEl("li").setText("Use YYYY-MM-DD format for dates");
tipsList.createEl("li").setText("Add time with YYYY-MM-DD HH:mm for precise countdowns");
tipsList.createEl("li").setText("Supported types: birthday, countdown, since, diff");
tipsList.createEl("li").setText("Add verbose=true/false to override global setting");
} }
} }
+2 -1
View File
@@ -1,4 +1,5 @@
{ {
"1.0.0": "0.15.0", "1.0.0": "0.15.0",
"1.1.0": "0.15.0" "1.1.0": "0.15.0",
"1.2.0": "0.15.0"
} }