3.6 KiB
Todo-Glance
A server-backed CRUD todo widget for Glance. Stores tasks in SQLite instead of browser localStorage, so your todos persist across devices and sessions.
Integrates as a Glance Extension widget with native theming via Glance CSS variables.
Stack
- Go — single
main.go, no frameworks - SQLite via modernc.org/sqlite — pure Go, no CGO required
- Vanilla JS — embedded in the Go binary, no build step
Quick Start
Docker Compose (recommended)
docker compose up --build
- Glance dashboard:
http://localhost:8080 - Todo API:
http://localhost:8081
The included glance.yml has the widget pre-configured. Edit it to add your other Glance widgets.
Standalone
go build -o todo-glance .
./todo-glance
Then add the widget to your existing Glance config:
- type: extension
url: http://todo-glance:8081/
allow-potentially-dangerous-html: true
cache: 1s
Replace todo-glance with the hostname or IP where the server is reachable from Glance.
Environment Variables
| Variable | Default | Description |
|---|---|---|
TODO_PORT |
8081 |
Server listen port |
TODO_DB_PATH |
./todos.db |
SQLite database file path |
TODO_EXTERNAL_URL |
(from Host header) | URL browsers use to reach the API. Required when the browser-facing URL differs from the internal one (e.g. behind a reverse proxy). |
API
| Method | Path | Description |
|---|---|---|
GET |
/ |
Extension widget HTML (returns Widget-Title and Widget-Content-Type headers) |
GET |
/api/todos |
List all todos |
POST |
/api/todos |
Create a todo — {"text": "...", "priority": 0-3, "tags": [...]} |
PUT |
/api/todos/{id} |
Update a todo — {"text": "...", "done": true, "priority": 0-3, "tags": [...]} |
DELETE |
/api/todos/{id} |
Delete a todo — returns 204 |
Priority levels: 0 = none, 1 = low, 2 = medium, 3 = high. Todos are sorted by: incomplete first, then highest priority, then newest.
Examples
# Create with priority and tags
curl -X POST -H 'Content-Type: application/json' \
-d '{"text":"Fix login bug","priority":3,"tags":["work","urgent"]}' \
http://localhost:8081/api/todos
# Create simple
curl -X POST -H 'Content-Type: application/json' \
-d '{"text":"Buy milk"}' http://localhost:8081/api/todos
# List (sorted by priority)
curl http://localhost:8081/api/todos
# Mark done
curl -X PUT -H 'Content-Type: application/json' \
-d '{"done":true}' http://localhost:8081/api/todos/1
# Change priority
curl -X PUT -H 'Content-Type: application/json' \
-d '{"priority":2}' http://localhost:8081/api/todos/1
# Update tags
curl -X PUT -H 'Content-Type: application/json' \
-d '{"tags":["work","reviewed"]}' http://localhost:8081/api/todos/1
# Delete
curl -X DELETE http://localhost:8081/api/todos/1
Architecture
Browser (Glance page)
│
│ GET / Glance fetches widget HTML from todo-glance
│ ─────────────► (internal Docker network)
│
│ API calls JS in the widget calls /api/* endpoints
│ ─────────────► (browser hits TODO_EXTERNAL_URL / localhost:8081)
│
▼
todo-glance ──► SQLite file (/data/todos.db in Docker)
The HTML is served to Glance over the internal network. Once rendered in the browser, the embedded JS makes API calls directly to the todo-glance server using the external URL. CORS headers are set on all /api/ endpoints to allow this cross-origin access.