diff --git a/skills/daily-focus-board/assets/board.template.html b/skills/daily-focus-board/assets/board.template.html index e06ad916..747f8509 100644 --- a/skills/daily-focus-board/assets/board.template.html +++ b/skills/daily-focus-board/assets/board.template.html @@ -331,7 +331,7 @@ function render(){ +`` - +``; + +``; if(isCounter(t)){ const v=state.counters[t.id],g=t.goal>0?t.goal:1,pct=Math.min(100,Math.round(v/g*100)),inc=t.inc||Math.max(1,Math.round(g/10)),unit=t.unit||""; c.innerHTML=`
${esc(t.emoji||"🎯")}
@@ -418,6 +418,7 @@ function tagOf(t){return state.tag[t.id]!==undefined?state.tag[t.id]:(t.tag||"") function setQuad(id,v){state.quad[id]=v;save();render();} function setTag(id,v){state.tag[id]=v;save();render();} function escAttr(s){return esc(s).replace(/"/g,""");} +function safeCls(s){return (s||"").replace(/[^a-zA-Z0-9_-]/g,"");} function reorder(from,targetId){if(!from||from===targetId)return;let ids=renderedIds.slice();const fromI=ids.indexOf(from),tgtI=ids.indexOf(targetId);if(fromI<0||tgtI<0)return;ids.splice(fromI,1);let ins=ids.indexOf(targetId);if(fromI{const ca=carriedOf(a)?1:0,cb=carriedOf(b)?1:0;if(ca!==cb)return ca-cb;const ra=(rank[quadOf(a)]===undefined?4:rank[quadOf(a)]),rb=(rank[quadOf(b)]===undefined?4:rank[quadOf(b)]);if(ra!==rb)return ra-rb;return orderIndex(a.id)-orderIndex(b.id);}).map(t=>t.id);state.order=ids;save();render();} function updateOverload(){const el=document.getElementById("overload");if(!el)return;const live=tasks.filter(t=>!carriedOf(t)&&statusOf(t)!=="done").length;if(live>9){el.style.display="block";el.textContent=`That's ${live} active tasks for today — more than a focus board loves. Consider carrying a few to tomorrow (⤳ not today), or use Focus mode to take one at a time. No pressure — this is a nudge, not a rule.`;}else{el.style.display="none";}} diff --git a/skills/daily-focus-board/examples/sample-board.html b/skills/daily-focus-board/examples/sample-board.html index 697c2a76..54b3f82c 100644 --- a/skills/daily-focus-board/examples/sample-board.html +++ b/skills/daily-focus-board/examples/sample-board.html @@ -341,7 +341,7 @@ function render(){ +`` - +`
`; + +``; if(isCounter(t)){ const v=state.counters[t.id],g=t.goal>0?t.goal:1,pct=Math.min(100,Math.round(v/g*100)),inc=t.inc||Math.max(1,Math.round(g/10)),unit=t.unit||""; c.innerHTML=`
${esc(t.emoji||"🎯")}
@@ -428,6 +428,7 @@ function tagOf(t){return state.tag[t.id]!==undefined?state.tag[t.id]:(t.tag||"") function setQuad(id,v){state.quad[id]=v;save();render();} function setTag(id,v){state.tag[id]=v;save();render();} function escAttr(s){return esc(s).replace(/"/g,""");} +function safeCls(s){return (s||"").replace(/[^a-zA-Z0-9_-]/g,"");} function reorder(from,targetId){if(!from||from===targetId)return;let ids=renderedIds.slice();const fromI=ids.indexOf(from),tgtI=ids.indexOf(targetId);if(fromI<0||tgtI<0)return;ids.splice(fromI,1);let ins=ids.indexOf(targetId);if(fromI{const ca=carriedOf(a)?1:0,cb=carriedOf(b)?1:0;if(ca!==cb)return ca-cb;const ra=(rank[quadOf(a)]===undefined?4:rank[quadOf(a)]),rb=(rank[quadOf(b)]===undefined?4:rank[quadOf(b)]);if(ra!==rb)return ra-rb;return orderIndex(a.id)-orderIndex(b.id);}).map(t=>t.id);state.order=ids;save();render();} function updateOverload(){const el=document.getElementById("overload");if(!el)return;const live=tasks.filter(t=>!carriedOf(t)&&statusOf(t)!=="done").length;if(live>9){el.style.display="block";el.textContent=`That's ${live} active tasks for today — more than a focus board loves. Consider carrying a few to tomorrow (⤳ not today), or use Focus mode to take one at a time. No pressure — this is a nudge, not a rule.`;}else{el.style.display="none";}} diff --git a/skills/daily-focus-board/references/customize.md b/skills/daily-focus-board/references/customize.md index cb9d0dcd..3bcde66d 100644 --- a/skills/daily-focus-board/references/customize.md +++ b/skills/daily-focus-board/references/customize.md @@ -3,8 +3,8 @@ ## Theming Colors live in the `:root` CSS block of `assets/board.template.html` (`--ember`, `--good`, `--urgent`, backgrounds). The look is warm/dark by default. Tag colors: -`new` (green), `deadline` (red), `career` (purple) — add your own by copying a `.tag.` -rule and passing that name as a task's `tagc`. +`new` (green), `deadline` (red), `career` (purple) — add your own by copying a `.tagedit.` +rule and passing that name as a task's `tagc` (use a plain class name: letters, digits, `-`, `_`). ## v2 — file-backed state (closes the agent loop) v1 stores progress in the browser (`localStorage`), which the agent can't read back. To let diff --git a/skills/daily-focus-board/scripts/serve-board.ps1 b/skills/daily-focus-board/scripts/serve-board.ps1 index fe5f0e85..04cb2fc6 100644 --- a/skills/daily-focus-board/scripts/serve-board.ps1 +++ b/skills/daily-focus-board/scripts/serve-board.ps1 @@ -7,8 +7,17 @@ param( ) $full = Join-Path $Dir $File if (-not (Test-Path $full)) { Write-Error "Board not found: $full"; exit 1 } -Start-Process -FilePath "python" -ArgumentList @("-m","http.server","$Port","--bind","127.0.0.1","--directory","`"$Dir`"") -WindowStyle Hidden +try { + if (Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue) { + Write-Error "Port $Port is already in use — choose another with -Port or stop the existing server."; exit 1 + } +} catch { } # Get-NetTCPConnection may be unavailable on some platforms; skip the pre-check there. +$proc = Start-Process -FilePath "python" -ArgumentList @("-m","http.server","$Port","--bind","127.0.0.1","--directory","`"$Dir`"") -WindowStyle Hidden -PassThru Start-Sleep -Seconds 2 +if ($proc.HasExited) { + Write-Error "The server exited on startup (code $($proc.ExitCode)) — is Python installed and the port free?"; exit 1 +} $url = "http://localhost:$Port/$File" Write-Host "Focus board: $url" +Write-Host "Server PID $($proc.Id) — stop it with: Stop-Process -Id $($proc.Id)" Start-Process $url # opens in default browser; in a Copilot-app session, open a browser canvas to this URL instead