Why did vertical spacing of my outline entries break in Typst 0.13.0?

#let table_of_contents = {
$if(toc)$
    set outline(
        depth: $toc-depth$
    )

    show outline.entry: it => {        
        show regex("^([\d\.]+) "): it => { 
            box(width: 2cm, it)
        }

        let item(it, size, color) = {
            return link(
                it.element.location(),
                text(
                    size: size,
                    fill: color,
                    weight: "bold",
                    (
                        it.prefix(),
                        it.body(),
                        [ #box(width: 1fr, it.fill) ],
                        it.page()
                    ).join()
                )
            )
        }
        if (it.level == 1) {
            v(4pt, weak:true)
            item(it, 15pt, navy)
            v(4pt, weak:true)
        } else if (it.level == 2) {
            v(2pt, weak:true)
            item(it, 12pt, black)
            v(2pt, weak:true)
        } else {
            v(0pt, weak:true)
            item(it, 10pt, black)
            v(0pt, weak:true)
        }
    }
    outline()
    pagebreak()
$endif$
}

The above code worked for 0.10.0, but after upgrading to 0.13, the spacing of the outline was lost.


The working one is like this:
, this is old code from my colleague, I am thinking maybe need to rewrite it in some new way, it is more like classic LaTex way now, right? Thanks a lot for your help.

Hello @bruceliu, I cannot reproduce your output. it’s much preferable if you give a working example instead of abstracting code.

Do you have styling rules on links? It might come from that.

Hello @quachpas , thanks for your quick reply. I saw this code.

#show link: it => {
    if type(it.dest) == "string" {
        set text(fill: aqua)
        underline(it)
    } else {
        it
    }
}

, is it relevant? I tried creating a testing project in typst.app, but it shows ā€œunknown variable: ifā€ for this line

$if(toc)$

, this is not valid in 0.13 already, right?
Thanks.

Type comparison to strings was deprecated in 0.13.0 I believe. So you need to remove the ā€œā€!
As for the syntax $if(toc)$, I wasn’t here for the earlier versions of Typst, but I haven’t seen it for the later versions. I’d just write if ... { ... }.

Hello @quachpas , thanks for your reply, the type comparison may be just a warning. I paste all other parts now after removing some confidential texts of my company.



#let header = {
    set text(size: 10pt)
    v(1cm)
    grid(
        columns: 3,
        [*classification*], [], [],
        box(width: 1fr),
    )
    v(1em)
}

#set document(
    title: "$title$",
    author: "$author$",
    date: none
)

#set par(
    justify: false,
    leading: 0.6em
)

#set text(
    font: "Arimo",
    size: 10pt
)

#show raw: set text(font: "Inconsolata")

#set heading(
    numbering: "1.1 "
)

#show heading: set text(
    font: "Arimo",
    weight: "bold"
)

#show heading.where(
    level: 1
): it => {
    v(36pt, weak: true)
    text(
        font: "Arimo",
        size: 24pt,
        weight: "bold",
        fill: navy,
        it
    )
    v(12pt)
}

#show heading.where(
    level: 2
): it => {
    v(24pt, weak: true)
    text(
        font: "Arimo",
        size: 14pt,
        weight: "bold",
        fill: black,
        it
    )
    v(12pt)
}

#show link: it => {
    if type(it.dest) == str {
        set text(fill: aqua)
        underline(it)
    } else {
        it
    }
}

#show heading.where(
    level: 3
): it => {
    v(18pt, weak: true)
    text(
        font: "Arimo",
        size: 12pt,
        weight: "bold",
        fill: black,
        it
    )
    v(12pt)
}

#set figure(
    supplement: none
)

#show figure: it => {
    set align(left)
    set table(
        fill: (_, row) => if row == 0 { navy },
        stroke: 0.5pt + gray
    )
    show table: jt => {
        set align(left)
        // Allow breaking before "_"
        // This breaks Reqytify tags.
        // show regex("_"): c => { sym.zws + c }
        jt
    }
    show image: set align(left)
    block(it)
}

#show figure.where(
    kind: table
): set block(breakable: true)

#set figure.caption(
    position: top
)

#show figure.caption: it => {
    set align(left)
    set text(
        size: 8pt,
        fill: aqua,
        style: "italic"
    )
    it
}

#show outline.entry: it => {
    set text(
        size: 15pt,
        fill: navy,
        weight: "bold"
    )
    v(12pt, weak:true)
    it
}


