diff --git a/Makefile b/Makefile index 1a1ba84..14b0251 100755 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ VENV := .venv PY := $(VENV)/bin/python PIP := $(VENV)/bin/pip -all: fix-permissions clean-output clean-venv build search +all: fix-permissions clean-output build search clean-venv build: @echo "Building project..." diff --git a/assets/images/blogs/2026-03-12-journeys-branch.png b/assets/images/blogs/2026-03-12-journeys-branch.png new file mode 100644 index 0000000..1e0eafe Binary files /dev/null and b/assets/images/blogs/2026-03-12-journeys-branch.png differ diff --git a/assets/images/blogs/2026-03-18-slack-dag-manager.png b/assets/images/blogs/2026-03-18-slack-dag-manager.png new file mode 100644 index 0000000..39a9247 Binary files /dev/null and b/assets/images/blogs/2026-03-18-slack-dag-manager.png differ diff --git a/assets/images/reviews/timesheets/2026-03-15-timesheet.png b/assets/images/reviews/timesheets/2026-03-15-timesheet.png new file mode 100644 index 0000000..e2d4ad6 Binary files /dev/null and b/assets/images/reviews/timesheets/2026-03-15-timesheet.png differ diff --git a/assets/images/reviews/timesheets/timesheet-08-03-26.png b/assets/images/reviews/timesheets/timesheet-08-03-26.png new file mode 100644 index 0000000..6402ba1 Binary files /dev/null and b/assets/images/reviews/timesheets/timesheet-08-03-26.png differ diff --git a/assets/scripts/comments.js b/assets/scripts/comments.js index 3d49226..1c4c772 100755 --- a/assets/scripts/comments.js +++ b/assets/scripts/comments.js @@ -77,17 +77,17 @@ function buildCommentTree(comments) { const byId = {}; const roots = []; - comments.forEach(c => { - c.children = []; - byId[c.id] = c; + comments.forEach(comment => { + comment.children = []; + byId[comment.id] = comment; }); - comments.forEach(c => { - if (c.parent_id) { - const parent = byId[c.parent_id]; - if (parent) parent.children.push(c); + comments.forEach(comment => { + if (comment.parent_id) { + const parent = byId[comment.parent_id]; + if (parent) parent.children.push(comment); } else { - roots.push(c); + roots.push(comment); } }); @@ -112,7 +112,7 @@ function renderComments(comments) { } const tree = buildCommentTree(comments); - tree.forEach(c => list.appendChild(createComment(c))); + tree.forEach(comment => list.appendChild(createComment(comment))); } @@ -153,8 +153,8 @@ async function postComment(author, content, parentId = null) { function wireCommentForm() { const form = document.getElementById("comment-form"); - form.addEventListener("submit", async e => { - e.preventDefault(); + form.addEventListener("submit", async event => { + event.preventDefault(); const authorInput = form.querySelector("input[name='author']"); const textarea = form.querySelector("textarea[name='content']"); @@ -167,7 +167,7 @@ function wireCommentForm() { const ok = await postComment(author, content); if (ok) { textarea.value = ""; - loadComments(); // same pattern as your Kanban board + loadComments(); } else { alert("Failed to post comment"); } diff --git a/assets/scripts/competency-status-board.js b/assets/scripts/competency-status-board.js index 317924e..baf3db3 100755 --- a/assets/scripts/competency-status-board.js +++ b/assets/scripts/competency-status-board.js @@ -101,33 +101,36 @@ function populateMobileControls(items) { }; } -document.getElementById("move-confirm").addEventListener("click", async () => { - const itemId = document.getElementById("move-item").value; - const from = document.getElementById("move-from").value; - const to = document.getElementById("move-to").value; +const moveConfirmBtn = document.getElementById("move-confirm"); +if (moveConfirmBtn) { + moveConfirmBtn.addEventListener("click", async () => { + const itemId = document.getElementById("move-item").value; + const from = document.getElementById("move-from").value; + const to = document.getElementById("move-to").value; - if (!itemId || !to) { - alert("Select an item and target column"); - return; - } + if (!itemId || !to) { + alert("Select an item and target column"); + return; + } - if (from === to) { - alert("Item is already in that column"); - return; - } + if (from === to) { + alert("Item is already in that column"); + return; + } - const res = await fetch(`/api/competencies/items/${itemId}/state`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ state: to }), + const res = await fetch(`/api/competencies/items/${itemId}/state`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ state: to }), + }); + + if (res.ok) { + loadBoard(); + } else { + alert("Failed to move competency"); + } }); - - if (res.ok) { - loadBoard(); - } else { - alert("Failed to move competency"); - } -}); +} let draggedItemId = null; diff --git a/assets/scripts/wird-tracker.js b/assets/scripts/wird-tracker.js new file mode 100644 index 0000000..68dcb01 --- /dev/null +++ b/assets/scripts/wird-tracker.js @@ -0,0 +1,557 @@ +/* ============================================================ + wird-tracker.js + ============================================================ */ + +(function () { + "use strict"; + + const API = "/api/wird"; + + + // type: "count" | "juz" | "min" | "rating" + const DAILY_WIRD = { + durood: { label: "Durood", type: "count", unit: "count", target: 500 }, + istighfar: { label: "Istighfar", type: "count", unit: "count", target: 200 }, + quran: { label: "Quran", type: "juz", unit: "juz", target: 3 }, + muraqabah: { label: "Muraqabah", type: "min", unit: "min", target: 10 }, + wuqoof_qalbi: { label: "Wuquf Qalbi", type: "rating", unit: "", target: 3 }, + }; + + const WIRD_META = { + ...DAILY_WIRD, + shaykh_meeting: { label: "Meeting w/ Shaykh", type: "meeting", unit: "meeting", target: 1 }, + }; + + const RATING_LABELS = { + 1: "distracted", + 2: "scattered", + 3: "present", + 4: "attentive", + 5: "absorbed", + }; + + const MEETING_CYCLE_DAYS = 21; + + const $ = (sel, ctx = document) => ctx.querySelector(sel); + const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)]; + const isoDate = (d = new Date()) => d.toISOString().slice(0, 10); + + function daysBetween(a, b) { + return Math.round((new Date(b) - new Date(a)) / 86400000); + } + function addDays(iso, n) { + const d = new Date(iso); d.setDate(d.getDate() + n); return isoDate(d); + } + function fmtDisplay(iso) { + return new Date(iso + "T00:00:00").toLocaleDateString("en-GB", { + day: "numeric", month: "short", year: "numeric", + }); + } + + function fmtValue(type, val) { + const meta = WIRD_META[type]; + if (!meta) return val; + if (meta.type === "rating") return val ? `${RATING_LABELS[val] || val} (${val}/5)` : "—"; + if (meta.type === "meeting") return val >= 1 ? "✓ attended" : "✗ missed"; + return `${Number(val).toLocaleString()} ${meta.unit}`; + } + + function statusClass(type, val) { + const meta = WIRD_META[type]; + if (!meta || !val || val <= 0) return ""; + if (meta.type === "rating") { + if (val >= 4) return "over"; + if (val >= 3) return "done"; + return "miss"; + } + if (val >= meta.target * 1.1) return "over"; + if (val >= meta.target) return "done"; + return "miss"; + } + + let allEntries = []; + let todayMap = {}; + let meetingLog = []; + let chart = null; + + document.addEventListener("DOMContentLoaded", async () => { + setTodayLabel(); + await loadAll(); + renderToday(); + renderMeetingPanel(); + renderHistory(); + renderChart(); + bindControls(); + }); + + function setTodayLabel() { + $("#today-date").textContent = new Date().toLocaleDateString("en-GB", { + weekday: "long", day: "numeric", month: "long", year: "numeric", + }); + } + + async function loadAll() { + try { + const r = await fetch(`${API}/entries`); + if (!r.ok) throw new Error(r.status); + allEntries = await r.json(); + buildTodayMap(); + buildMeetingLog(); + } catch (e) { + console.error("Wird API error:", e); + } + } + + function buildTodayMap() { + const today = isoDate(); + todayMap = {}; + for (const e of allEntries) { + if (e.date !== today) continue; + // For ratings, take the latest entry (last log wins), not a sum + if (WIRD_META[e.wirdType]?.type === "rating") { + const existing = todayMap[e.wirdType]; + if (!existing || e.createdAt > existing.createdAt) { + todayMap[e.wirdType] = Number(e.value); + } + } else { + todayMap[e.wirdType] = (todayMap[e.wirdType] || 0) + Number(e.value); + } + } + } + + function buildMeetingLog() { + meetingLog = allEntries + .filter(e => e.wirdType === "shaykh_meeting" && Number(e.value) >= 1) + .sort((a, b) => b.date.localeCompare(a.date)); + } + + async function postEntry(payload) { + const r = await fetch(`${API}/entries`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + if (!r.ok) throw new Error(await r.text()); + return r.json(); + } + + function renderToday() { + const wrap = $("#wird-cards"); + wrap.innerHTML = ""; + let done = 0; + const types = Object.keys(DAILY_WIRD); + + for (const type of types) { + const meta = DAILY_WIRD[type]; + const val = todayMap[type] || 0; + const cls = statusClass(type, val); + if (cls === "done" || cls === "over") done++; + + const card = document.createElement("div"); + card.className = `wird-card ${cls}`; + card.dataset.type = type; + + if (meta.type === "rating") { + card.innerHTML = buildRatingCard(meta, val); + } else { + const pct = Math.min((val / meta.target) * 100, 100); + card.innerHTML = ` +
${meta.label}
+
+ ${fmtValue(type, val)} + / ${meta.target.toLocaleString()} ${meta.unit} +
+
+
+
+ + `; + } + + card.querySelector(".card-log-btn").addEventListener("click", () => openModal(type)); + wrap.appendChild(card); + } + + const pct = Math.round((done / types.length) * 100); + $("#today-progress-fill").style.width = pct + "%"; + $("#today-progress-label").textContent = `${done} / ${types.length} complete`; + } + + function buildRatingCard(meta, val) { + // 5 pips, filled up to current rating + const pips = [1,2,3,4,5].map(n => { + const filled = val >= n; + const isMin = n === meta.target; + return ``; + }).join(""); + + const lbl = val ? `${RATING_LABELS[val]} (${val}/5)` : "not logged"; + + return ` +
${meta.label}
+
${pips}
+
${lbl}
+ + `; + } + + const modal = $("#log-modal"); + const form = $("#log-form"); + const typeEl = $("#log-type"); + const valEl = $("#log-value"); + const dateEl = $("#log-date"); + const notesEl = $("#log-notes"); + const ratingEl = $("#log-rating-value"); + + // Pip click handlers + let selectedRating = 0; + $$("#modal-pips .modal-pip").forEach(btn => { + btn.addEventListener("click", () => { + selectedRating = parseInt(btn.dataset.val); + ratingEl.value = selectedRating; + $$("#modal-pips .modal-pip").forEach(b => { + const v = parseInt(b.dataset.val); + b.classList.toggle("selected", v <= selectedRating); + }); + }); + }); + + function openModal(preType = null) { + form.reset(); + selectedRating = 0; + ratingEl.value = ""; + $$("#modal-pips .modal-pip").forEach(b => b.classList.remove("selected")); + dateEl.value = isoDate(); + if (preType) typeEl.value = preType; + updateModalFields(); + modal.showModal(); + } + + function openMeetingModal() { + form.reset(); + dateEl.value = isoDate(); + typeEl.value = "shaykh_meeting"; + updateModalFields(); + modal.showModal(); + } + + function updateModalFields() { + const type = typeEl.value; + const isRating = type === "wuqoof_qalbi"; + const isMeeting = type === "shaykh_meeting"; + + $("#value-group").style.display = (!isRating && !isMeeting) ? "" : "none"; + $("#rating-group").style.display = isRating ? "" : "none"; + $("#shaykh-group").style.display = isMeeting ? "" : "none"; + + if (!isRating && !isMeeting) { + const meta = DAILY_WIRD[type]; + if (meta) valEl.placeholder = `Target: ${meta.target} ${meta.unit}`; + } + } + + typeEl.addEventListener("change", updateModalFields); + $("#modal-cancel").addEventListener("click", () => modal.close()); + + form.addEventListener("submit", async (e) => { + e.preventDefault(); + const type = typeEl.value; + const isRating = type === "wuqoof_qalbi"; + const isMtg = type === "shaykh_meeting"; + + if (isRating && !ratingEl.value) { + alert("Please select a rating."); + return; + } + + const payload = { + wirdType: type, + date: dateEl.value, + value: isRating ? Number(ratingEl.value) + : isMtg ? 1 + : Number(valEl.value), + notes: notesEl.value.trim() || null, + }; + + try { + const saved = await postEntry(payload); + allEntries.push(saved); + buildTodayMap(); + buildMeetingLog(); + renderToday(); + renderMeetingPanel(); + renderHistory(); + renderChart(); + modal.close(); + } catch (err) { + alert("Could not save entry: " + err.message); + } + }); + + function renderMeetingPanel() { + const today = isoDate(); + const last = meetingLog[0] || null; + const lastDate = last ? last.date : null; + const nextDate = lastDate ? addDays(lastDate, MEETING_CYCLE_DAYS) : null; + const daysToNext = nextDate ? daysBetween(today, nextDate) : null; + + let statusHtml = ""; + if (!lastDate) { + statusHtml = `No meetings logged yet`; + } else if (daysToNext > 0) { + statusHtml = `Next due in ${daysToNext} day${daysToNext !== 1 ? "s" : ""} — ${fmtDisplay(nextDate)}`; + } else if (daysToNext === 0) { + statusHtml = `Due today`; + } else { + const ov = Math.abs(daysToNext); + statusHtml = `${ov} day${ov !== 1 ? "s" : ""} overdue — expected ${fmtDisplay(nextDate)}`; + } + + const cycles = buildCycleInsights(); + const cycleRows = cycles.map(c => ` + + ${fmtDisplay(c.start)} → ${fmtDisplay(c.end)} + ${c.met + ? `✓ met — ${fmtDisplay(c.metOn)}` + : c.ongoing + ? `ongoing` + : `✗ missed`} + + ${c.met ? `day ${c.dayOfCycle}` : "—"} + + `).join(""); + + $("#meeting-panel-body").innerHTML = ` +
+
+ Last meeting + ${lastDate ? fmtDisplay(lastDate) : "—"} +
+
+ Next expected + ${nextDate ? fmtDisplay(nextDate) : "—"} +
+
${statusHtml}
+
+
+

3-week cycles

+ ${cycles.length === 0 + ? `

Log at least one meeting to see cycle insights.

` + : ` + + ${cycleRows} +
Cycle windowStatusWhen
`} +
+ `; + } + + function buildCycleInsights() { + if (meetingLog.length === 0) return []; + const dates = [...meetingLog].reverse().map(e => e.date); + const today = isoDate(); + const cycles = []; + let start = dates[0]; + while (start <= today) { + const end = addDays(start, MEETING_CYCLE_DAYS - 1); + const hit = dates.find(d => d >= start && d <= end); + cycles.push({ + start, end, + met: !!hit, + metOn: hit || null, + dayOfCycle: hit ? daysBetween(start, hit) + 1 : null, + ongoing: end > today, + }); + start = addDays(end, 1); + } + return cycles.reverse(); + } + + function renderHistory() { + const tbody = $("#history-body"); + tbody.innerHTML = ""; + + const sorted = [...allEntries] + .filter(e => e.wirdType !== "shaykh_meeting") + .sort((a, b) => b.date.localeCompare(a.date)); + + if (sorted.length === 0) { + tbody.innerHTML = `No entries yet.`; + return; + } + + for (const e of sorted) { + const meta = WIRD_META[e.wirdType] || {}; + const cls = statusClass(e.wirdType, e.value); + const badgeTxt = cls === "over" ? (meta.type === "rating" ? "flourishing" : "above") + : cls === "done" ? (meta.type === "rating" ? "present" : "met") + : cls === "miss" ? (meta.type === "rating" ? "below" : "below") + : "—"; + const tr = document.createElement("tr"); + tr.innerHTML = ` + ${e.date} + ${meta.label || e.wirdType} + ${fmtValue(e.wirdType, e.value)} + ${badgeTxt} + ${e.notes || ""} + `; + tbody.appendChild(tr); + } + } + + function renderChart() { + const type = $("#trend-type").value; + const days = parseInt($("#trend-range").value); + const meta = WIRD_META[type]; + const isRating = meta.type === "rating"; + const now = new Date(); + + const labels = []; + const vals = []; + + for (let i = days - 1; i >= 0; i--) { + const d = new Date(now); + d.setDate(d.getDate() - i); + const iso = isoDate(d); + labels.push(iso.slice(5)); + + const dayEntries = allEntries.filter(e => e.date === iso && e.wirdType === type); + if (isRating) { + // Use the last logged rating for the day + const last = dayEntries.sort((a,b) => a.createdAt > b.createdAt ? 1 : -1).pop(); + vals.push(last ? Number(last.value) : 0); + } else { + vals.push(dayEntries.reduce((s, e) => s + Number(e.value), 0)); + } + } + + const nonZero = vals.filter(v => v > 0); + const avg = nonZero.length + ? (isRating + ? (nonZero.reduce((a,b)=>a+b,0)/nonZero.length).toFixed(1) + : Math.round(nonZero.reduce((a,b)=>a+b,0)/nonZero.length)) + : 0; + const max = nonZero.length ? Math.max(...nonZero) : 0; + const streak = calcStreak(type); + + if (isRating) { + $("#trend-stats").innerHTML = ` +
${avg}avg rating
+
${RATING_LABELS[max] || "—"}best day
+
${streak}dstreak e ${meta.target}
+
${nonZero.length}days logged
+ `; + } else { + $("#trend-stats").innerHTML = ` +
${Number(avg).toLocaleString()}avg / day
+
${Number(max).toLocaleString()}best day
+
${streak}dcurrent streak
+
${meta.target.toLocaleString()}daily target
+ `; + } + + const cs = getComputedStyle(document.documentElement); + const accent = cs.getPropertyValue("--wird-accent").trim() || "#7c5c3a"; + const gridColor = cs.getPropertyValue("--border").trim() || "#d7d7d7"; + const tickColor = cs.getPropertyValue("--muted").trim() || "#666"; + + const ctx = $("#trend-chart").getContext("2d"); + if (chart) chart.destroy(); + + chart = new Chart(ctx, { + type: "line", + data: { + labels, + datasets: [ + { + label: meta.label, + data: vals, + borderColor: accent, + backgroundColor: accent + "22", + fill: true, + tension: .35, + pointRadius: 3, + pointHoverRadius: 5, + }, + { + label: "Target", + data: vals.map(() => meta.target), + borderColor: "rgba(74,124,89,.5)", + borderDash: [5,4], + pointRadius: 0, + fill: false, + tension: 0, + }, + ], + }, + options: { + responsive: true, + maintainAspectRatio: true, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + label: ctx => { + const v = ctx.parsed.y; + if (isRating && ctx.datasetIndex === 0) + return `${meta.label}: ${RATING_LABELS[v] || v} (${v}/5)`; + return `${ctx.dataset.label}: ${v}`; + }, + }, + }, + }, + scales: { + x: { + grid: { color: gridColor + "22" }, + ticks: { color: tickColor, font: { family: "monospace", size: 10 }, maxTicksLimit: 10 }, + }, + y: { + grid: { color: gridColor + "22" }, + ticks: { + color: tickColor, + font: { family: "monospace", size: 10 }, + // For rating chart: show labels instead of numbers + ...(isRating ? { + min: 0, max: 5, stepSize: 1, + callback: v => RATING_LABELS[v] || (v === 0 ? "" : v), + } : {}), + }, + beginAtZero: true, + ...(isRating ? { min: 0, max: 5 } : {}), + }, + }, + }, + }); + } + + function calcStreak(type) { + const meta = WIRD_META[type]; + let streak = 0; + const now = new Date(); + for (let i = 0; i < 365; i++) { + const d = new Date(now); + d.setDate(d.getDate() - i); + const iso = isoDate(d); + const entries = allEntries.filter(e => e.date === iso && e.wirdType === type); + let total; + if (meta.type === "rating") { + const last = entries.sort((a,b) => a.createdAt > b.createdAt ? 1 : -1).pop(); + total = last ? Number(last.value) : 0; + } else { + total = entries.reduce((s, e) => s + Number(e.value), 0); + } + if (total >= meta.target) streak++; + else if (i > 0) break; + } + return streak; + } + + function bindControls() { + $("#open-log-btn").addEventListener("click", () => openModal()); + $("#log-meeting-btn").addEventListener("click", openMeetingModal); + $("#trend-type").addEventListener("change", renderChart); + $("#trend-range").addEventListener("change", renderChart); + } + +})(); + diff --git a/assets/styles/style.css b/assets/styles/style.css index d548dd3..170e230 100755 --- a/assets/styles/style.css +++ b/assets/styles/style.css @@ -317,7 +317,7 @@ body.no-sidenotes { .note { position: relative; padding: 1rem 1rem 0.9rem; - background: #fffef8; + background: --code-bg; border-radius: 8px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08), @@ -326,6 +326,7 @@ body.no-sidenotes { transition: transform 0.15s ease, box-shadow 0.15s ease; + } /* subtle randomness */ @@ -391,6 +392,7 @@ body.no-sidenotes { font-size: 0.95rem; line-height: 1.45; white-space: pre-wrap; + color: --fg; } /* ========================= @@ -424,7 +426,7 @@ body.no-sidenotes { #notes-form { width: 100%; max-width: 420px; - background: #fffef8; + background: --bg; padding: 1.25rem 1.25rem 1.1rem; border-radius: 10px; box-shadow: diff --git a/assets/styles/wird-tracker.css b/assets/styles/wird-tracker.css new file mode 100644 index 0000000..3a0a196 Binary files /dev/null and b/assets/styles/wird-tracker.css differ diff --git a/blogs/2025/2025-list.org b/blogs/2025/2025-list.org deleted file mode 100755 index 54f7657..0000000 --- a/blogs/2025/2025-list.org +++ /dev/null @@ -1,28 +0,0 @@ -#+TITLE: 2025 List -#+OPTIONS: toc:nil num:nil - -See the categories: @@html:Categories@@ - -* 2025 - -** December 2025 -- [[file:12-december/28-12-week-review.org][[28-12-2025] - Weekly Review]] @@html:28-12-2025 12:12@@ @@html: review @@ -- [[file:12-december/21-12-week-review.org][[21-12-2025] - Weekly Review]] @@html:21-12-2025 12:12@@ @@html: review @@ -- [[file:12-december/14-12-week-review.org][[14-12-2025] - Weekly Review]] @@html:09-12-2025 12:12@@ @@html: review @@ -- [[file:12-december/07-12-week-review.org][[07-12-2025] - Weekly Review]] @@html:07-12-2025 20:34@@ @@html: review @@ - -** November 2025 -- [[file:11-november/30-11-week-review.org][[30-11-2025] - Weekly Review]] @@html:30-11-2025 17:09@@ @@html: review @@ -- [[file:11-november/23-11-week-review.org][[23-11-2025] - Weekly Review]] @@html:17-11-2025 18:05@@ @@html: review @@ -- [[file:11-november/16-11-week-review.org][[16-11-2025] - Weekly Review]] @@html:10-11-2025 17:44@@ @@html: review @@ -- [[file:11-november/09-11-week-review.org][[09-11-2025] - Weekly Review]] @@html:09-11-2025 20:08@@ @@html: review @@ -- [[file:11-november/02-11-week-review.org][[02-11-2025] - Weekly Review]] @@html:02-11-2025 00:00@@ @@html: review @@ - -** August 2025 -- [[file:08-august/third-time.org][Third Time]] @@html:28-08-2025 17:08@@ @@html: insights @@ -- [[file:08-august/benefits-of-reading.org][Benefits of Reading]] @@html:14-08-2025 23:36@@ @@html: reading @@ @@html: insights @@ -- [[file:08-august/hilberts.hotel.org][Hilbert's Hotel]] @@html:11-08-2025 18:39@@ @@html: maths @@ @@html: insights @@ -- [[file:08-august/spending-the-whole-day-on-this-website.org][09-08-2025: Website Changes]] @@html:09-08-2025 00:00@@ @@html: emacs @@ @@html: website @@ -- [[file:08-august/what-do-i-want-to-do-with-emacs.org][What Do I Want To Do With Emacs]] @@html:08-08-2025 00:00@@ @@html: emacs @@ @@html: review @@ -- [[file:08-august/wacom-with-arch.org][Wacom With Arch]] @@html:08-08-2025 00:00@@ @@html: insights @@ -- [[file:08-august/zettelkasten.org][Zettelkasten Method]] @@html:07-08-2025 00:00@@ @@html: education @@ diff --git a/blogs/2026/03-march/08-03-week-review.org b/blogs/2026/03-march/08-03-week-review.org new file mode 100644 index 0000000..8bc222b --- /dev/null +++ b/blogs/2026/03-march/08-03-week-review.org @@ -0,0 +1,15 @@ +#+TITLE: [08-03-2026] - Weekly Review +#+OPTIONS: num:nil +#+DATE: <2026-03-08 Sun 12:00> +#+filetags: :review: +#+COMMENTS: t +#+SLUG: 08-03-26-week-review + +* Review +Another work week done. This week was spent mostly working on the Journeys upgrade (again), but we are nearing completion. Towards the end of the week we had to drop what we were doing to focus on getting Site Visits to live. I hope that In'sha'Allah I can do the deployment process for Journeys as there is a lot of learning potential. + +Unfortunately Hyper-V broke on my laptop, so I have to go in the office next monday to get it repaired. + +* Timesheet + +[[../../../assets/images/reviews/timesheets/timesheet-08-03-26.png]] diff --git a/blogs/2026/03-march/15-03-week-review.org b/blogs/2026/03-march/15-03-week-review.org new file mode 100644 index 0000000..b20d666 --- /dev/null +++ b/blogs/2026/03-march/15-03-week-review.org @@ -0,0 +1,20 @@ +#+TITLE: [15-03-2026] - Weekly Review +#+OPTIONS: num:nil +#+DATE: <2026-03-15 Sun 12:00> +#+filetags: :review: +#+COMMENTS: t +#+SLUG: 15-03-26-week-review + +* Review + +This week was a four day work week. I had no plans on booking the Friday off but a message came saying we were invited to perform Nafl I'tikaaf. Thus, it hit me that this is the last Friday of Ramadan so I should make the most of it. In'sha'Allah I plan to stay until Monday after Fajr (writing this as of <2026-03-12 Thu>). + +I finally finished the upgrades for Journeys Web API. I released a PR on <2026-03-12 Thu> and should get to resolving the comments on Monday In'sha'Allah. + +Over 100 commits on this single PR... + +[[../../../assets/images/blogs/2026-03-12-journeys-branch.png]] + +* Timesheet + +[[../../../assets/images/reviews/timesheets/2026-03-15-timesheet.png]] diff --git a/blogs/2026/03-march/feeling-sleepy.org b/blogs/2026/03-march/feeling-sleepy.org new file mode 100644 index 0000000..575ab42 --- /dev/null +++ b/blogs/2026/03-march/feeling-sleepy.org @@ -0,0 +1,8 @@ +#+TITLE: Feeling extremely sleepy +#+OPTIONS: num:nil +#+DATE: <2026-03-16 Mon 16:18> +#+filetags: :life: +#+COMMENTS: t +#+SLUG: feeling-sleepy + +One thing I realised about myself is that if I feel /sleepy/ (as in running on fumes), then I will literally go unconscious, as I can't tell the difference between reality and dream. diff --git a/blogs/2026/03-march/fixing-the-dag-18-03.org b/blogs/2026/03-march/fixing-the-dag-18-03.org new file mode 100644 index 0000000..1c27b8a --- /dev/null +++ b/blogs/2026/03-march/fixing-the-dag-18-03.org @@ -0,0 +1,10 @@ +#+TITLE: DAG fixes +#+OPTIONS: num:nil +#+DATE: <2026-03-18 Wed 15:01> +#+filetags: :life: +#+COMMENTS: t +#+SLUG: fixing-the-dag-18-03 + +What an interesting morning. So yesterday, my manager sent me a DM asking to look into the DAG stuff (was failing for a few days due to the restructuring of SQ). + +[[../../../assets/images/blogs/2026-03-18-slack-dag-manager.png]] diff --git a/blogs/2026/03-march/oversleeping-16-03.org b/blogs/2026/03-march/oversleeping-16-03.org new file mode 100644 index 0000000..ecfdeb2 --- /dev/null +++ b/blogs/2026/03-march/oversleeping-16-03.org @@ -0,0 +1,10 @@ +#+TITLE: Oversleeping and missing a meeting... +#+OPTIONS: num:nil +#+DATE: <2026-03-16 Mon 11:21> +#+filetags: :life: +#+COMMENTS: t +#+SLUG: oversleeping-16-03 + +Just this morning, I went to sleep at 6 am, due to spending the night elsewhere, and had some urgent things to do. I ended up waking up at 9:30, which meant the daily standup just finished. Never again. + +Sleeping in and missing a meeting is a negative million kind of feeling. diff --git a/blogs/2026/03-march/setting-a-wird-tracker-19-03.org b/blogs/2026/03-march/setting-a-wird-tracker-19-03.org new file mode 100644 index 0000000..3c7837f --- /dev/null +++ b/blogs/2026/03-march/setting-a-wird-tracker-19-03.org @@ -0,0 +1,9 @@ +#+TITLE: Setting a Wird Tracker +#+OPTIONS: num:nil +#+DATE: <2026-03-19 Thu 13:15> +#+filetags: :life: +#+COMMENTS: t +#+SLUG: setting-a-wird-tracker-19-03 + +I decided it was time to use the extensibility of this website to add an [[../../../home/wird-tracker.org][Awrad tracker]], which would serve as a place for me to track the litanies on a daily basis. I used claude to generate the architecture and to give the frontend and backend for it. It did a good job {{{sidenote(1, It also generated a comprehensive documentation here https://zainezq.com/home/guide/wird-tracker-guide.html)}}}. + diff --git a/blogs/2026/2026-list.org b/blogs/2026/2026-list.org deleted file mode 100755 index e4dd8a9..0000000 --- a/blogs/2026/2026-list.org +++ /dev/null @@ -1,25 +0,0 @@ -#+TITLE: 2026 List -#+OPTIONS: toc:nil num:nil - -See the categories: @@html:Categories@@ - -* 2026 - -** March 2026 -- [[file:03-march/01-03-week-review.org][[01-03-2026] - Weekly Review]] @@html:01-03-2026 12:00@@ @@html: review @@ - -** February 2026 -- [[file:02-february/27-02-26.org][Journeys rambles again...]] @@html:27-02-2026 17:12@@ @@html: life @@ -- [[file:02-february/26-02-26.org][Starting the Journeys Upgrade]] @@html:26-02-2026 17:32@@ @@html: life @@ -- [[file:02-february/24-02-26.org][Integration tests failing (sob)]] @@html:24-02-2026 16:55@@ @@html: life @@ -- [[file:02-february/22-02-week-review.org][[22-02-2026] - Weekly Review]] @@html:22-02-2026 12:00@@ @@html: review @@ -- [[file:02-february/15-02-week-review.org][[15-02-2026] - Weekly Review]] @@html:15-02-2026 12:00@@ @@html: review @@ -- [[file:02-february/08-02-week-review.org][[08-02-2026] - Weekly Review]] @@html:08-02-2026 12:00@@ @@html: review @@ -- [[file:02-february/01-02-week-review.org][[01-02-2026] - Weekly Review]] @@html:01-02-2026 12:00@@ @@html: review @@ -- [[file:02-february/third-meeting.org][Third Meeting with lima :)]] @@html:01-02-2026 12:00@@ @@html: life @@ - -** January 2026 -- [[file:01-january/25-01-week-review.org][[25-01-2026] - Weekly Review]] @@html:25-01-2026 12:00@@ @@html: review @@ -- [[file:01-january/18-01-week-review.org][[18-01-2026] - Weekly Review]] @@html:18-01-2026 12:12@@ @@html: review @@ -- [[file:01-january/11-01-week-review.org][[11-01-2026] - Weekly Review]] @@html:11-01-2026 12:12@@ @@html: review @@ -- [[file:01-january/04-01-week-review.org][[04-01-2026] - Weekly Review]] @@html:04-01-2026 12:12@@ @@html: review @@ diff --git a/blogs/blogs-list.org b/blogs/blogs-list.org index 8160b4f..760ef07 100755 --- a/blogs/blogs-list.org +++ b/blogs/blogs-list.org @@ -3,37 +3,54 @@ See the categories: @@html:Categories@@ -* Blogs: -- [[file:2026/2026-list.org][2026 List]] @@html:08-03-2026 17:33@@ -- [[file:2025/2025-list.org][2025 List]] @@html:08-03-2026 17:33@@ +* 2026 + +** March 2026 +- [[file:2026/03-march/setting-a-wird-tracker-19-03.org][Setting a Wird Tracker]] @@html:19-03-2026 13:15@@ @@html: life @@ +- [[file:2026/03-march/fixing-the-dag-18-03.org][DAG fixes]] @@html:18-03-2026 15:01@@ @@html: life @@ +- [[file:2026/03-march/feeling-sleepy.org][Feeling extremely sleepy]] @@html:16-03-2026 16:18@@ @@html: life @@ +- [[file:2026/03-march/oversleeping-16-03.org][Oversleeping and missing a meeting...]] @@html:16-03-2026 11:21@@ @@html: life @@ +- [[file:2026/03-march/15-03-week-review.org][[15-03-2026] - Weekly Review]] @@html:15-03-2026 12:00@@ @@html: review @@ +- [[file:2026/03-march/08-03-week-review.org][[08-03-2026] - Weekly Review]] @@html:08-03-2026 12:00@@ @@html: review @@ - [[file:2026/03-march/01-03-week-review.org][[01-03-2026] - Weekly Review]] @@html:01-03-2026 12:00@@ @@html: review @@ + +** February 2026 - [[file:2026/02-february/27-02-26.org][Journeys rambles again...]] @@html:27-02-2026 17:12@@ @@html: life @@ - [[file:2026/02-february/26-02-26.org][Starting the Journeys Upgrade]] @@html:26-02-2026 17:32@@ @@html: life @@ - [[file:2026/02-february/24-02-26.org][Integration tests failing (sob)]] @@html:24-02-2026 16:55@@ @@html: life @@ - [[file:2026/02-february/22-02-week-review.org][[22-02-2026] - Weekly Review]] @@html:22-02-2026 12:00@@ @@html: review @@ - [[file:2026/02-february/15-02-week-review.org][[15-02-2026] - Weekly Review]] @@html:15-02-2026 12:00@@ @@html: review @@ - [[file:2026/02-february/08-02-week-review.org][[08-02-2026] - Weekly Review]] @@html:08-02-2026 12:00@@ @@html: review @@ -- [[file:2026/02-february/01-02-week-review.org][[01-02-2026] - Weekly Review]] @@html:01-02-2026 12:00@@ @@html: review @@ - [[file:2026/02-february/third-meeting.org][Third Meeting with lima :)]] @@html:01-02-2026 12:00@@ @@html: life @@ +- [[file:2026/02-february/01-02-week-review.org][[01-02-2026] - Weekly Review]] @@html:01-02-2026 12:00@@ @@html: review @@ + +** January 2026 - [[file:2026/01-january/25-01-week-review.org][[25-01-2026] - Weekly Review]] @@html:25-01-2026 12:00@@ @@html: review @@ - [[file:2026/01-january/18-01-week-review.org][[18-01-2026] - Weekly Review]] @@html:18-01-2026 12:12@@ @@html: review @@ - [[file:2026/01-january/11-01-week-review.org][[11-01-2026] - Weekly Review]] @@html:11-01-2026 12:12@@ @@html: review @@ - [[file:2026/01-january/04-01-week-review.org][[04-01-2026] - Weekly Review]] @@html:04-01-2026 12:12@@ @@html: review @@ +* 2025 + +** December 2025 - [[file:2025/12-december/28-12-week-review.org][[28-12-2025] - Weekly Review]] @@html:28-12-2025 12:12@@ @@html: review @@ - [[file:2025/12-december/21-12-week-review.org][[21-12-2025] - Weekly Review]] @@html:21-12-2025 12:12@@ @@html: review @@ - [[file:2025/12-december/14-12-week-review.org][[14-12-2025] - Weekly Review]] @@html:09-12-2025 12:12@@ @@html: review @@ - [[file:2025/12-december/07-12-week-review.org][[07-12-2025] - Weekly Review]] @@html:07-12-2025 20:34@@ @@html: review @@ + +** November 2025 - [[file:2025/11-november/30-11-week-review.org][[30-11-2025] - Weekly Review]] @@html:30-11-2025 17:09@@ @@html: review @@ - [[file:2025/11-november/23-11-week-review.org][[23-11-2025] - Weekly Review]] @@html:17-11-2025 18:05@@ @@html: review @@ - [[file:2025/11-november/16-11-week-review.org][[16-11-2025] - Weekly Review]] @@html:10-11-2025 17:44@@ @@html: review @@ - [[file:2025/11-november/09-11-week-review.org][[09-11-2025] - Weekly Review]] @@html:09-11-2025 20:08@@ @@html: review @@ - [[file:publish-pages.org][How to publish pages using Org Publish]] @@html:08-11-2025 10:57@@ @@html: website @@ - [[file:2025/11-november/02-11-week-review.org][[02-11-2025] - Weekly Review]] @@html:02-11-2025 00:00@@ @@html: review @@ + +** August 2025 - [[file:2025/08-august/third-time.org][Third Time]] @@html:28-08-2025 17:08@@ @@html: insights @@ - [[file:2025/08-august/benefits-of-reading.org][Benefits of Reading]] @@html:14-08-2025 23:36@@ @@html: reading @@ @@html: insights @@ - [[file:2025/08-august/hilberts.hotel.org][Hilbert's Hotel]] @@html:11-08-2025 18:39@@ @@html: maths @@ @@html: insights @@ - [[file:2025/08-august/spending-the-whole-day-on-this-website.org][09-08-2025: Website Changes]] @@html:09-08-2025 00:00@@ @@html: emacs @@ @@html: website @@ -- [[file:2025/08-august/what-do-i-want-to-do-with-emacs.org][What Do I Want To Do With Emacs]] @@html:08-08-2025 00:00@@ @@html: emacs @@ @@html: review @@ - [[file:2025/08-august/wacom-with-arch.org][Wacom With Arch]] @@html:08-08-2025 00:00@@ @@html: insights @@ +- [[file:2025/08-august/what-do-i-want-to-do-with-emacs.org][What Do I Want To Do With Emacs]] @@html:08-08-2025 00:00@@ @@html: emacs @@ @@html: review @@ - [[file:2025/08-august/zettelkasten.org][Zettelkasten Method]] @@html:07-08-2025 00:00@@ @@html: education @@ -- [[file:blogs-intro.org][Blogs Introduction]] @@html:06-08-2025 00:00@@ @@html: introduction @@ \ No newline at end of file +- [[file:blogs-intro.org][Blogs Introduction]] @@html:06-08-2025 00:00@@ @@html: introduction @@ diff --git a/build-site.el b/build-site.el index 2ea88c3..237607e 100755 --- a/build-site.el +++ b/build-site.el @@ -60,6 +60,7 @@ + @@ -71,6 +72,7 @@ + " ) @@ -96,8 +98,7 @@ \"Site