Unify about and home page views.

This commit is contained in:
Chris McCormick 2026-01-07 09:59:31 +08:00
parent a2359c41c4
commit 84b21eb810
3 changed files with 81 additions and 37 deletions

View file

@ -5,6 +5,7 @@ A Kanban board for your Markdown TODO file in a single [index.html](./index.html
- Single HTML file - simply upload to self-host - Single HTML file - simply upload to self-host
- CLI tool to launch as a Chrome app: `kbtd TODO.md` - CLI tool to launch as a Chrome app: `kbtd TODO.md`
- Two-way binding between UI and text file - Two-way binding between UI and text file
- Great for indie-scale solo projects and small teams
![Screencast of TODO Kanban editing a TODO.md file](./screencast.gif) ![Screencast of TODO Kanban editing a TODO.md file](./screencast.gif)

View file

@ -9,15 +9,10 @@
## TODO ## TODO
- [ ] Display sub-lines of the form `key: value` immediately after item - [ ] Display sub-lines of the form `key: value` immediately after item
- [ ] Project list pulldown in top right
## Bugs ## Bugs
## Refactor
- [ ] Consolidate menu creation (card menus and burger menu)
- [ ] Extract line parsing logic - separate parsing from state management
- [ ] Make createAddForm more generic to handle both columns and cards
## Done ## Done
- [x] Make it a proper PWA with the minimal-pwa technique - [x] Make it a proper PWA with the minimal-pwa technique

View file

@ -803,6 +803,23 @@
</style> </style>
</head> </head>
<body> <body>
<template id="intro-content-template">
<h1>Kanban TODO</h1>
<p>A Kanban board for your Markdown TODO file.</p>
<ul style="text-align: left; max-width: 600px;">
<li>Drag-and-drop visual editing of plain text Markdown</li>
<li>Runs 100% in your browser - no server, no database</li>
<li>Single HTML file - upload to self-host</li>
<li>CLI tool to launch as a Chrome app: <code>kbtd TODO.md</code></li>
<li>Two-way binding between UI and text file</li>
<li>Great for indie-scale solo projects and small teams</li>
</ul>
</template>
<template id="footer-content-template">
<p><a href="https://github.com/chr15m/kanban-todo/blob/main/README.md" target="_blank">See README.md for more info.</a></p>
</template>
<template id="install-instructions-template"> <template id="install-instructions-template">
<p>Install launch script:</p> <p>Install launch script:</p>
<pre>curl -O <a href="https://mccormick.cx/apps/kanban-todo/kbtd">https://mccormick.cx/apps/kanban-todo/kbtd</a> <pre>curl -O <a href="https://mccormick.cx/apps/kanban-todo/kbtd">https://mccormick.cx/apps/kanban-todo/kbtd</a>
@ -815,20 +832,7 @@ chmod 755 kbtd
./kbtd TODO.md</pre> ./kbtd TODO.md</pre>
</template> </template>
<div id="app"> <template id="project-selection-template">
<div id="landing-screen" class="screen center-content">
<h1>Kanban TODO</h1>
<p>A Kanban board for your Markdown TODO file.</p>
<ul style="text-align: left; max-width: 600px;">
<li>Drag-and-drop visual editing of plain text Markdown</li>
<li>Runs 100% in your browser - no server, no database</li>
<li>Single HTML file - upload to self-host</li>
<li>CLI tool to launch as a Chrome app: <code>kbtd TODO.md</code></li>
<li>Two-way binding between UI and text file</li>
</ul>
<div id="api-warning" class="warning" style="display:none; max-width: 600px;">
⚠ Your browser does not support the FileSystem Access API. Chromium-based browsers (Chrome, Edge, etc.) are known to work.
</div>
<div class="project-name-form"> <div class="project-name-form">
<label for="project-name-input">Project name:</label> <label for="project-name-input">Project name:</label>
<div class="form-row"> <div class="form-row">
@ -840,7 +844,23 @@ chmod 755 kbtd
<h3>Recent projects:</h3> <h3>Recent projects:</h3>
<ul id="recent-projects-list" class="recent-projects-list"></ul> <ul id="recent-projects-list" class="recent-projects-list"></ul>
</div> </div>
</template>
<template id="source-copyright-template">
<p><a href="https://github.com/chr15m/kanban-todo" target="_blank">Source code for self-hosting</a> - upload index.html to your server.</p>
<p>Copyright &copy; Chris McCormick 2025</p>
</template>
<div id="app">
<div id="landing-screen" class="screen center-content">
<div id="landing-intro"></div>
<div id="landing-footer"></div>
<div id="api-warning" class="warning" style="display:none; max-width: 600px;">
⚠ Your browser does not support the FileSystem Access API. Chromium-based browsers (Chrome, Edge, etc.) are known to work.
</div>
<div id="landing-project-selection"></div>
<div id="landing-instructions"></div> <div id="landing-instructions"></div>
<div id="landing-source-copyright"></div>
<div id="landing-error" class="error" style="display:none"></div> <div id="landing-error" class="error" style="display:none"></div>
</div> </div>
@ -924,20 +944,13 @@ chmod 755 kbtd
<div id="about-modal" class="modal"> <div id="about-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h3>About Kanban TODO</h3> <div id="about-intro"></div>
<p>A Kanban board for your Markdown TODO file.</p> <div id="about-footer"></div>
<ul style="text-align: left;">
<li>Drag-and-drop visual editing of plain text Markdown</li>
<li>Runs 100% in your browser - no server, no database</li>
<li>Single HTML file - upload to self-host</li>
<li>CLI tool to launch as a Chrome app: <code>kbtd TODO.md</code></li>
</ul>
<div id="about-api-warning" class="warning" style="display:none;"> <div id="about-api-warning" class="warning" style="display:none;">
⚠ Your browser does not support the FileSystem Access API. This app requires a Chromium-based browser (Chrome, Edge, etc.) to work. ⚠ Your browser does not support the FileSystem Access API. This app requires a Chromium-based browser (Chrome, Edge, etc.) to work.
</div> </div>
<div id="about-instructions"></div> <div id="about-instructions"></div>
<p><a href="https://github.com/chr15m/kanban-todo" target="_blank">Source code for self-hosting</a></p> <div id="about-source-copyright"></div>
<p>Copyright &copy; Chris McCormick 2025</p>
<div class="modal-buttons"> <div class="modal-buttons">
<button id="about-close-btn">Close</button> <button id="about-close-btn">Close</button>
</div> </div>
@ -1004,6 +1017,24 @@ chmod 755 kbtd
return parseInt(el.dataset[key]); return parseInt(el.dataset[key]);
} }
function insertIntroContent(containerId) {
const template = $('#intro-content-template');
const clone = template.content.cloneNode(true);
$(`#${containerId}`).appendChild(clone);
}
function insertFooterContent(containerId) {
const template = $('#footer-content-template');
const clone = template.content.cloneNode(true);
$(`#${containerId}`).appendChild(clone);
}
function insertProjectSelection(containerId) {
const template = $('#project-selection-template');
const clone = template.content.cloneNode(true);
$(`#${containerId}`).appendChild(clone);
}
function insertInstallInstructions(containerId) { function insertInstallInstructions(containerId) {
const template = $('#install-instructions-template'); const template = $('#install-instructions-template');
const clone = template.content.cloneNode(true); const clone = template.content.cloneNode(true);
@ -1012,6 +1043,12 @@ chmod 755 kbtd
$(`#${containerId}`).appendChild(clone); $(`#${containerId}`).appendChild(clone);
} }
function insertSourceCopyright(containerId) {
const template = $('#source-copyright-template');
const clone = template.content.cloneNode(true);
$(`#${containerId}`).appendChild(clone);
}
function createAddForm(placeholder, onSubmit, onCancel) { function createAddForm(placeholder, onSubmit, onCancel) {
const input = h('input', { type: 'text', placeholder }); const input = h('input', { type: 'text', placeholder });
const form = h('div', { className: 'add-card-form' }, input); const form = h('div', { className: 'add-card-form' }, input);
@ -2342,8 +2379,17 @@ chmod 755 kbtd
} }
async function init() { async function init() {
insertIntroContent('landing-intro');
insertIntroContent('about-intro');
insertFooterContent('landing-footer');
insertFooterContent('about-footer');
insertProjectSelection('landing-project-selection');
insertInstallInstructions('landing-instructions'); insertInstallInstructions('landing-instructions');
insertInstallInstructions('about-instructions'); insertInstallInstructions('about-instructions');
insertSourceCopyright('landing-source-copyright');
insertSourceCopyright('about-source-copyright');
setupEventHandlers();
if (!checkFileSystemAccessAPI()) { if (!checkFileSystemAccessAPI()) {
$('#api-warning').style.display = 'block'; $('#api-warning').style.display = 'block';
@ -2403,6 +2449,7 @@ chmod 755 kbtd
}, 250); }, 250);
} }
function setupEventHandlers() {
$('#open-file-btn').onclick = async () => { $('#open-file-btn').onclick = async () => {
const projectNameInput = $('#project-name-input'); const projectNameInput = $('#project-name-input');
const projectName = projectNameInput.value.trim(); const projectName = projectNameInput.value.trim();
@ -2522,6 +2569,7 @@ chmod 755 kbtd
$('#move-confirm-btn').onclick = async () => { $('#move-confirm-btn').onclick = async () => {
await confirmMove(); await confirmMove();
}; };
}
// PWA setup // PWA setup
function setupPWA() { function setupPWA() {