#let cover_page = {
    set page(
        paper: "a4",
        margin: 0cm,
    )
    
    set text(
        size: 10pt,
        fill: black
    )

    box(
        width: 100%,
        inset: (x: 1.8cm, y: 1cm)
    )



    $if(title)$
        box(
            width: 100%,
            inset: (x: 1.8cm, y: 1cm),
            text(
                34pt,
                fill: navy,
                upper(strong[$title$])
            )
        )
    $endif$

    $if(subtitle)$
        box(
            width: 100%,
            inset: (x: 1.8cm),
            text(
                14pt,
                weight: "bold",
                [$subtitle$]
            )
        )
    $endif$
}

#let table_of_contents = {
    set outline(
        depth: 3
    )

    show outline.entry: it => {        
        show regex("^([\d\.]+) "): it => { 
            box(width: 2cm, it)
        }

        let item(it, size, color) = {
            return link(
                it.element.location(),
                text(
                    size: size,
                    fill: color,
                    weight: "bold",
                    (
                        it.prefix(),
                        it.body(),
                        [ #box(width: 1fr, it.fill) ],
                        it.page()
                    ).join()
                )
            )
        }
        if (it.level == 1) {
            v(4pt, weak:true)
            item(it, 15pt, navy)
            v(4pt, weak:true)
        } else if (it.level == 2) {
            v(2pt, weak:true)
            item(it, 12pt, black)
            v(2pt, weak:true)
        } else {
            v(0pt, weak:true)
            item(it, 10pt, black)
            v(0pt, weak:true)
        }
    }
    outline()
    pagebreak()
  
}


#let list_of_figures = context {
    if query(figure.where(kind: image)) != () {
        outline(title: [List of Figures], target: figure.where(kind: image))
        pagebreak()
    }
}

#let list_of_tables = context {
    if query(figure.where(kind: table)) != query(figure.where(caption: none)) {
        outline(title: [List of Tables], target: figure.where(kind: table))
        pagebreak()
    }
}

#let references = {
$if(bibliography)$
    set heading(outlined: false)
    block(
        text(
            size: 15pt,
            fill: navy,
            weight: "bold",
            bibliography(
                title: "Other Applicable Documents",
                "$bibliography$"
            )
        )
    )
    pagebreak()
$endif$
}

#cover_page

#pagebreak()

#context {
    let header_size = measure(header)

    set page(
        paper: "a4",
        margin: (
            x: 1.8cm,
            top: header_size.height
        ),
        header-ascent: 0%,
        header: header

    )

    table_of_contents

    list_of_figures

    list_of_tables

    references

    [$body$]


}

The v spacing is still lost. BTW, I am using pandoc to execute typst, the input is just a simple .md markdown file. The ā€˜title’ and other variables are passed from pandoc somehow, it works with pandoc but failed in the typst.app web editor.

Thanks a lot.

Ah! I don’t use quarto, so I cannot reproduce unfortunately.

The outline function has had significant changes in Typst 0.13. See the migration guide here for how to adapt your code to the new system. I’ll copy-paste the most relevant part:

// Typst 0.13+ āœ…
#show outline.entry.where(level: 1): set block(below: 1em)

// Typst 0.12 and below āš ļø
#show outline.entry: it => {
  it
  v(1em, weak: true)
}
2 Likes

Hi @sijo , thanks for the hint, I tried a few ways, seems all not working.

#let table_of_contents = {
    set outline(
        depth: 3
    )


    show outline.entry: it => {
        show regex("^([\d\.]+) "): it => { 
            box(width: 2cm, it)
        }

        let item(it, size, color) = {
            return link(
                it.element.location(),
                text(
                    size: size,
                    fill: color,
                    weight: "bold",
                    (
                        it.prefix(),
                        it.body(),
                        [ #box(width: 1fr, it.fill) ],
                        it.page()
                    ).join()
                )
            )
        }
        if (it.level == 1) {
            set block(below: 40pt)  //first try
            //v(4pt, weak:true)
            item(it, 15pt, navy)
            //v(40pt, weak:true)  //this worked, but in older way
        } else if (it.level == 2) {
            v(2pt, weak:true)
            item(it, 12pt, black)
            v(2pt, weak:true)
        } else {
            v(0pt, weak:true)
            item(it, 10pt, black)
            v(0pt, weak:true)
        }
    }
    show outline.entry.where(level: 1): set block(below: 40pt) //second try

    outline()
    pagebreak()
  
}

#show outline.entry.where(level: 1): set block(below: 10em) //third try

I think the problem is that your item function doesn’t return a block. Try wrapping the text in a block…

But more generally, you should probably rewrite your whole outline styling code since it has changed so much in new Typst 0.13. See the doc and examples here.

@sijo , thanks for the hint, I managed to use show rules to get similar effects. Thanks.

1 Like