5.2 KiB
5.2 KiB
#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 tofalseto disable all journal commands.journal.template— page name to use as the template (defaults toLibrary/Std/Journal/Template).journal.prefix— page-name prefix for new journal entries (defaults toJournal/). Must end with a/if you want entries grouped under a folder.journal.tag— tag used to mark journal pages (defaults tojournal). 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.
-- 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
-- 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
-- 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