Compare commits

...

16 commits
0.1.1 ... main

Author SHA1 Message Date
Philemon Chiro
94d3f74406 Release 0.2.5
- New "Flat sticky notes" setting disables the per-card wall rotation.
  Requested by a Reddit user who wanted notes to sit perfectly straight.
- Drop the third-party "builtin-modules" dependency in favor of Node's
  built-in node:module.builtinModules — addresses a directory-scanner
  hygiene warning.
- Drop text-decoration-color on colored-card links, since it was only
  partially supported by Obsidian's bundled Chromium and the inherited
  underline color reads fine.
- Add CONTRIBUTING.md covering build, dev, PR conventions, and the
  release workflow.
2026-05-16 20:29:13 +02:00
Philemon Chiro
4e12371044 Release 0.2.4
- Search input no longer loses focus mid-typing while filtering (#2).
- All 36 !important declarations removed from styles.css in favor of
  selector-specificity bumps, clearing the directory scanner's
  '!important' finding.
2026-05-16 04:56:59 +02:00
Philemon Chiro
b3f1cd7ea6 Preserve search focus across renders; remove all !important declarations
Fixes #2: the debounced render emptied the view container on every
keystroke and re-created the search input, so focus dropped each time
filtering finished. Capture the active-element + selection range before
emptying, then restore focus and cursor position after the new input is
mounted.

Also rewrites every !important in styles.css (36 occurrences) by
bumping selector specificity instead — chaining 'body' / 'input.' /
'textarea.' / '.modal.' to win against Obsidian's defaults cleanly.
This clears the directory scanner's '!important' findings.
2026-05-16 04:55:28 +02:00
Philemon Chiro
d1d0f7ddc2 Bump release workflow actions to Node 24 majors
GitHub's deprecation annotation on the 0.2.3 run flagged the prior
v4/v4/v2 actions for using Node 20, which is removed from the runner
in September 2026. Move to actions/checkout@v6, actions/setup-node@v6,
and actions/attest-build-provenance@v4 — all on the node24 runtime.
2026-05-16 04:22:05 +02:00
Philemon Chiro
30315925e5 Release 0.2.3
Maintenance release that ships through the new tag-triggered workflow:
- Build now signs main.js / manifest.json / styles.css with GitHub
  artifact attestation, addressing the directory's missing-attestation
  finding on prior assets.
- pnpm install no longer aborts on the esbuild post-install script, so
  the directory's build verification runs cleanly.
- styles.css uses full 6-digit hex throughout.
2026-05-16 04:13:19 +02:00
Philemon Chiro
d202c1859f Add release workflow with build provenance attestation; use full hex format
- New workflow signs main.js / manifest.json / styles.css with GitHub
  artifact attestation on every tag push, then creates or updates the
  matching release. Going forward, pushing a 'X.Y.Z' tag is enough to
  ship a verified release.
- Expand all '#fff' shorthand to '#ffffff' for hex-format consistency
  flagged by the community directory scanner.
2026-05-16 04:09:43 +02:00
Philemon Chiro
41a64a0fb3 Allow esbuild build script under pnpm
Portal CI installs with pnpm, which blocks postinstall scripts by default
and fails the build verification. Declare esbuild as an allowed builder
so pnpm install completes cleanly.
2026-05-16 04:07:58 +02:00
Philemon Chiro
2acd138de5 Update README hero screenshot: chrome-cropped wall view 2026-05-02 10:06:09 +02:00
Philemon Chiro
9ca88b1f0a Update capture and modal screenshots: chrome-cropped versions 2026-05-02 10:02:27 +02:00
Philemon Chiro
d449b0d09b Update README screenshots: wall hero, expanded capture, colored modal preview
Replaces the earlier grid-density screenshots with the wall view — which is
both the new default density and the visually distinctive feature the plugin
is named for. Adds a capture-expanded screenshot so the README shows the
title + body + pin/color flow at a glance.
2026-05-02 09:55:20 +02:00
Philemon Chiro
83a09fec59 v0.2.2: light/dark theme polish across all surfaces
Single light-theme override block in styles.css covering:
- Cards (border, hover lift), card hover-action buttons, tag chips
- Active filter chip, sort/archive/density toolbar buttons
- Bulk-action floating bar, capture action buttons + Discard button
- Modal action buttons on uncolored notes

New theme-agnostic colored-surface treatment:
- Capture wrap gets has-pick-color when a color is chosen; title,
  body, placeholders, action icons and Discard button all flip
  to white so they remain legible against the dark color palette
- Card hover-action buttons on colored cards now have a dark
  translucent backdrop instead of just floating white icons
- Backlinks badge readability rules for both colored and light states

Wall view:
- New 'theme' wall background that uses Obsidian's
  --background-primary and --background-modifier-border for full
  theme adaptivity; this is the new default
- Light-theme variants for the dark-only walls (slate, blueprint,
  chalkboard, cork) so picking them in light mode doesn't crash
  a dark wall into a light card surface
- Wall card shadows lighter in light mode

Modal preview:
- Inherits the note color: paints the modal background, makes
  inner content transparent, lighter tag chips and code-block
  backgrounds for contrast
- Title, action buttons, and edit-mode textarea all forced to
  light colors when the modal has a note color
- Restored Obsidian's .modal-bg dim backdrop (was being set
  transparent, removing the dim overlay)
