Skip to content

Commit 20aea90

Browse files
typst logo partial
moves the logo declaration to a new partial the lua filter fills the logo object in the pandoc metadata declares new brand-logo and brand-logo-images dictionaries in Typst header
1 parent 2f24776 commit 20aea90

6 files changed

Lines changed: 123 additions & 85 deletions

File tree

src/format/typst/format-typst.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function typstFormat(): Format {
9292
partials: [
9393
"definitions.typ",
9494
"typst-template.typ",
95+
"logo.typ",
9596
"typst-show.typ",
9697
"notes.typ",
9798
"biblio.typ",

src/resources/filters/quarto-post/typst-brand-yaml.lua

Lines changed: 113 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,33 @@ function render_typst_brand_yaml()
9696
local decl = '#let brand-color-background = ' .. to_typst_dict_indent(themebk)
9797
quarto.doc.include_text('in-header', decl)
9898
end
99+
if brand.processedData.logo and next(brand.processedData.logo) then
100+
local logo = brand.processedData.logo
101+
if logo.images then
102+
local declImage = {}
103+
for name, image in pairs(logo.images) do
104+
declImage[name] = {
105+
path = quote_string(image.path),
106+
alt = quote_string(image.alt),
107+
}
108+
end
109+
if next(declImage) then
110+
quarto.doc.include_text('in-header', '#let brand-logo-images = ' .. to_typst_dict_indent(declImage))
111+
end
112+
end
113+
local declLogo = {}
114+
for _, size in pairs({'small', 'medium', 'large'}) do
115+
if logo[size] then
116+
declLogo[size] = {
117+
path = quote_string(logo[size].path),
118+
alt = quote_string(logo[size].alt),
119+
}
120+
end
121+
end
122+
if next(declLogo) then
123+
quarto.doc.include_text('in-header', '#let brand-logo = ' .. to_typst_dict_indent(declLogo))
124+
end
125+
end
99126
local function conditional_entry(key, value, quote_strings)
100127
if quote_strings == null then quote_strings = true end
101128
if not value then return '' end
@@ -212,102 +239,103 @@ function render_typst_brand_yaml()
212239
', content)'
213240
}))
214241
end
215-
216-
-- logo
217-
local logo = param('logo')
218-
local logoOptions = {}
219-
local foundLogo = null
220-
if logo then
221-
if type(logo) == 'string' then
222-
foundLogo = _quarto.modules.brand.get_logo(brandMode, logo) or {path=logo}
223-
elseif type(logo) == 'table' then
224-
for k, v in pairs(logo) do
225-
logoOptions[k] = v
226-
end
227-
if logo.path then
228-
foundLogo = _quarto.modules.brand.get_logo(brandMode, logo.path) or {path=logo}
229-
end
242+
end
243+
end,
244+
Meta = function(meta)
245+
local brand = param('brand')
246+
local brandMode = param('brand-mode') or 'light'
247+
brand = brand and brand[brandMode]
248+
-- it can contain the path but we want to store an object here
249+
if not meta.brand or pandoc.utils.type(meta.brand) == 'Inlines' then
250+
meta.brand = {}
251+
end
252+
-- logo
253+
local logo = param('logo')
254+
local logoOptions = {}
255+
local foundLogo = null
256+
if logo then
257+
if type(logo) == 'string' then
258+
foundLogo = _quarto.modules.brand.get_logo(brandMode, logo) or {path=logo}
259+
elseif type(logo) == 'table' then
260+
for k, v in pairs(logo) do
261+
logoOptions[k] = v
262+
end
263+
if logo.path then
264+
foundLogo = _quarto.modules.brand.get_logo(brandMode, logo.path) or {path=logo}
230265
end
231266
end
232-
if not foundLogo and brand.processedData.logo then
233-
local tries = {'large', 'small', 'medium'} -- low to high priority
234-
foundLogo = _quarto.modules.brand.get_logo(brandMode, 'medium')
235-
or _quarto.modules.brand.get_logo(brandMode, 'small')
236-
or _quarto.modules.brand.get_logo(brandMode, 'large')
237-
end
238-
if foundLogo then
239-
logoOptions.path = foundLogo.path
240-
logoOptions.alt = foundLogo.alt
267+
end
268+
if not foundLogo and brand and brand.processedData and brand.processedData.logo then
269+
foundLogo = _quarto.modules.brand.get_logo(brandMode, 'medium')
270+
or _quarto.modules.brand.get_logo(brandMode, 'small')
271+
or _quarto.modules.brand.get_logo(brandMode, 'large')
272+
end
273+
if foundLogo then
274+
logoOptions.path = foundLogo.path
275+
logoOptions.alt = foundLogo.alt
241276

