Skip to content

Commit 24b807f

Browse files
authored
Merge pull request #143 from posit-dev/feat-h-rule-shortcode
feat: horizontal rule shortcode
2 parents 0f1198c + 5f8f825 commit 24b807f

10 files changed

Lines changed: 1894 additions & 0 deletions

File tree

great-docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ nav_icons:
264264
Color Swatches: pipette
265265
Table Previews: table
266266
Table Explorer: telescope
267+
Horizontal Rules: minus
267268

268269
# Author Information
269270
# ------------------
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
title: Horizontal Rule
2+
author: Great Docs
3+
version: 1.0.0
4+
quarto-required: ">=1.3.0"
5+
contributes:
6+
shortcodes:
7+
- hr.lua
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
-- hr.lua — Quarto shortcode for decorative horizontal rules
2+
--
3+
-- Usage in .qmd files:
4+
--
5+
-- {{< hr >}}
6+
-- {{< hr style="dashed" color="sky" >}}
7+
-- {{< hr style="dotted" thickness="3px" width="50%" align="center" >}}
8+
-- {{< hr text="§" >}}
9+
-- {{< hr text="Continue Reading" style="solid" color="#6366f1" >}}
10+
-- {{< hr preset="gradient-shimmer" >}}
11+
-- {{< hr preset="fade" width="60%" >}}
12+
--
13+
-- Pure Lua implementation — no Python helper needed.
14+
-- All styling is handled via CSS classes in great-docs.scss.
15+
16+
local function kwarg_str(kwargs, key)
17+
local raw = kwargs[key]
18+
if raw == nil then return "" end
19+
local s = pandoc.utils.stringify(raw)
20+
return s or ""
21+
end
22+
23+
-- Named palette colors that map to CSS custom properties
24+
local PALETTE_COLORS = {
25+
sky = true,
26+
peach = true,
27+
prism = true,
28+
lilac = true,
29+
slate = true,
30+
honey = true,
31+
dusk = true,
32+
mint = true,
33+
accent = true,
34+
}
35+
36+
-- Valid presets
37+
local PRESETS = {
38+
["gradient-shimmer"] = true,
39+
["gradient-static"] = true,
40+
["fade"] = true,
41+
["fade-edges"] = true,
42+
["dots"] = true,
43+
["diamond"] = true,
44+
["ornament"] = true,
45+
["wave"] = true,
46+
["double-line"] = true,
47+
}
48+
49+
-- Valid line styles
50+
local STYLES = {
51+
solid = true, dotted = true, dashed = true, double = true,
52+
}
53+
54+
-- Named thickness values
55+
local THICKNESS_MAP = {
56+
thin = "1px",
57+
medium = "2px",
58+
thick = "4px",
59+
}
60+
61+
-- Named spacing values
62+
local SPACING_MAP = {
63+
compact = "1rem",
64+
normal = "2rem",
65+
spacious = "4rem",
66+
}
67+
68+
return {
69+
["hr"] = function(args, kwargs)
70+
local preset = kwarg_str(kwargs, "preset")
71+
local style = kwarg_str(kwargs, "style")
72+
local color = kwarg_str(kwargs, "color")
73+
local thickness = kwarg_str(kwargs, "thickness")
74+
local width = kwarg_str(kwargs, "width")
75+
local align = kwarg_str(kwargs, "align")
76+
local text = kwarg_str(kwargs, "text")
77+
local text_color = kwarg_str(kwargs, "text-color")
78+
local text_size = kwarg_str(kwargs, "text-size")
79+
local spacing = kwarg_str(kwargs, "spacing")
80+
81+
-- Build CSS classes
82+
local classes = { "gd-hr" }
83+
84+
if preset ~= "" and PRESETS[preset] then
85+
table.insert(classes, "gd-hr--" .. preset)
86+
end
87+
88+
if style ~= "" and STYLES[style] then
89+
table.insert(classes, "gd-hr--" .. style)
90+
end
91+
92+
if align == "left" then
93+
table.insert(classes, "gd-hr--left")
94+
elseif align == "right" then
95+
table.insert(classes, "gd-hr--right")
96+
end
97+
98+
-- Build inline styles for dynamic values
99+
local inline_styles = {}
100+
101+
-- Color: palette name → CSS var, otherwise raw CSS color
102+
if color ~= "" then
103+
if PALETTE_COLORS[color] then
104+
table.insert(inline_styles,
105+
"--gd-hr-color: var(--gd-palette-" .. color .. ", var(--gd-accent, #6366f1))")
106+
else
107+
table.insert(inline_styles, "--gd-hr-color: " .. color)
108+
end
109+
end
110+
111+
-- Thickness
112+
if thickness ~= "" then
113+
local resolved = THICKNESS_MAP[thickness] or thickness
114+
table.insert(inline_styles, "--gd-hr-thickness: " .. resolved)
115+
end
116+
117+
-- Width
118+
if width ~= "" then
119+
if width == "full" then
120+
width = "100%"
121+
end
122+
table.insert(inline_styles, "--gd-hr-width: " .. width)
123+
end
124+
125+
-- Spacing
126+
if spacing ~= "" then
127+
local resolved = SPACING_MAP[spacing] or spacing
128+
table.insert(inline_styles, "--gd-hr-spacing: " .. resolved)
129+
end
130+
131+
local style_attr = ""
132+
if #inline_styles > 0 then
133+
style_attr = ' style="' .. table.concat(inline_styles, "; ") .. '"'
134+
end
135+
136+
local class_attr = table.concat(classes, " ")
137+
138+
-- If there's embedded text, use the flex wrapper structure
139+
if text ~= "" then
140+
local text_classes = { "gd-hr-text" }
141+
if text_size == "sm" then
142+
table.insert(text_classes, "gd-hr-text--sm")
143+
elseif text_size == "lg" then
144+
table.insert(text_classes, "gd-hr-text--lg")
145+
end
146+
147+
local text_style = ""
148+
if text_color ~= "" then
149+
text_style = ' style="color: ' .. text_color .. '"'
150+
end
151+
152+
local html = '<div class="' .. class_attr .. ' gd-hr--with-text"' .. style_attr .. '>'
153+
.. '<span class="gd-hr-line"></span>'
154+
.. '<span class="' .. table.concat(text_classes, " ") .. '"' .. text_style .. '>'
155+
.. text
156+
.. '</span>'
157+
.. '<span class="gd-hr-line"></span>'
158+
.. '</div>'
159+
160+
return pandoc.RawBlock("html", html)
161+
end
162+
163+
-- Simple <hr> element
164+
local html = '<hr class="' .. class_attr .. '"' .. style_attr .. '>'
165+
return pandoc.RawBlock("html", html)
166+
end,
167+
}

0 commit comments

Comments
 (0)