Skip to content

About

Logseq Plugin to add Progress Bar to Nodes

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Logseq Progress Bar Plugin

Logseq Progress Bar

Visualize task completion as segmented progress bars in Logseq DB graphs.

Track progress derived from configurable properties (status, state, or any custom enum) on blocks with specified tags (#Task, #Project, etc.). Supports manual placement, query integration, and real-time updates.

DB graphs only — file-based graphs are not supported.

Progress bars on nested task hierarchies and Logseq query blocks — color-coded status segments rolling up to per-parent and per-query completion percentages


Installation

From Local Build

  1. Clone the repo and build:

    cd logseq-progressbar
    pnpm install
    pnpm build

    Requires Node 24 (.nvmrc) and pnpm.

  2. In Logseq, go to Settings → Advanced → Enable Developer mode

  3. Open Plugins (three-dot menu → Plugins)

  4. Click the three-dot menu in the Plugins panel → Load unpacked plugin

  5. Select the logseq-progressbar directory

Development

pnpm dev            # Vite dev server at http://localhost:8296 (HMR, plugin auto-reload)
pnpm watch          # Rebuild dist/ on change (no server)
pnpm test           # Unit tests + feature × settings matrix, with the coverage gate
pnpm typecheck      # Strict TypeScript check (includes the SDK-floor guard)
pnpm build          # Production build
pnpm e2e            # Live matrix in the Logseq web app at localhost:3001
pnpm e2e:desktop    # Live matrix in a second instance of the desktop app

With pnpm dev running, load the plugin in Logseq via Plugins → Load plugin from web url → http://localhost:8296/ (the dev server only answers CORS requests from localhost:3001).


Usage

Basic — Slash Command

Type /progress-bar in any block to insert a progress bar that tracks child blocks.

Manual — Renderer Macro

Insert the macro directly:

{{renderer :progress-bar}}

The bar scans descendant blocks for configured tags and aggregates their statuses.

With Overrides

Override any global setting per-instance:

{{renderer :progress-bar, tags: Task|Bug, property: status, format: both}}
{{renderer :progress-bar, tags: Project, property: state, complete: Completed, width: 300px}}

With a Query

Drop the renderer directly into a Logseq query block (the bar is auto-detected from :logseq.property/query):

{{renderer :progress-bar}}

Both query forms are supported:

  • Simple DSL — Logseq's query DSL. The (task …) clause defines which statuses are tracked:

    (task "Todo" "Doing" "Done")
  • Custom datascript — full datalog as a {:query […]} map or a bare [:find …] vector. The :find clause must pull blocks ((pull ?b [*]) or an equivalent shape):

    {:query [:find (pull ?b [*])
             :where
             [?b :logseq.property/status ?s]
             (or [?s :db/ident :logseq.property/status.todo]
                 [?s :db/ident :logseq.property/status.doing]
                 [?s :db/ident :logseq.property/status.done])]}

To attach a bar to a query block from elsewhere on the page, pass its UUID:

{{renderer :progress-bar, query: 69acb093-df21-438d-9bae-72decf188ed2}}

Either way, results are grouped by the tracked property (status by default) and counted in the plugin.


Renderer Parameters

All parameters are optional. Global plugin settings are used as defaults.

Param Example Description
tags tags: Task|Bug Tags to track (pipe-separated)
property property: state Property to read for progress
complete complete: Done|Canceled Values that count as "complete" (pipe-separated)
depth depth: 2 Scan depth (1, 2, ..., or all)
strict strict: true Only count blocks with matching tags
format format: both Label format: percent, fraction, or both
width width: 200px Bar width: full, compact, or a CSS length / percentage (anything else falls back to full)
query query: <uuid> Track a query block's results

Settings

Open Plugins → Progress Bar → Settings to configure global defaults.

Tag & Property Configuration

Setting Default Description
Tags in Scope Task, Checklist Comma-separated tag names to track
Property Mappings {"Task": "status", "Checklist": "check"} JSON mapping each tag to its progress property. Checkbox-typed properties self-bucket (true → Done, false → Todo).
Complete Values {"status": ["Done"]} JSON mapping each property to its "complete" values (string properties only — booleans bypass this).

Display Settings

Setting Default Description
Default Scan Depth all How deep to scan (all or a number)
Strict Tag Filtering false Exclude untagged blocks from the count
Display Format percent percent (54%), fraction (7/13), or both
Bar Width full full (100% width) or compact (inline)
Show on Empty false Show an empty 0% bar when no items match
Debug logging false Log scan and render details to the plugin console

Hand-edited or stale values are coerced defensively: an invalid display format falls back to percent, a depth of 0 or less means all, and a JSON mapping that is not an object falls back to the default.

Color Overrides

Override segment colors per status value (JSON):

{
  "Done": { "light": "#22c55e", "dark": "#16a34a" },
  "Doing": { "light": "#3b82f6", "dark": "#2563eb" }
}

Default Colors

Status Light Mode Dark Mode
Done #4ade80 #22c55e
Doing / Now #60a5fa #3b82f6
In Review #facc15 #eab308
Todo / Later #e2e8f0 #475569
Backlog #f1f5f9 #334155
Canceled #fca5a5 #ef4444

Colors adapt automatically to Logseq's dark/light theme.


How It Works

  1. The renderer macro triggers on {{renderer :progress-bar, ...}}
  2. Global settings are merged with per-instance overrides
  3. Descendant blocks (or query results) are scanned at the configured depth
  4. Blocks are filtered by tags in scope
  5. The tracked property is read from each block; blocks with no value are skipped
  6. Status counts are aggregated and a completion percentage is calculated
  7. A segmented pill-shaped bar is rendered with completed segments on the left
  8. Hovering shows a tooltip with the full status breakdown
  9. The bar updates in real-time when task statuses change (DB.onChanged)

Examples

Track tasks under a project block

- Project Alpha #Project
  - Design UI #Task (status: Done)
  - Implement API #Task (status: Doing)
  - Write tests #Task (status: Todo)
  - {{renderer :progress-bar}}

Result: segmented bar showing 1/3 complete (33%).

Track with custom property

- Q1 Goals
  - Launch product #Project (state: Completed)
  - Hire team #Project (state: Now)
  - Raise funding #Project (state: Later)
  - {{renderer :progress-bar, tags: Project, property: state, complete: Completed}}

Compact inline bar with fraction

- Sprint 12 {{renderer :progress-bar, format: fraction, width: 200px}}
  - Fix login bug #Task (status: Done)
  - Add search #Task (status: Doing)
  - Update docs #Task (status: Todo)

Track a checklist with clickable checkboxes

The plugin ships #Checklist → check (a :checkbox property) as a built-in default in settings. Tag children with #Checklist (or your own class that declares a :checkbox property) — Logseq renders a native clickable checkbox on the left of the block, and the progress bar updates in real time as you toggle items.

- Trip prep {{renderer :progress-bar}}
  - ☐ Book flights #Checklist
  - ☑ Pack passport #Checklist
  - ☑ Confirm hotel #Checklist
  - ☐ Notify cat-sitter #Checklist

Result: 2/4 complete (50%). true lands in the Done bucket, false in Todo. The plugin does not create the #Checklist class or check property — author them yourself (or rename in settings to point at any class you've already built, e.g. {"MyChecklist": "done"}).

A tagged block whose class declares a :checkbox property counts as Todo even if you've never clicked the checkbox — Logseq renders ☐ by default and the progress bar treats that as "not done yet" to match. Tick it and the bar updates without you having to re-tag the block.

Checkbox and enum-status children can live under the same parent — they roll up into one bar.


Development

Project Structure

src/
├── index.ts        — Thin SDK adapter: the only module importing @logseq/libs
├── sdk.ts          — SdkPort: the four SDK calls the pure modules need
├── progress.ts     — resolveInstance → computeStats → renderTemplate pipeline
├── slots.ts        — Registry of live renderer slots (+ generation counter)
├── settings.ts     — Settings schema, readGlobalConfig (coercion), resolveConfig
├── parser.ts       — Renderer macro argument parser
├── scanner.ts      — Block scanning (children, page, query) through the port
├── query.ts        — Query classifier, DSL→datalog, entity adapter, pull enricher
├── identCache.ts   — Property ident / type / class-property cache
├── aggregator.ts   — Status counting + completion calculation
├── colors.ts       — Palette, segment ordering, colour validation
├── renderer.ts     — HTML rendering, width validation, CSS styles
├── debug.ts        — Verbose-log helper
├── *.test.ts       — Vitest suites next to the module they cover
└── matrix.test.ts  — Every feature × every settings permutation
scripts/e2e/        — Live matrices (web app and desktop app)

Testing

Three layers, all repeatable:

Layer Command What it proves
Unit + matrix pnpm test Every pure module; 13 features × 144 settings permutations; 80 % coverage gate
Live, web app pnpm e2e Seeds a page in the Logseq web app (localhost:3001), checks every scenario under 48 settings permutations in the host DOM, flips a status and a checkbox, toggles the theme, edits another page, and counts every SDK call the plugin makes (zero graph writes, reads stop after one debounced burst)
Live, desktop app pnpm e2e:desktop The same matrix in a second instance of the installed desktop app on a throwaway graph; settings are applied in memory so the shared settings file is never written

See the headers of scripts/e2e/progress-matrix.sh and desktop-matrix.sh for prerequisites.


Privacy

The plugin runs entirely inside your Logseq client. No data leaves the client — there are no external network calls, no telemetry, and no third-party services. The plugin's own page carries a Content-Security-Policy that only allows its bundled code.

Graph writes: none. The plugin never creates, edits or deletes blocks, pages, tags or properties. It reads block properties and runs Datascript queries against the loaded graph, and renders the bar into Logseq's plugin UI slot (provideUI), which is DOM only. The live test suite (pnpm e2e) counts every SDK call during a full run and fails if a single write occurs.

The only thing the plugin stores is its settings (tags, property mappings, colour overrides), which Logseq keeps in its standard plugin-settings file alongside other plugin settings.


License

MIT

About

Logseq Plugin to add Progress Bar to Nodes

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages