Files
plainleaf/libraries/Library/Std/Journal/Journal.md
T

170 lines
5.2 KiB
Markdown

#meta
This page implements the built-in daily journal feature: four commands (`Journal: Today`, `Journal: Previous Day`, `Journal: Next Day`, `Journal: Picker`) and a default template at [[^Library/Std/Journal/Template]].
# Configuration
The journal feature can be configured via the `journal` config key:
* `journal.enabled` — set to `false` to disable all journal commands.
* `journal.template` — page name to use as the template (defaults to `Library/Std/Journal/Template`).
* `journal.prefix` — page-name prefix for new journal entries (defaults to `Journal/`). Must end with a `/` if you want entries grouped under a folder.
* `journal.tag` — tag used to mark journal pages (defaults to `journal`). The template, Prev/Next commands, and the default index page all key off this tag.
# Configuration
The schema, helpers, and command definitions live in two fenced blocks. The first (`priority: 10`) registers the config schema and defines helpers attached to the `journal` namespace. The second (`priority: -1`) runs after user CONFIG has loaded, so `config.get("journal.enabled")` reflects the user's override.
```space-lua
-- priority: 10
journal = journal or {}
config.defineCategory {
name = "Journal",
description = "Configure the built-in daily journal feature.",
priority = 15,
}
config.define("journal", {
description = "Configure the built-in journal feature",
type = "object",
properties = {
enabled = {
type = "boolean",
default = true,
description = "Enable the built-in Journal commands",
ui = { category = "Journal", label = "Enable journal", priority = 4 },
},
template = {
type = "string",
default = "Library/Std/Journal/Template",
description = "Page name to use as the template for new journal entries",
ui = { category = "Journal", label = "Journal template page", priority = 3 },
},
prefix = {
type = "string",
default = "Journal/",
description = "Page-name prefix for new journal entries (e.g. 'Journal/' yields 'Journal/2026-05-12'). Must end with '/' to group under a folder.",
ui = { category = "Journal", label = "Journal page prefix", priority = 2 },
},
tag = {
type = "string",
default = "journal",
description = "Tag used to mark journal pages. Prev/Next and the index-page section both key off this tag.",
ui = { category = "Journal", label = "Journal tag", priority = 1 },
},
},
additionalProperties = false,
})
```
# API
```space-lua
-- priority: 10
function journal.openOrCreate(dateStr)
local pageName = config.get("journal.prefix") .. dateStr
if space.pageExists(pageName) then
editor.navigate(pageName)
return
end
local templatePage = config.get("journal.template")
template.createPageFromTemplate(templatePage, pageName, true)
end
function journal.entries()
return query[[
from j = index.pages(config.get("journal.tag"))
order by j.date desc
]]
end
function journal.neighbor(direction)
local entries = journal.entries()
if #entries == 0 then return nil end
local currentPage = editor.getCurrentPage()
local pivot = date.today()
for _, e in ipairs(entries) do
if e.name == currentPage and e.date then
pivot = e.date
break
end
end
if direction == "previous" then
for _, e in ipairs(entries) do
if e.date and e.date < pivot then
return e
end
end
else
local result
for _, e in ipairs(entries) do
if e.date and e.date > pivot then
result = e
end
end
return result
end
return nil
end
```
# Commands
```space-lua
-- priority: -1
if config.get("journal.enabled", true) then
-- using command.update here (instead of command.define) to support key binding overrides (executed before)
command.update {
name = "Journal: Today",
key = "Ctrl-q j",
run = function()
journal.openOrCreate(date.today())
end,
}
command.update {
name = "Journal: Previous Day",
key = "Ctrl-q p",
run = function()
local entry = journal.neighbor("previous")
if entry then
editor.navigate(entry.name)
else
editor.flashNotification("No earlier journal entries")
end
end,
}
command.update {
name = "Journal: Next Day",
key = "Ctrl-q n",
run = function()
local entry = journal.neighbor("next")
if entry then
editor.navigate(entry.name)
else
editor.flashNotification("No later journal entries")
end
end,
}
command.update {
name = "Journal: Picker",
run = function()
local entries = journal.entries()
if #entries == 0 then
editor.flashNotification("No journal entries yet")
return
end
local prefix = config.get("journal.prefix")
local items = {}
for _, e in ipairs(entries) do
local label = e.name
if prefix ~= "" and label:startsWith(prefix) then
label = label:sub(#prefix + 1)
end
table.insert(items, { name = label, fullName = e.name })
end
local selected = editor.filterBox("Journal entry", items, "Pick a journal entry to open")
if not selected then return end
editor.navigate(selected.fullName)
end,
}
end
```