- Hidden Obsidian's built-in × close (it overlapped the action row)

Capture box:
- Auto-saves on focus loss with a 200ms grace window so the color
  popup doesn't trigger a premature save
- Title input no longer triggers save on Enter; plain Enter inserts
  a newline; ⌘/Ctrl + Enter saves explicitly
- Discard button next to Save
- Save button styled as mod-cta primary

Lint:
- Discard tooltip lowercased to satisfy ui/sentence-case
- document.activeElement → activeDocument.activeElement for
  popout-window compatibility (obsidianmd/prefer-active-doc)
2026-05-02 09:31:27 +02:00
Philemon Chiro
752dbc0c3c Fix two pre-bot lints: discard tooltip sentence case, activeDocument
- 'Discard (Esc)' → 'Discard (esc)' for the obsidianmd sentence-case rule
- document.activeElement → activeDocument.activeElement in the
  capture's blur handler (popout-window compatibility)
2026-05-02 08:32:30 +02:00
Philemon Chiro
5659633ad8 v0.2.1: capture redesign + colored modal + wall polish
Capture box (Keep parity):
- Title input above body, both visible only when capture is focused
- Discard button next to a primary Save button
- Pin and color toggles in the action row; picking a color tints the
  whole capture box so you preview the sticky color before saving
- Auto-save on focus loss (200ms grace so the color popup menu doesn't
  trigger a premature save)
- Plain Enter inserts a newline; cmd/ctrl-Enter saves
- Title typography: 20px / 500 weight, divider between title and body,
  inputs are flush (no nested borders)
- Capture also auto-adds the new note to the current wall when in
  wall mode

Wall view:
- Pinned cards float to the top in pinOrder
- 3D pushpin head on pinned wall cards (red gradient + drop shadow,
  softer shadow on light backgrounds)
- Removed the floating + add button (redundant with the capture box)
- Removed the wall switcher dropdown; one implicit wall, exposed via
  a 'Clear wall' command in the palette

Modal preview:
- Inherits the note's color: paints the modal background, transparent
  inner panels, lighter tag chips and code-block backgrounds for
  contrast on the dark color palette
- Hidden Obsidian's built-in × close (overlapped with the action row);
  Esc / click-outside / Open-in-tab still close

Bulk actions:
- 40px buttons with 20px icons (was 32/16) for better legibility,
  vertical divider between count and actions

Async/await cleanup:
- onOpen, onClose, render, and the bulk-trash handler no longer
  declare async without an await; require-await passes locally
2026-05-02 08:25:24 +02:00
Philemon Chiro
c3d9269f49 v0.2.0: wall mode and reviewer-bot async-no-await fixes
The bigger half is the new "wall" view: a sticky-note styled,
vertically-scrolled, curated subset of your notes.

