typst icon indicating copy to clipboard operation
typst copied to clipboard

Short figure caption for outline

Open mareikep opened this issue 1 year ago • 10 comments

Description

Allow adding an optional short caption to be displayed in the outline

Use Case

When adding a caption to a figure, the text might be quite long, in particular, when the figure contains a table or (multiple) images that require explanation. The entire caption text is automatically added to the outline, which may look really messy, depending on the text length. In the caption package of LaTeX, one can add an argument <list entry> (kind of a short caption), that shows up in the outline instead of the <heading> (i.e. the actual caption), if given: \caption[⟨list entry⟩]{⟨heading⟩}. If no <list entry> is given, the <heading> is shown in the outline (as is happening now in typst) and if it is given, but left empty ( \caption[]{⟨heading⟩}) , no entry will be made in the outline.

mareikep avatar May 23 '23 13:05 mareikep

I propose changing the heading.outlined type from boolean to string/none. This modification will enable the Table of Contents (ToC) to display a specified string if it is not set to none.

kamasylvia avatar Aug 25 '23 05:08 kamasylvia

But then, if it is none is it not showing or is it using the long caption?

NicolasHaeffner avatar Sep 29 '23 09:09 NicolasHaeffner

See also: https://github.com/typst/typst/pull/1892#issuecomment-1729119959

laurmaedje avatar Sep 29 '23 09:09 laurmaedje

Here's an idea for a workaround while this isn't implemented yet:

#let outlined-figure(
	contents,
	label-name,
	placement: auto,
	caption: none,
	outline-caption: none,
) = [
	#if outline-caption != none [
		#show figure: it => it.counter.update(v => v - 1)
		#figure(contents, caption: outline-caption)
	]
	#figure(
		contents,
		placement: placement,
		caption: caption,
		outlined: outline-caption == none,
	) #label(label-name)
]

Seems to work and produce the desired result (as far as I can tell).

yrd avatar Oct 12 '23 14:10 yrd

Here's an idea for a workaround while this isn't implemented yet:

#let outlined-figure(
	contents,
	label-name,
	placement: auto,
	caption: none,
	outline-caption: none,
) = [
	#if outline-caption != none [
		#show figure: it => it.counter.update(v => v - 1)
		#figure(contents, caption: outline-caption)
	]
	#figure(
		contents,
		placement: placement,
		caption: caption,
		outlined: outline-caption == none,
	) #label(label-name)
]

Seems to work and produce the desired result (as far as I can tell).

This works for me. Thank you!!

bguo068 avatar Dec 13 '23 03:12 bguo068

Here is another solution that is maybe a little bit less cursed:

#let in-outline = state("in-outline", false)
#show outline: it => {
  in-outline.update(true)
  it
  in-outline.update(false)
}

#let flex-caption(long, short) = locate(loc => 
  if in-outline.at(loc) { short } else { long }
)

Which can then be used like this:

#outline(title: [Figures], target: figure)

#figure(
  rect(),
  caption: flex-caption(
    [This is my long caption text in the document.],
    [This is short],
  )
)

laurmaedje avatar Dec 13 '23 11:12 laurmaedje

Here is another solution that is maybe a little bit less cursed:

#let in-outline = state("in-outline", false)
#show outline: it => {
  in-outline.update(true)
  it
  in-outline.update(false)
}

#let flex-caption(long, short) = locate(loc => 
  if in-outline.at(loc) { short } else { long }
)

Which can then be used like this:

#outline(title: [Figures], target: figure)

#figure(
  rect(),
  caption: flex-caption(
    [This is my long caption text in the document.],
    [This is short],
  )
)

Working nicely 😄 . Also works for headings:

#heading(level:1, flex-caption(
  [ a ver long title a ver long title a ver long title  ], 
  [my short one])
)

Thank you so much!!

bguo068 avatar Dec 14 '23 07:12 bguo068

Here is another solution that is maybe a little bit less cursed:

#let in-outline = state("in-outline", false)
#show outline: it => {
  in-outline.update(true)
  it
  in-outline.update(false)
}

#let flex-caption(long, short) = locate(loc => 
  if in-outline.at(loc) { short } else { long }
)

Which can then be used like this:

#outline(title: [Figures], target: figure)

#figure(
  rect(),
  caption: flex-caption(
    [This is my long caption text in the document.],
    [This is short],
  )
)

For future reference - this can (obviously) also be used to omit citations inside figure outlines.

#outline(title: [Figures], target: figure)

#figure(
  rect(),
  caption: flex-caption(
    [Some figure showing x @somesource], //Display caption including citation
    [Some figure showing  x], //Caption without citation used in the outline
  )
)

mst2k avatar Feb 25 '24 19:02 mst2k

Hi all — I'm new to Typst, so if I should check out some more documentation on my own, please don't hesitate to tell me "just read [XYZ]"!

But I was curious if the new "context" introduced in 0.11.0 will be able to improve the current workaround? I tend to think it can, but I am not entirely sure how. Any advice?

yichechang avatar Mar 30 '24 16:03 yichechang

But I was curious if the new "context" introduced in 0.11.0 will be able to improve the current workaround?

Yes, it would now look like this:

#let flex-caption(long, short) = context if in-outline.get() { short } else { long }

andreasKroepelin avatar Apr 30 '24 11:04 andreasKroepelin