diff --git a/src/resources/filters/modules/typst_css.lua b/src/resources/filters/modules/typst_css.lua index 6ef1b7d2d6..860766f0ce 100644 --- a/src/resources/filters/modules/typst_css.lua +++ b/src/resources/filters/modules/typst_css.lua @@ -593,6 +593,47 @@ local function quote(s) return '"' .. s .. '"' end +local same_weights = { + 'thin', + 'light', + 'normal', + 'regular', + 'medium', + 'bold', + 'black', +} + +local weight_synonyms = { + ['ultra-light'] = 'extra-light', + ['demi-bold'] = 'semi-bold', + ['ultra-bold'] = 'extra-bold', +} + +local dashed_weights = { + 'extra-light', + 'ultra-light', + 'semi-bold', + 'demi-bold', + 'extra-bold', + 'ultra-bold', +} + +local function translate_font_weight(w, warnings) + if not w then return nil end + local num = tonumber(w) + if num and 1 <= num and num <= 1000 then + return num + elseif tcontains(same_weights, w) then + return w + elseif tcontains(dashed_weights, w) then + w = weight_synonyms[w] or w + return w:gsub('-', '') + else + output_warning(warnings, 'invalid font weight ' .. tostring(w)) + return nil + end +end + local function translate_border_style(v, _warnings) local dash if v == 'none' then @@ -718,6 +759,7 @@ return { translate_border_width = translate_border_width, translate_border_style = translate_border_style, translate_border_color = translate_border_color, + translate_font_weight = translate_font_weight, consume_width = consume_width, consume_style = consume_style, consume_color = consume_color diff --git a/src/resources/filters/quarto-post/typst-brand-yaml.lua b/src/resources/filters/quarto-post/typst-brand-yaml.lua index 51e78f993c..6389f0b900 100644 --- a/src/resources/filters/quarto-post/typst-brand-yaml.lua +++ b/src/resources/filters/quarto-post/typst-brand-yaml.lua @@ -51,6 +51,11 @@ function render_typst_brand_yaml() end end + local function quote_string(value) + if type(value) ~= 'string' then return value end + return '"' .. value .. '"' + end + return { Pandoc = function(pandoc) local brand = param('brand') @@ -82,10 +87,6 @@ function render_typst_brand_yaml() local decl = '// theme colors at opacity ' .. BACKGROUND_OPACITY .. '\n#let brand-color-background = ' .. to_typst_dict_indent(themebk) quarto.doc.include_text('in-header', decl) end - local function quote_string(value) - if type(value) ~= 'string' then return value end - return '"' .. value .. '"' - end local function conditional_entry(key, value, quote_strings) if quote_strings == null then quote_strings = true end if not value then return '' end @@ -98,7 +99,7 @@ function render_typst_brand_yaml() quarto.doc.include_text('in-header', table.concat({ '#set text(', -- '#show par: set text(', overrules #show heading! - conditional_entry('weight', base.weight), + conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(base.weight)), ')' })) end @@ -117,7 +118,7 @@ function render_typst_brand_yaml() quarto.doc.include_text('in-header', table.concat({ '#show heading: set text(', conditional_entry('font', headings.family), - conditional_entry('weight', headings.weight), + conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(headings.weight)), conditional_entry('style', headings.style), conditional_entry('fill', headings.color, false), ')' @@ -138,7 +139,7 @@ function render_typst_brand_yaml() quarto.doc.include_text('in-header', table.concat({ '#show raw.where(block: false): set text(', conditional_entry('font', monospaceInline.family), - conditional_entry('weight', monospaceInline.weight), + conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceInline.weight)), conditional_entry('size', monospaceInline.size, false), conditional_entry('fill', monospaceInline.color, false), ')' @@ -157,7 +158,7 @@ function render_typst_brand_yaml() quarto.doc.include_text('in-header', table.concat({ '#show raw.where(block: true): set text(', conditional_entry('font', monospaceBlock.family), - conditional_entry('weight', monospaceBlock.weight), + conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(monospaceBlock.weight)), conditional_entry('size', monospaceBlock.size, false), conditional_entry('fill', monospaceBlock.color, false), ')' @@ -187,7 +188,7 @@ function render_typst_brand_yaml() link = link or {} quarto.doc.include_text('in-header', table.concat({ '#show link: set text(', - conditional_entry('weight', link.weight), + conditional_entry('weight', _quarto.modules.typst.css.translate_font_weight(link.weight)), conditional_entry('fill', link.color or primaryColor, false), ')' })) @@ -312,9 +313,11 @@ function render_typst_brand_yaml() headings = headings or {} local color = headings.color or foregroundColor color = color and pandoc.RawInline('typst', color) + local weight = _quarto.modules.typst.css.translate_font_weight(headings.weight or base.weight) + weight = weight and pandoc.RawInline('typst', tostring(quote_string(weight))) meta.brand.typography.headings = { family = headings.family or base.family, - weight = headings.weight or base.weight, + weight = weight, style = headings.style or base.style, decoration = headings.decoration or base.decoration, color = color, diff --git a/tests/docs/smoke-all/typst/brand-yaml/typography/dashed-font-weights.qmd b/tests/docs/smoke-all/typst/brand-yaml/typography/dashed-font-weights.qmd new file mode 100644 index 0000000000..5b41ee9ae4 --- /dev/null +++ b/tests/docs/smoke-all/typst/brand-yaml/typography/dashed-font-weights.qmd @@ -0,0 +1,44 @@ +--- +title: "Dashed font weights" +format: + typst: + keep-typ: true +brand: + typography: + base: + weight: ultra-light + headings: + weight: ultra-bold + monospace-inline: + weight: light + monospace-block: + weight: semi-bold +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - '#set text\(weight: "extralight", \)' + - 'heading-weight: "extrabold",' + - '#show raw.where\(block: false\): set text\(weight: "light", \)' + - '#show raw.where\(block: true\): set text\(weight: "semibold", \)' + - [] + ensurePdfRegexMatches: + - + - 'base is extralight' + - 'heading-2 is extrabold' + - [] + +--- + +## heading-2 is `#context text.weight`{=typst} + +``` +def fact n: + if n == 1: + return 1 + return n * fact(n-1) +``` + +base is `#context text.weight`{=typst} \ +{{< lipsum 1 >}} \ No newline at end of file