170 lines
5.2 KiB
Markdown
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
|
|
```
|