I agree and also wanted to share some of my changes to this journaling marvel.
By the way, my experience with Lua started same day I installed SB. So, not sure about my code quality! Also sorry for this long post.
Here a summary and then the details:
- At the frontmatter, I prefer to save the related values as part of specific "YAML" section (instead of beeing at the "root" level). This required a way to update the frontmatter.
- Ids, icons and descriptions from variables (lua tables).
- Functions for table visualization with colors and icons.
- Changes to the initial CBT library provided by thepaperpilot.
Now the details:
1. Update a FrontMatter Section:
As a section (instead of "root" level), is easy for me to query all values at once and also avoid the issues with repeated values several times in the frontmatter's Cognitive Distortion Section.
After diging the yaml test code, I found two basic frontmatter operations ("set-key" and "delete-key"). So, I created a function with the combined two level operations (delete + insert):
function updFrontmatterSection(path, value)
--path: Frontmatter "root" section name
--value: Value: The section values. Can be an array/list/dictionary/nested array of arrays and so on
local fminfo = index.extractFrontmatter(editor.getText())
local fmtable = fminfo.frontmatter and fminfo.frontmatter[path]
if not fmtable then
fmtable = { }
end
if fmtable[value] then
--print(value .. " found...removing")
fmtable[value] = false
else
--print(value .." not found...adding")
fmtable[value] = true
end
local updated = index.patchFrontmatter(editor.getText(),
{ { op="delete-key", path=path }, })
editor.setText(updated)
local updated = index.patchFrontmatter(editor.getText(),
{ { op="set-key", path=path, value=fmtable }, })
editor.setText(updated)
editor.rebuildEditorState()
end
2. Values from variables
Note: I started as simple lua table, then as arrays/dicts/nested tables.
creature_icons = {daughter="🧚♀️", wife="🏃♀️", pets="🐾", baby="👶🏻", someoneelse="👤"}
cbt_feeling_icons = { [1]="🙁", [2]="☹️", [3]="😐", [4]="🙂", [5]="😀"}
cbt_feeling_colors = { [1]="red", [2]="orange", [3]="yellow", [4]="green", [5]="purple"}
cbt_sensitivities_icons = {sleep="😴", exercise="🏋🏻♂️", bed="🛏️", headache="🤕", medication="💊", food="🍜", coffee="☕", music="🔊", phone="📱", reading="📖", laptop="👨💻", money="💵", toughts="🧠", vomit="🤮"}
suds_thermometer = {
level_100 = {value=100, color_hex="#ff032d", color_rbg="rgba(255, 3, 45)", color_hsl="hsl(350, 100, 51)", icon = "", desc="100 Highest anxiety/distress that you have ever felt.", short_desc="100 Highest a/d."},
level_90 = {value=90, color_hex="#ff032d", color_rbg="rgba(255, 3, 45)", color_hsl="hsl(350, 100, 51)", icon = "", desc=" 90 Extremely anxious/distressed.", short_desc="90 Extremely a/d."},
--...and so on
}
-- desc value of each cbt_cdistortions refers to another variable. This is only for easy code-reading because the long description of the distortion
cbt_cdistortions = {
filtering = {name="Filtering", icon = "⤵️", desc=filtering_desc},
discounting_positive= {name="Discounting the positive", icon = "😒", desc=discounting_positive_desc},
polarization= {name="Polarization or all-or-nothing thinking", icon = "3", desc=polarization_desc},
overgeneralization= {name="Overgeneralization", icon = "4", desc=overgeneralization_desc},
jumping2conclusions= {name="Jumping to conclusions", icon = "5", desc=jumping2conclusions_desc},
catastrophizing= {name="Catastrophizing", icon = "6", desc=catastrophizing_desc},
personalization= {name="Personalization", icon = "7", desc=personalization_desc},
fallacies= {name="Fallacies", icon = "8", desc=fallacies_desc},
blame= {name="Blame", icon = "9", desc=blame_desc},
should_statements= {name="Should statements", icon = "10", desc=should_statements_desc},
emotional_reasoning= {name="Emotional reasoning", icon = "11", desc=emotional_reasoning_desc},
global_labeling= {name="Global labeling", icon = "12", desc=global_labeling_desc},
always_being_right= {name="Always being right", icon = "13", desc=always_being_right_desc},
}
--And here the loooong descriptions
filtering_desc=[[Mental filtering is draining and straining all positives in a situation and, instead, dwelling on its negatives.
Even if there are more positive aspects than negative in a situation or person, you focus on the negatives exclusively.
For example, focusing on a minor suggestion for improvement after receiving many compliments during a performance review at work may affect your mood negativeldiscounting_positivey.]]
discounting_positive_desc=[[Discounting positives is similar to mental filtering. The main difference is that you dismiss it as something of no value when you do think of positive aspects.
For example, if someone compliments the way you look today, you may think they’re just being nice.]]
--and so on
3. Fuctions
function renderIcons(iconsTable, values)
--more generic than other rendering functions
local icons = ""
for k, v in pairs(values) do
if v and iconsTable[k] then
print(iconsTable[v])
icons = icons .. iconsTable[k]
end
end
return icons
end
function renderCBTSensitivities(table)
local icons = ""
for k, v in pairs(table) do
if v and cbt_sensitivities_icons[k] then
icons = icons .. cbt_sensitivities_icons[k]
end
end
return icons
end
function renderCBTFeeling(feeling)
if feeling and cbt_feeling_icons[feeling] then
return cbt_feeling_icons[feeling] .. ":" .. feeling
else
return "❓" .. (feeling and ":" .. feeling or "")
end
end
function getCBTCdistortion(distortion)
if distortion then
return(cbt_cdistortions[distortion])
end
end
function getSUDSThermometerLevel(value)
local temp_level = "no_value"
if value and type(value) == "number" then
if value < 9 then
temp_level = "level_0"
elseif value <= 19 then
temp_level = "level_10"
elseif value <= 29 then
temp_level = "level_20"
elseif value <= 39 then
temp_level = "level_30"
elseif value <= 49 then
temp_level = "level_40"
elseif value <= 59 then
temp_level = "level_50"
elseif value <= 69 then
temp_level = "level_60"
elseif value <= 79 then
temp_level = "level_70"
elseif value <= 89 then
temp_level = "level_80"
elseif value <= 99 then
temp_level = "level_90"
elseif value >= 100 then
temp_level = "level_100"
end
end
return temp_level
end
function getSUDSThermometer(value)
local temp_value = getSUDSThermometerLevel(value)
--if not value then value = 20 end
local wd = {}
wd = widget.htmlBlock(dom.div {
style = 'display: inline-block;width: fit-content;background-color:' .. suds_thermometer[temp_value].color_hex .. ' ;margin:10px 0;"',
dom.text {
style = "color:#7607a7",
suds_thermometer[temp_value].desc
}
})
return wd
end
4 Changes to the CBT Lib
- Library/thepaperpilot/CBT-Journal/Tracker Section
-- priority: 10
function cbt_journal.tracker_section(section, trackers)
local buttons = {}
local fminfo = index.extractFrontmatter(editor.getText())
function add_button(text, value)
local fmsection = fminfo.frontmatter and fminfo.frontmatter[section]
local current = false
if not fmsection then
print("section not found")
fmsection = { }
else
current = fmsection[value]
end
table.insert(buttons, dom.button {
style = "margin-right: 0.5em; padding: .2em; font-size: 200%;" .. (current and "background-color: var(--editor-highlight-background-color)" or ""),
onclick = function()
updFrontmatterSection(section, value)
end,
text
})
end
for key, text in pairs(trackers) do
add_button(text, key)
end
return widget.html(dom.div(buttons))
end
slashcommand.define {
name = "Tracker Section",
run = function()
editor.insertAtCursor("${cbt_journal.tracker_section({\n \n})}\n", false, true)
editor.moveCursor(editor.getCursor() - 5)
end
}
Previuos change will allow something like: ${cbt_journal.tracker_section("sensitivities", cbt_sensitivities_icons)} to show the icons/buttons and save the frontmatter as:
sensitivities:
hydration: false
reading: false
brush_teeth: false
sleep: true
exercise: true
bed: true
headache: true
- Library/thepaperpilot/CBT-Journal/Cognitive Distortions Section
I like this one.
-- priority: 10
function cbt_journal.cognitive_distortions_section()
local section = "cognitiveDistortions"
local options = {}
local fminfo = index.extractFrontmatter(editor.getText())
local expanded = fminfo.frontmatter and fminfo.frontmatter.cognitiveDistortionsExpanded
local fmsection = fminfo.frontmatter and fminfo.frontmatter[section] or {}
local count = 0
for k, v in pairs(fmsection) do
if v then
count = count + 1
end
end
function add_options()
for k, v in pairs(cbt_cdistortions) do
add_option(k, cbt_cdistortions[k].name, cbt_cdistortions[k].desc)
end
end
function add_option(value, name, description)
local current = false
if fmsection and fmsection[value] then
--print("section found:")
current = fmsection[value]
else
--print(value .. " not found on fmsection")
end
if expanded then
--print(name)
table.insert(options, dom.button {
--style = "padding: .5em; text-align: left;",
style = "padding: .5em; text-align: left;" .. (current and "background-color: var(--editor-highlight-background-color);" or ""),
onclick = function()
print("Update")
updFrontmatterSection(section, value)
end,
widget.html(markdown.markdownToHtml("## " .. name .. "\n\n" .. description))
})
elseif current then
table.insert(options, dom.li {
name
})
end
end
add_options()
if not expanded then
if count > 0 then
table.insert(options, dom.button {
style = "padding: .5em",
onclick = function()
local updated = index.patchFrontmatter(editor.getText(),
{
{ op="set-key", path="cognitiveDistortionsExpanded", value=true },
})
editor.setText(updated)
editor.rebuildEditorState()
end,
"Edit"
})
else
return widget.html(dom.button {
style = "padding: .5em",
onclick = function()
local updated = index.patchFrontmatter(editor.getText(),
{
{ op="set-key", path="cognitiveDistortionsExpanded", value=true },
})
editor.setText(updated)
editor.rebuildEditorState()
end,
"Experience any cognitive distortions today?"
})
end
else
table.insert(options, dom.button {
style = "padding: .5em",
onclick = function()
local updated = index.patchFrontmatter(editor.getText(),
{
{ op="set-key", path="cognitiveDistortionsExpanded", value=false },
})
editor.setText(updated)
editor.rebuildEditorState()
end,
"Done editing"
})
end
return widget.html(dom.div {
style = "display: flex; flex-flow: column; gap: .5em",
table.unpack(options)
})
end
slashcommand.define {
name = "Cognitive Distortions Section",
run = function()
editor.insertAtCursor("${cbt_journal.cognitive_distortions_section()}\n", false, true)
end
}
the frontmatter will be similar to:
cognitiveDistortionsExpanded: false
cognitiveDistortions:
filtering: true
discounting_positive: true
- Library/thepaperpilot/CBT-Journal/Check-Ins Section
Goal: Improve the table rendering from the yaml sections (instead of the root) and produce something like
-- priority: 10
function cbt_journal.checkins_section(prefix)
return query[[
from index.tag "page"
where _.name:startsWith(prefix)
select {
["check-in"] = "[[" .. _.name .. "|" .. _.name:gsub("^" .. prefix, "") .. "]]",
temperature=_.temperature,
feeling=renderCBTFeeling(_.feeling),
who=renderCreatures(_.who),
sensitivities=renderCBTSensitivities(_.sensitivities),
}
order by created desc
]];
end
slashcommand.define {
name = "Check-Ins Section",
run = function()
editor.insertAtCursor("${cbt_journal.checkins_section()}\n", false, true)
end
}
All parts are moving on my space! I think for now is better to share as reply to this post instead a PR to the library.
