19 KiB
19 KiB
cssclasses
| cssclasses | ||||||
|---|---|---|---|---|---|---|
|
Dailys
Week
// Force English locale for weekdays
moment.locale("en");
const today = moment();
// === CONFIGURE WEEK RANGE HERE ===
// For current week:
const weekStart = today.clone().startOf("isoWeek");
const weekEnd = today.clone().endOf("isoWeek");
// For next week, uncomment these:
// const weekStart = today.clone().add(1, "week").startOf("isoWeek");
// const weekEnd = today.clone().add(1, "week").endOf("isoWeek");
// For weekend only (Sat & Sun):
// const weekStart = today.clone().startOf("isoWeek").add(5, "days"); // Saturday
// const weekEnd = today.clone().startOf("isoWeek").add(6, "days"); // Sunday
// All notes tagged #Calendar within the week
const pages = dv.pages("#Calendar")
.where(p => {
const d = moment(p.file.name, "DD.MM.YYYY", true);
return d.isValid() && d.isBetween(weekStart, weekEnd, "day", "[]");
});
// Generate days array (Mon–Sun or custom)
const totalDays = weekEnd.diff(weekStart, "days") + 1;
const weekDays = Array.from({ length: totalDays }, (_, i) => weekStart.clone().add(i, "days"));
// Separate days with and without notes
const daysWithNotes = [];
const daysWithoutNotes = [];
for (const day of weekDays) {
const page = pages.find(p => p.file.name === day.format("DD.MM.YYYY"));
if (page) {
daysWithNotes.push({ date: day, page });
} else {
daysWithoutNotes.push(day);
}
}
// Build Columns plugin Markdown
let md = "````col\nheight=shortest\ntextAlign=start\n===\n";
// Columns for days with notes
for (const { date, page } of daysWithNotes) {
const isToday = date.isSame(today, "day");
const label = `${isToday ? "📌 " : ""}${date.format("ddd")}<br>${date.format("DD.MM.YYYY")}`;
md += "```col-md\n";
md += `### ${label}\n`;
// Show reason from frontmatter under the title
if (page.reason) {
md += `**Reason:** ${page.reason}\n\n`;
}
// Get tasks from the note
const tasks = page.file.tasks;
// Filter tasks under # Tasks heading if possible
const tasksInSection = tasks.filter(t => {
if (t.heading) return t.heading.toLowerCase().includes("tasks");
return true; // fallback: include all tasks if heading not available
});
if (tasksInSection.length > 0) {
for (const t of tasksInSection) {
md += `- [${t.completed ? "x" : " "}] ${t.text}\n`;
}
} else {
md += "_No tasks found_\n";
}
md += "```\n\n";
}
// Single column for days without notes
if (daysWithoutNotes.length > 0) {
md += "```col-md\n";
md += "### Days without notes\n";
for (const day of daysWithoutNotes) {
md += `- ${day.format("ddd")} — ${day.format("DD.MM.YYYY")}\n`;
}
md += "```\n\n";
}
md += "````\n";
// Render the dashboard
dv.paragraph(md);
Weekend
// Force English locale for weekdays
moment.locale("en");
const today = moment();
// === CONFIGURE WEEK RANGE HERE ===
// For current week:
//const weekStart = today.clone().startOf("isoWeek");
//const weekEnd = today.clone().endOf("isoWeek");
// For next week, uncomment these:
// const weekStart = today.clone().add(1, "week").startOf("isoWeek");
// const weekEnd = today.clone().add(1, "week").endOf("isoWeek");
// For weekend only (Sat & Sun):
const weekStart = today.clone().startOf("isoWeek").add(5, "days"); // Saturday
const weekEnd = today.clone().startOf("isoWeek").add(6, "days"); // Sunday
// All notes tagged #Calendar within the week
const pages = dv.pages("#Calendar")
.where(p => {
const d = moment(p.file.name, "DD.MM.YYYY", true);
return d.isValid() && d.isBetween(weekStart, weekEnd, "day", "[]");
});
// Generate days array (Mon–Sun or custom)
const totalDays = weekEnd.diff(weekStart, "days") + 1;
const weekDays = Array.from({ length: totalDays }, (_, i) => weekStart.clone().add(i, "days"));
// Separate days with and without notes
const daysWithNotes = [];
const daysWithoutNotes = [];
for (const day of weekDays) {
const page = pages.find(p => p.file.name === day.format("DD.MM.YYYY"));
if (page) {
daysWithNotes.push({ date: day, page });
} else {
daysWithoutNotes.push(day);
}
}
// Build Columns plugin Markdown
let md = "````col\nheight=shortest\ntextAlign=start\n===\n";
// Columns for days with notes
for (const { date, page } of daysWithNotes) {
const isToday = date.isSame(today, "day");
const label = `${isToday ? "📌 " : ""}${date.format("ddd")}<br>${date.format("DD.MM.YYYY")}`;
md += "```col-md\n";
md += `### ${label}\n`;
// Show reason from frontmatter under the title
if (page.reason) {
md += `**Reason:** ${page.reason}\n\n`;
}
// Get tasks from the note
const tasks = page.file.tasks;
// Filter tasks under # Tasks heading if possible
const tasksInSection = tasks.filter(t => {
if (t.heading) return t.heading.toLowerCase().includes("tasks");
return true; // fallback: include all tasks if heading not available
});
if (tasksInSection.length > 0) {
for (const t of tasksInSection) {
md += `- [${t.completed ? "x" : " "}] ${t.text}\n`;
}
} else {
md += "_No tasks found_\n";
}
md += "```\n\n";
}
// Single column for days without notes
if (daysWithoutNotes.length > 0) {
md += "```col-md\n";
md += "### Days without notes\n";
for (const day of daysWithoutNotes) {
md += `- ${day.format("ddd")} — ${day.format("DD.MM.YYYY")}\n`;
}
md += "```\n\n";
}
md += "````\n";
// Render the dashboard
dv.paragraph(md);
Next Week
// Force English locale for weekdays
moment.locale("en");
const today = moment();
// === CONFIGURE WEEK RANGE HERE ===
// For current week:
//const weekStart = today.clone().startOf("isoWeek");
//const weekEnd = today.clone().endOf("isoWeek");
// For next week, uncomment these:
const weekStart = today.clone().add(1, "week").startOf("isoWeek");
const weekEnd = today.clone().add(1, "week").endOf("isoWeek");
// For weekend only (Sat & Sun):
// const weekStart = today.clone().startOf("isoWeek").add(5, "days"); // Saturday
// const weekEnd = today.clone().startOf("isoWeek").add(6, "days"); // Sunday
// All notes tagged #Calendar within the week
const pages = dv.pages("#Calendar")
.where(p => {
const d = moment(p.file.name, "DD.MM.YYYY", true);
return d.isValid() && d.isBetween(weekStart, weekEnd, "day", "[]");
});
// Generate days array (Mon–Sun or custom)
const totalDays = weekEnd.diff(weekStart, "days") + 1;
const weekDays = Array.from({ length: totalDays }, (_, i) => weekStart.clone().add(i, "days"));
// Separate days with and without notes
const daysWithNotes = [];
const daysWithoutNotes = [];
for (const day of weekDays) {
const page = pages.find(p => p.file.name === day.format("DD.MM.YYYY"));
if (page) {
daysWithNotes.push({ date: day, page });
} else {
daysWithoutNotes.push(day);
}
}
// Build Columns plugin Markdown
let md = "````col\nheight=shortest\ntextAlign=start\n===\n";
// Columns for days with notes
for (const { date, page } of daysWithNotes) {
const isToday = date.isSame(today, "day");
const label = `${isToday ? "📌 " : ""}${date.format("ddd")}<br>${date.format("DD.MM.YYYY")}`;
md += "```col-md\n";
md += `### ${label}\n`;
// Show reason from frontmatter under the title
if (page.reason) {
md += `**Reason:** ${page.reason}\n\n`;
}
// Get tasks from the note
const tasks = page.file.tasks;
// Filter tasks under # Tasks heading if possible
const tasksInSection = tasks.filter(t => {
if (t.heading) return t.heading.toLowerCase().includes("tasks");
return true; // fallback: include all tasks if heading not available
});
if (tasksInSection.length > 0) {
for (const t of tasksInSection) {
md += `- [${t.completed ? "x" : " "}] ${t.text}\n`;
}
} else {
md += "_No tasks found_\n";
}
md += "```\n\n";
}
// Single column for days without notes
if (daysWithoutNotes.length > 0) {
md += "```col-md\n";
md += "### Days without notes\n";
for (const day of daysWithoutNotes) {
md += `- ${day.format("ddd")} — ${day.format("DD.MM.YYYY")}\n`;
}
md += "```\n\n";
}
md += "````\n";
// Render the dashboard
dv.paragraph(md);
Stats
// === Config ===
const splitOnSlash = false; // true -> merge hierarchical tags (#project/obsidian -> project)
const topN = 50; // show top N tags (null for all)
// === Catppuccin Mocha Palette ===
const catppuccin = {
rosewater: '#f5e0dc',
flamingo: '#f2cdcd',
pink: '#f5c2e7',
mauve: '#cba6f7',
red: '#f38ba8',
maroon: '#eba0ac',
peach: '#fab387',
yellow: '#f9e2af',
green: '#a6e3a1',
teal: '#94e2d5',
sky: '#89dceb',
sapphire: '#74c7ec',
blue: '#89b4fa',
lavender: '#b4befe',
text: '#cdd6f4',
subtext1: '#bac2de',
base: '#1e1e2e'
};
const catppuccinColors = [
catppuccin.rosewater,
catppuccin.flamingo,
catppuccin.pink,
catppuccin.mauve,
catppuccin.red,
catppuccin.maroon,
catppuccin.peach,
catppuccin.yellow,
catppuccin.green,
catppuccin.teal,
catppuccin.sky,
catppuccin.sapphire,
catppuccin.blue,
catppuccin.lavender
];
// === Helpers ===
function flattenTags(input, out = []) {
if (!input) return out;
if (Array.isArray(input)) {
for (const v of input) flattenTags(v, out);
} else if (typeof input === 'string') {
out.push(input);
} else if (typeof input === 'object') {
if (typeof input.tag === 'string') out.push(input.tag);
else if (typeof input.path === 'string') out.push(input.path);
else {
const s = String(input);
if (s && s !== '[object Object]') out.push(s);
}
} else {
out.push(String(input));
}
return out;
}
// Convert a string to Title Case (preserving slashes/hyphens)
function toTitleCase(str) {
return str.replace(/[\w]+/g, w =>
w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
);
}
// === Collect tags from all pages ===
const pages = dv.pages();
let allTags = [];
for (const p of pages) {
if (p.file?.tags) flattenTags(p.file.tags, allTags);
if (p.tags) flattenTags(p.tags, allTags);
if (p.tags_list) flattenTags(p.tags_list, allTags);
}
// === Normalize and count ===
const counts = {};
for (let tag of allTags) {
if (!tag) continue;
tag = String(tag).replace(/^#/, '').trim().toLowerCase();
if (!tag) continue;
if (splitOnSlash && tag.includes('/')) tag = tag.split('/')[0];
counts[tag] = (counts[tag] || 0) + 1;
}
// === Handle no tags ===
const tagEntries = Object.entries(counts);
if (tagEntries.length === 0) {
dv.el("p", "⚠️ No tags found in your vault.");
} else {
// === Sort + limit ===
tagEntries.sort((a, b) => b[1] - a[1]);
const limited = (topN && tagEntries.length > topN)
? tagEntries.slice(0, topN)
: tagEntries;
// Convert to title case for display
const labels = limited.map(e => toTitleCase(e[0].replace(/[-_]/g, ' ')));
const dataValues = limited.map(e => e[1]);
// === Color setup ===
const bgColors = [];
const borderColors = [];
for (let i = 0; i < labels.length; i++) {
const color = catppuccinColors[i % catppuccinColors.length];
bgColors.push(color + "55");
borderColors.push(color);
}
// === Chart.js config ===
const chartData = {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Tag Usage',
data: dataValues,
backgroundColor: bgColors,
borderColor: borderColors,
borderWidth: 1
}]
},
options: {
plugins: {
legend: { display: false },
title: {
display: true,
text: `Tag Usage (Top ${labels.length})`,
color: catppuccin.text,
font: { size: 16 }
}
},
scales: {
x: {
ticks: { color: catppuccin.subtext1, autoSkip: false, maxRotation: 60, minRotation: 30 },
title: { display: true, text: 'Tags', color: catppuccin.text },
grid: { color: catppuccin.base }
},
y: {
ticks: { color: catppuccin.subtext1 },
title: { display: true, text: 'Count', color: catppuccin.text },
beginAtZero: true,
grid: { color: catppuccin.base }
}
},
maintainAspectRatio: false
}
};
// === Render ===
const wrapper = this.container.createEl('div');
wrapper.style.minHeight = '320px';
wrapper.style.maxHeight = '60vh';
wrapper.style.overflow = 'auto';
wrapper.style.borderRadius = '8px';
wrapper.style.padding = '8px';
window.renderChart(chartData, wrapper);
}
// === Config ===
const splitOnSlash = false; // true -> merge hierarchical tags (#project/obsidian -> project)
const topN = 20; // show top N tags (null for all)
// === Catppuccin Mocha Palette ===
const catppuccin = {
rosewater: '#f5e0dc',
flamingo: '#f2cdcd',
pink: '#f5c2e7',
mauve: '#cba6f7',
red: '#f38ba8',
maroon: '#eba0ac',
peach: '#fab387',
yellow: '#f9e2af',
green: '#a6e3a1',
teal: '#94e2d5',
sky: '#89dceb',
sapphire: '#74c7ec',
blue: '#89b4fa',
lavender: '#b4befe',
text: '#cdd6f4',
subtext1: '#bac2de',
base: '#1e1e2e'
};
const catppuccinColors = [
catppuccin.rosewater,
catppuccin.flamingo,
catppuccin.pink,
catppuccin.mauve,
catppuccin.red,
catppuccin.maroon,
catppuccin.peach,
catppuccin.yellow,
catppuccin.green,
catppuccin.teal,
catppuccin.sky,
catppuccin.sapphire,
catppuccin.blue,
catppuccin.lavender
];
// === Helpers ===
function flattenTags(input, out = []) {
if (!input) return out;
if (Array.isArray(input)) {
for (const v of input) flattenTags(v, out);
} else if (typeof input === 'string') {
out.push(input);
} else if (typeof input === 'object') {
if (typeof input.tag === 'string') out.push(input.tag);
else if (typeof input.path === 'string') out.push(input.path);
else {
const s = String(input);
if (s && s !== '[object Object]') out.push(s);
}
} else {
out.push(String(input));
}
return out;
}
function toTitleCase(str) {
return str.replace(/[\w]+/g, w =>
w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
);
}
// === Collect tags ===
const pages = dv.pages();
let allTags = [];
for (const p of pages) {
if (p.file?.tags) flattenTags(p.file.tags, allTags);
if (p.tags) flattenTags(p.tags, allTags);
if (p.tags_list) flattenTags(p.tags_list, allTags);
}
// === Normalize + count ===
const counts = {};
for (let tag of allTags) {
if (!tag) continue;
tag = String(tag).replace(/^#/, '').trim().toLowerCase();
if (!tag) continue;
if (splitOnSlash && tag.includes('/')) tag = tag.split('/')[0];
counts[tag] = (counts[tag] || 0) + 1;
}
const tagEntries = Object.entries(counts);
if (tagEntries.length === 0) {
dv.el("p", "⚠️ No tags found in your vault.");
} else {
// === Sort + limit ===
tagEntries.sort((a, b) => b[1] - a[1]);
const limited = (topN && tagEntries.length > topN)
? tagEntries.slice(0, topN)
: tagEntries;
const labels = limited.map(e => toTitleCase(e[0].replace(/[-_]/g, ' ')));
const dataValues = limited.map(e => e[1]);
const total = dataValues.reduce((a, b) => a + b, 0);
// === Colors ===
const bgColors = [], borderColors = [];
for (let i = 0; i < labels.length; i++) {
const color = catppuccinColors[i % catppuccinColors.length];
bgColors.push(color + "aa");
borderColors.push(color);
}
// === Create container ===
const wrapper = this.container.createEl('div');
wrapper.style.minHeight = '400px';
wrapper.style.maxHeight = '70vh';
wrapper.style.position = 'relative';
wrapper.style.borderRadius = '8px';
wrapper.style.padding = '8px';
wrapper.style.overflow = 'auto';
// === Center label ===
const centerLabel = document.createElement('div');
centerLabel.style.position = 'absolute';
centerLabel.style.top = '50%';
centerLabel.style.left = '44%';
centerLabel.style.transform = 'translate(-50%, -50%)';
centerLabel.style.color = catppuccin.text;
centerLabel.style.fontSize = '14px';
centerLabel.style.fontWeight = '600';
centerLabel.style.textAlign = 'center';
centerLabel.innerText = 'Tag Usage';
wrapper.appendChild(centerLabel);
// === Chart.js config ===
const chartData = {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: dataValues,
backgroundColor: bgColors,
borderColor: borderColors,
borderWidth: 1
}]
},
options: {
cutout: '60%',
plugins: {
legend: {
display: true,
position: 'right',
labels: { color: catppuccin.subtext1, font: { size: 12 } }
},
title: {
display: true,
text: `Tag Distribution (Top ${labels.length})`,
color: catppuccin.text,
font: { size: 16 }
},
tooltip: {
callbacks: {
label: ctx => {
const val = ctx.raw;
const pct = ((val / total) * 100).toFixed(1);
return `${ctx.label}: ${val} (${pct}%)`;
}
}
}
},
onHover: (evt, elements) => {
if (elements.length > 0) {
const el = elements[0];
const label = labels[el.index];
const value = dataValues[el.index];
const pct = ((value / total) * 100).toFixed(1);
centerLabel.innerText = `${label}\n${pct}%`;
} else {
centerLabel.innerText = 'Tag Usage';
}
},
maintainAspectRatio: false
}
};
window.renderChart(chartData, wrapper);
}