- New density modes 'wall' and 'wall-compact' selectable from the
  toolbar. Wall is now the default density on fresh installs.
- Per-card sticky-note look: deterministic 1-3 degree rotation
  seeded by file path, paper-style drop shadow, hover lift to 0deg.
- Eight wall backgrounds (cork, whiteboard, slate, paper, graph,
  blueprint, linen, chalkboard) chosen from the settings tab.
  Default: slate.
- Walls are curated, not auto-filled. The wall starts empty; users
  add notes via the floating + button (FuzzySuggestModal picker)
  or via the empty state's "Fill from current view" shortcut
  (only offered when the current filter has <= 200 notes).
- Right-click any card on the wall: "Remove from wall".
- Command "Clear wall" (palette) wipes the current wall.
- The freeform-canvas prototype was scrapped in favor of the
  column layout after testing showed dragging cards onto a giant
  scattered canvas was unusable at vault scale.

Bot fixes:

- async onClose / async render / async make-trash arrow had no
  awaits. Made onClose and onOpen non-async (return Promise.resolve)
  to match Obsidian's signature; render is now sync; the trash arrow
  is sync too (its body's awaits are inside a ConfirmModal callback).
- Switched view content access from this.containerEl.children[1] to
  this.contentEl. Fixes a tab-switching ghosting bug — newer Obsidian
  versions can wrap views in extra layers, shifting the children
  index, so renders were occasionally landing on the wrong element.
  Per the developer docs, contentEl is the stable getter.
- The wall FAB moved from position: fixed to position: absolute
  inside the body container, so it disappears with its tab instead
  of bleeding across panes.
- Added @typescript-eslint/require-await to the local eslint config
  so the next round of these doesn't slip past.
2026-05-02 06:39:17 +02:00
Philemon Chiro
3ebc6f485a v0.1.2: address Obsidian community-store reviewer bot
Bumps minAppVersion to 1.7.2 (the lowest version where every API the
plugin uses is supported — processFrontMatter and revealLeaf were the
two that pushed this up).

ESLint pass against eslint-plugin-obsidianmd is now clean (0 errors,
0 warnings). Notable changes:

- Removes the deprecated MarkdownRenderer.renderMarkdown fallback;
  always uses MarkdownRenderer.render now (minAppVersion covers it)
- Replaces Workspace.activeLeaf reads with Workspace.getActiveViewOfType
- Replaces Vault.trash with FileManager.trashFile to respect the user's
  configured deletion preference
- Replaces window.confirm() with a small ConfirmModal so the bulk-delete
  prompt is consistent with the rest of the UI
- Dynamic style assignments now use HTMLElement.setCssStyles rather than
  el.style.* directly
- All static modal styling has been moved out of inline styles into CSS
  classes (keep-modal-stack, keep-modal-row, keep-modal-buttons, etc.)
- Async event handlers that returned Promise<void> where the listener
  expects void are now sync wrappers that internally void-await
- Empty catch blocks now have explanatory comments
- Removes 'this' aliasing in openNotePreview (uses arrow function instead)
- Drops unused vars and fixes sentence case in setting descriptions

Adds eslint.config.mjs with the obsidianmd recommended config so future
changes can be lint-checked locally before pushing.
2026-05-01 20:08:14 +02:00
Philemon Chiro
f0e35d868f Add TypeScript source and esbuild build pipeline
main.ts is now the canonical source; main.js is the compiled artifact
committed alongside so manual installs work without a build step. Class
signatures and the public types (KeepCardsSettings, Filter, ParsedQuery,
ColorDef, BatchState) are explicitly typed; tsconfig is lenient on
implicit any and null checks to keep the diff against the hand-authored
JS minimal for this initial port. Subsequent passes can tighten the
types incrementally.

Build: npm install && npm run build (or npm run dev for watch mode).

Addresses the reviewer note in the obsidian-releases PR about needing
the .ts source committed for transparency.
2026-04-30 12:48:00 +02:00
17 changed files with 10200 additions and 960 deletions

50
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,50 @@
name: Release
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
permissions:
contents: write
id-token: write
attestations: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build plugin
run: npm run build
- name: Attest build provenance
uses: actions/attest-build-provenance@v4
with:
subject-path: |
main.js
manifest.json
styles.css
- name: Create or update release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
if gh release view "$TAG" >/dev/null 2>&1; then
gh release upload "$TAG" main.js manifest.json styles.css --clobber
else
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
main.js manifest.json styles.css
fi

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ node_modules/
data.json
.env
.env.local
launch/

50
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,50 @@
# Contributing to Notekeeper
Thanks for considering a contribution. This is a small project and the bar to merge is intentionally low — useful is more important than perfect.
## Project shape
- **`main.ts`** — the entire plugin source, single file by design. Includes the view, modals, settings tab, and helpers.
- **`styles.css`** — every visual style. Light-theme overrides live in a clearly-marked block at the bottom.
- **`manifest.json` / `versions.json`** — the Obsidian plugin manifest and per-version minimum-app-version map.
- **`main.js`** — esbuild output. Committed so manual installs work without a build step. Rebuild it before opening a PR.
## Build and dev
```bash
npm install
npm run dev # watch + rebuild on save
npm run build # type-check + production bundle
```
Local lint (matches the directory's automated scan, modulo the rules disabled in `eslint.config.mjs`):
```bash
npx eslint main.ts
```
## Opening a PR
- Make sure `npm run build` succeeds and `main.js` is up to date in the commit.
- Run `npx eslint main.ts` — should be clean.
- Test the change in a real vault. The `Documents/Obsidian Vault` pattern works, or any vault you don't mind experimenting on; just symlink or copy `main.js`, `manifest.json`, and `styles.css` into `<vault>/.obsidian/plugins/notekeeper/` and reload.
- Keep the diff narrow. If you find adjacent things to clean up, file a separate issue or PR.
## Filing an issue
Open one [on GitHub](https://github.com/PhilemonChiro/obsidian-notekeeper/issues). Helpful to include:
- Obsidian version and platform (desktop/mobile, OS)
- Notekeeper version (from settings)
- A short repro — ideally the smallest sequence of clicks that triggers the behaviour
- A screenshot or short clip if the bug is visual
Feature requests are very welcome. Even one-line ones.
## Releases
Releases ship through `.github/workflows/release.yml` on every `X.Y.Z` tag push. The workflow builds, signs `main.js` / `manifest.json` / `styles.css` with [GitHub build provenance attestation](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations), and either creates the release or uploads to an existing tag.
## Licence
Notekeeper is MIT. Contributions are accepted under the same licence.

View file

@ -1,12 +1,16 @@
# Notekeeper
A Google Keepstyle masonry of cards for your Obsidian vault. Browse, capture, pin, color, archive, and filter your notes from one screen — without leaving the grid.
A Google Keepstyle wall of sticky notes for your Obsidian vault. Browse, capture, pin, color, and curate your notes on a sticky-note wall — or switch to a denser card grid when you need more density.
![Grid view of notes laid out as a masonry of cards, with PINNED and OTHERS sections, varied colors, tags, and inline lists](docs/grid.png)
![Wall view of notes as sticky notes with rotation, color tags, and pinned items at the top](docs/grid.png)
Click any card to open a full markdown-rendered preview with one-click pin / edit / color / archive / open-in-tab actions:
Capture a note with a title, body, optional pin, and color — saved to the wall in one click:
![Note preview modal showing a Python code snippet with syntax highlighting](docs/modal.png)
![Capture box expanded with title, body, pin and color buttons, and a primary Save action](docs/capture.png)
Click any sticky for a full markdown-rendered preview that inherits the note's color:
![Note preview modal in a colored note showing live markdown rendering and inline action buttons](docs/modal.png)
## Features
@ -109,6 +113,20 @@ Open Obsidian → Settings → Community plugins → Browse, search "Notekeeper"
2. Copy them into `<vault>/.obsidian/plugins/notekeeper/`
3. Reload Obsidian and enable Notekeeper in Settings → Community plugins
## Development
Source lives in `main.ts`. The committed `main.js` is what Obsidian loads at runtime; rebuild it with esbuild after editing `main.ts`:
```bash
npm install
npm run build # type-check + bundle to main.js
npm run dev # rebuild on save
```
`main.ts`, `manifest.json`, and `styles.css` are the authored sources. The `main.js` artifact is produced by the build and committed alongside (so manual installs work without a build step).
PRs welcome. The codebase is single-file by design — keep it that way unless the addition is large enough to warrant its own module.
## License
MIT — see [LICENSE](./LICENSE).

BIN
docs/capture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

40
esbuild.config.mjs Normal file
View file

@ -0,0 +1,40 @@
import esbuild from "esbuild";
import process from "process";
import { builtinModules } from "node:module";
const prod = process.argv[2] === "production";
const ctx = await esbuild.context({
entryPoints: ["main.ts"],
bundle: true,
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtinModules,
],
format: "cjs",
target: "es2020",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
minify: false,
});
if (prod) {
await ctx.rebuild();
process.exit(0);
} else {
await ctx.watch();
}

34
eslint.config.mjs Normal file
View file

@ -0,0 +1,34 @@
import obsidianmd from 'eslint-plugin-obsidianmd';
import tsParser from '@typescript-eslint/parser';
const plugin = obsidianmd.default || obsidianmd;
export default [
...plugin.configs.recommended,
{
files: ['main.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
tsconfigRootDir: import.meta.dirname,
},
},
},
{
ignores: ['main.js', 'node_modules/**', 'docs/**', 'launch/**'],
},
{
files: ['main.ts'],
rules: {
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/require-await': 'error',
},
},
];

2100
main.js

File diff suppressed because it is too large Load diff

2746
main.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
{
"id": "notekeeper",
"name": "Notekeeper",
"version": "0.1.1",
"minAppVersion": "1.4.0",
"version": "0.2.5",
"minAppVersion": "1.7.2",
"description": "Browse your vault as a Google Keep-style masonry of cards. Quick capture, pin, color, archive, and filter notes by labels — sticky-note style.",
"author": "Philemon Chiro",
"authorUrl": "https://github.com/PhilemonChiro",

5099
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,25 @@
{
"name": "obsidian-notekeeper",
"version": "0.1.1",
"version": "0.2.5",
"description": "Browse your vault as a Google Keep-style masonry of cards. Quick capture, pin, color, archive, and filter notes by labels.",
"author": "Philemon Chiro",
"license": "MIT",
"private": true,
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "node esbuild.config.mjs production"
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production"
},
"devDependencies": {
"@types/node": "^20",
"builtin-modules": "^3.3.0",
"@typescript-eslint/parser": "^8.59.1",
"esbuild": "^0.21.0",
"eslint": "^9.39.4",
"eslint-plugin-obsidianmd": "^0.2.9",
"obsidian": "latest",
"tslib": "^2.6.0",
"typescript": "^5.4.0"
},
"pnpm": {
"onlyBuiltDependencies": ["esbuild"]
}
}

File diff suppressed because it is too large Load diff

21
tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES2020",
"allowJs": true,
"noImplicitAny": false,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": false,
"lib": ["DOM", "ES2020"],
"esModuleInterop": true,
"skipLibCheck": true,
"downlevelIteration": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "main.js"]
}

View file

@ -1,4 +1,11 @@
{
"0.1.0": "1.4.0",
"0.1.1": "1.4.0"
"0.1.1": "1.4.0",
"0.1.2": "1.7.2",
"0.2.0": "1.7.2",
"0.2.1": "1.7.2",
"0.2.2": "1.7.2",
"0.2.3": "1.7.2",
"0.2.4": "1.7.2",
"0.2.5": "1.7.2"
}