Hi, I am a beginner at typst and I am trying to create a cv, and I found a template good enough, but having issues in automatic rendering of points with Link reference, Bold, etc. It is directly showing the syntax, rather than parsing and formatting it.
Here is the code for one of them
#let render-project(projects, title) = {
if projects.len() == 0 {
return
}
let section_body = {
projects
.map(project => {
let main = link(project.url)[#project.name]
if project.url.len() == 0 {
main = project.name
}
let source_code = link(project.source_code)[GitHub]
if project.source_code.len() == 0 {
source_code = ""
}
[
#_entry_heading(
main: main,
dates: _format_dates(start-date: project.startDate, end-date: project.endDate),
description: project.roles.map(emph).join(" | "),
bottom_right: source_code,
)
#v(-2em) \
#project.description
#project.highlights.map(highlight => {
// Parse markdown links in the highlight text
let parts = highlight.split("](")
if parts.len() == 2 {
let text = parts.at(0)
let init = text.split("[").at(0)
let linked_text = text.split("[").at(1)
let url_and_rest = parts.at(1).split(")")
let url = url_and_rest.at(0)
let rest = url_and_rest.at(1)
[- #init#link(url)[#linked_text]#rest]
} else {
[- #highlight]
}
}).join(v(render_space_between_highlight))
]
})
.join(v(render_space_between_entry))
}
_section(title, section_body)
}
As you can see, I am manually parsing the highlight points, if I dont, the link [something](some_link)
is seen as it is, similar with bold and italics. Plus, the code I have written is only able to handle highlight, I am not so sure about how to add on BOLD, etc. if there is no other choice.
Is there a more cleaner way of doing it, I am pretty sure there would be. Please share the code snippet for the same.
Thanks! Loving typst a lot!
Your code does not show any output which makes it difficult to understand your problem/question. Could you please add a minimal example that shows the input and output? If your issue is only related to the loop over the project.highlights
, please only include that part in the example.
Hi @janekfleper,
Right sorry, Here is a proper working example
#let render_space_between_highlight = -0.5em
#let render_space_between_entry = -0.5em
#let render_space_between_sections = -0.5em
#let _entry_heading(
main: "", // top left
dates: "", // top right
description: "", // bottom left
bottom_right: "", // bottom right
) = {
[
=== #main #h(1fr) #dates \
#description #h(1fr) #bottom_right
]
}
#let _section(title, body) = {
[ == #smallcaps(title)]
v(-0.5em)
line(length: 100%, stroke: stroke(thickness: 0.4pt))
v(-0.5em)
body
v(render_space_between_sections)
}
#let _format_dates(
start-date: "",
end-date: "",
) = (
if start-date == end-date {
start-date
} else
{
start-date + " " + $dash.em$ + " " + end-date
}
)
#let render-project(projects, title) = {
if projects.len() == 0 {
return
}
let section_body = {
projects
.map(project => {
let main = link(project.url)[#project.name]
if project.url.len() == 0 {
main = project.name
}
let source_code = link(project.source_code)[GitHub]
if project.source_code.len() == 0 {
source_code = ""
}
[
#_entry_heading(
main: main,
dates: _format_dates(start-date: project.startDate, end-date: project.endDate),
description: project.roles.map(emph).join(" | "),
bottom_right: source_code,
)
#v(-2em) \
#project.description
#project.highlights.map(highlight => {
// Parse markdown links in the highlight text
let parts = highlight.split("](")
if parts.len() == 2 {
let text = parts.at(0)
let init = text.split("[").at(0)
let linked_text = text.split("[").at(1)
let url_and_rest = parts.at(1).split(")")
let url = url_and_rest.at(0)
let rest = url_and_rest.at(1)
[- #init#link(url)[#linked_text]#rest]
} else {
[- #highlight]
}
}).join(v(render_space_between_highlight))
]
})
.join(v(render_space_between_entry))
}
_section(title, section_body)
}
#let x = (
(
name: "Test",
url: "",
source_code: "https://github.com/π",
roles: ("stuff",),
startDate: "March 2025",
endDate: "May 2025",
description: "some description",
highlights: (
"hi [link_works](https://github.com/π) *Not_Bold* _Not_italics_ [second_link_doesnt_work](https://google.com)",
),
),
)
#render-project(x, "test")
You can check the text printed, only the first link works(as expected) and Bold, italics doesnt work. Please help
If the project highlights have to be written in markdown, you can use the package cmarker – Typst Universe. You can then replace the iteration over project.highlights
with
#import "@preview/cmarker:0.1.6"
#cmarker.render(project.highlights)
If markdown is not a requirement, you can also do the formatting in Typst. I would definitely recommend this unless there is some specific reason to use markdown (e.g. you are importing this data from a markdown file).
#let x = (
(
...,
highlights: [hi #link("https://github.com/π")[link_works] *Not_Bold* _Not_italics_ #link("https://google.com")[second_link_doesnt_work]]",
)
)
How should I modify the render-project
for this? More than one highlights can exists, so how should set both? I am not able to use your example.
Ah, I missed that there can be multiple highlights, my bad.
If you are using markdown + cmarker, you can keep the iteration and just write
#project.highlights.map(highlight => cmarker.render(highlight)).join(...)
If you are using the native Typst version, you can directly join the highlights with
#project.highlights.join(...)
In both cases the highlights have to be an array. The definition for the latter case should therefore be
#let x = (
(
...,
highlights: (
[hi #link("https://github.com/π")[link_works] *Not_Bold* _Not_italics_ #link("https://google.com")[second_link_doesnt_work]],
)",
)
)