Sharing a “Recent Journal Entries” feature to display the latest 30 journal pages existing under Journal/<ISO date>.md (eg: Journal/2026-01-18.md). “Latest” here means sorted alphabetically by page name, which is an ISO date.
This is helpful if you want to take a quick look at the last 30 journal entries by scrolling on a single page without having to click or navigate.
-- priority: 10
virtualPage.define {
pattern = "Recent Journal Entries",
run = function()
local text = "# Recent Journal Entries - Last 30\n\n"
-- Query for Journal pages with date pattern, sorted by name (newest first)
local journalPages = query[[
from index.tag "page"
where name:startsWith("Journal/") and name:match("Journal/(%d%d%d%d%-%d%d%-%d%d)")
order by name desc
limit 30
]]
if #journalPages == 0 then
text = text .. "No journal entries found.\n"
else
for _, page in ipairs(journalPages) do
text = text .. "## [[" .. page.name .. "]]\n\n"
-- Read and include page content
local content = space.readPage(page.name)
if content then
text = text .. content .. "\n\n---\n\n"
end
end
end
return text
end
}
command.define {
name = "Navigate: Recent Journal Entries",
run = function()
editor.navigate("Recent Journal Entries")
end
}
Q: is it possible to get virtual pages to show up when using the Page Picker? It works fine if I type out the whole page, but won’t autocomplete nor is listed.
Probably the most common use case of a virtual page is in combination with a page name patterns (e.g. to support tag:*), in which case you can’t really show it in a page picker, because what should be shown there. However in the (probably) rare case where there’s no regex pattern there, I think it can indeed be included in the page picker as well somehow (see github issue).
By the way: why implement this as a virtual page as opposed to putting this in a global space lua function (for instance named widgets.latestJournals) and simply invoking it in a regular page? ${widgets.latestJournals()}
Then the page will of course also appear in the page picker.
Ah right, yeah you do always get the Live Preview's rendering of the page/widget this way, no way around that, which is not 100% consistent in the way it's rendered compared to the in-editor rendering.