242-
local pads = {}
243-
for k, v in _quarto.utils.table.sortedPairs(logoOptions) do
244-
if k == 'padding' then
245-
local widths = {}
246-
_quarto.modules.typst.css.parse_multiple(v, 5, function(s, start)
247-
local width, newstart = _quarto.modules.typst.css.consume_width(s, start)
248-
table.insert(widths, width)
249-
return newstart
250-
end)
251-
local sides = _quarto.modules.typst.css.expand_side_shorthand(
252-
widths,
253-
'widths in padding list: ' .. v)
254-
pads.top = sides.top
255-
pads.right = sides.right
256-
pads.bottom = sides.bottom
257-
pads.left = sides.left
258-
elseif k:find '^padding-' then
259-
local _, ndash = k:gsub('-', '')
260-
if ndash == 1 then
261-
local side = k:match('^padding--(%a+)')
262-
local padding_sides = {'left', 'top', 'right', 'bottom'}
263-
if tcontains(padding_sides, side) then
264-
pads[side] = _quarto.modules.typst.css.translate_length(v)
265-
else
266-
quarto.log.warning('invalid padding key ' .. k)
267-
end
277+
local pads = {}
278+
for k, v in _quarto.utils.table.sortedPairs(logoOptions) do
279+
if k == 'padding' then
280+
local widths = {}
281+
_quarto.modules.typst.css.parse_multiple(v, 5, function(s, start)
282+
local width, newstart = _quarto.modules.typst.css.consume_width(s, start)
283+
table.insert(widths, width)
284+
return newstart
285+
end)
286+
local sides = _quarto.modules.typst.css.expand_side_shorthand(
287+
widths,
288+
'widths in padding list: ' .. v)
289+
pads.top = sides.top
290+
pads.right = sides.right
291+
pads.bottom = sides.bottom
292+
pads.left = sides.left
293+
elseif k:find '^padding-' then
294+
local _, ndash = k:gsub('-', '')
295+
if ndash == 1 then
296+
local side = k:match('^padding--(%a+)')
297+
local padding_sides = {'left', 'top', 'right', 'bottom'}
298+
if tcontains(padding_sides, side) then
299+
pads[side] = _quarto.modules.typst.css.translate_length(v)
268300
else
269301
quarto.log.warning('invalid padding key ' .. k)
270302
end
271-
end
272-
end
273-
local inset = nil
274-
if next(pads) then
275-
if pads.top == pads.right and
276-
pads.right == pads.bottom and
277-
pads.bottom == pads.left
278-
then
279-
inset = pads.top
280-
elseif pads.top == pads.bottom and pads.left == pads.right then
281-
inset = _quarto.modules.typst.as_typst_dictionary({x = pads.left, y = pads.top})
282303
else
283-
inset = _quarto.modules.typst.as_typst_dictionary(pads)
304+
quarto.log.warning('invalid padding key ' .. k)
284305
end
285-
else
286-
inset = '0.75in'
287306
end
288-
logoOptions.width = _quarto.modules.typst.css.translate_length(logoOptions.width or '1.5in')
289-
logoOptions.location = logoOptions.location and
290-
location_to_typst_align(logoOptions.location) or 'left+top'
291-
quarto.log.debug('logo options', logoOptions)
292-
local altProp = logoOptions.alt and (', alt: "' .. logoOptions.alt .. '"') or ''
293-
local imageFilename = logoOptions.path
294-
if _quarto.modules.mediabag.should_mediabag(imageFilename) then
295-
imageFilename = _quarto.modules.mediabag.resolved_url_cache[logoOptions.path] or _quarto.modules.mediabag.fetch_and_store_image(logoOptions.path)
296-
imageFilename = _quarto.modules.mediabag.write_mediabag_entry(imageFilename) or imageFilename
307+
end
308+
local inset = nil
309+
if next(pads) then
310+
if pads.top == pads.right and
311+
pads.right == pads.bottom and
312+
pads.bottom == pads.left
313+
then
314+
inset = pads.top
315+
elseif pads.top == pads.bottom and pads.left == pads.right then
316+
inset = _quarto.modules.typst.as_typst_dictionary({x = pads.left, y = pads.top})
297317
else
298-
-- backslashes need to be doubled for Windows
299-
imageFilename = string.gsub(imageFilename, '\\', '\\\\')
318+
inset = _quarto.modules.typst.as_typst_dictionary(pads)
300319
end
301-
quarto.doc.include_text('in-header',
302-
'#set page(background: align(' .. logoOptions.location .. ', box(inset: ' .. inset .. ', image("' .. imageFilename .. '", width: ' .. logoOptions.width .. altProp .. '))))')
303-
end
304-
end
305-
end,
306-
Meta = function(meta)
307-
local brandMode = param('brand-mode') or 'light'
308-
-- it can contain the path but we want to store an object here
309-
if not meta.brand or pandoc.utils.type(meta.brand) == 'Inlines' then
310-
meta.brand = {}
320+
else
321+
inset = '0.75in'
322+
end
323+
logoOptions.width = _quarto.modules.typst.css.translate_length(logoOptions.width or '1.5in')
324+
logoOptions.inset = inset
325+
logoOptions.location = logoOptions.location and
326+
location_to_typst_align(logoOptions.location) or 'left+top'
327+
quarto.log.debug('logo options', logoOptions)
328+
local imageFilename = logoOptions.path
329+
if _quarto.modules.mediabag.should_mediabag(imageFilename) then
330+
imageFilename = _quarto.modules.mediabag.resolved_url_cache[logoOptions.path] or _quarto.modules.mediabag.fetch_and_store_image(logoOptions.path)
331+
imageFilename = _quarto.modules.mediabag.write_mediabag_entry(imageFilename) or imageFilename
332+
imageFilename = imageFilename and imageFilename:gsub('\\_', '_')
333+
else
334+
-- backslashes need to be doubled for Windows
335+
imageFilename = string.gsub(imageFilename, '\\', '\\\\')
336+
end
337+
logoOptions.path = pandoc.RawInline('typst', imageFilename)
338+
meta.logo = logoOptions
311339
end
312340
meta.brand.typography = meta.brand.typography or {}
313341
local base = _quarto.modules.brand.get_typography(brandMode, 'base')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
$if(logo)$
2+
#set page(background: align($logo.location$, box(inset: $logo.inset$, image("$logo.path$", width: $logo.width$$if(logo.alt)$, alt: "$logo.alt$"$endif$))))
3+
$endif$

src/resources/formats/typst/pandoc/quarto/template.typ

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ $for(header-includes)$
66
$header-includes$
77
$endfor$
88

9+
$logo.typ()$
10+
911
$typst-show.typ()$
1012

1113
$for(include-before)$

tests/docs/smoke-all/typst/brand-yaml/logo/posit/brand-logo.qmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ _quarto:
99
typst:
1010
ensureTypstFileRegexMatches:
1111
-
12+
- '#let brand-logo-images = \(\s*brand-typst-with-good-padding: \(\s*path: "good-padding\.png"\s*\),\s*posit-logo-light-medium: \(\s*alt: "Posit Logo",\s*path: "posit-logo-2024.svg"\s*\)'
13+
- '#let brand-logo = \(\s*medium: \(\s*alt: "Posit Logo",\s*path: "posit-logo-2024\.svg"\s*\)\s*\)'
1214
- '#set page\(background: align\(left\+top, box\(inset: 0.75in, image\("posit-logo-2024.svg", width: 1.5in, alt: "Posit Logo"\)\)\)\)'
1315
- []
1416
---

tests/docs/smoke-all/typst/brand-yaml/logo/relative-path/brand-logo.qmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ _quarto:
1111
typst:
1212
ensureTypstFileRegexMatches:
1313
-
14+
- '#let brand-logo-images = \(\s*large-light: \(\s*path: "resources/quarto.png"\s*\)\s*\)'
15+
- '#let brand-logo = \(\s*large: \(\s*path: "brand_yaml/resources/quarto.png"\s*\)\s*\)'
1416
- '#set page\(background: align\(center\+top, box\(inset: 2em, image\("brand_yaml(/|\\\\)resources(/|\\\\)quarto.png", width: 225pt\)\)\)\)'
1517
- []
1618
---

0 commit comments

Comments
 (0)