nimib icon indicating copy to clipboard operation
nimib copied to clipboard

Table of contents with linkable headers

Open HugoGranstrom opened this issue 3 years ago • 12 comments

Initial discussion here: https://github.com/SciNim/getting-started/issues/21

The cheatsheet example has links to specific headers. This makes it easy to refer to specific sections of a post. The current implementation needs some work though, optimally the headers themself (or a symbol in front/after of them) should be clickable so one easily can copy the link.

The discussed approaches:

  • Hook into the rendering of the markdown and find the headers and insert links.
  • Explicit nbHeader, nbSubHeader etc, templates

HugoGranstrom avatar Jun 19 '21 21:06 HugoGranstrom

both approaches will need anyway something that translates heading into anchors (e.g. "My smart heading" -> "my-smart-heading"). I note down here for future reference a discussion on how it is done in github: https://gist.github.com/asabaylus/3071099

I also have some thoughts about pros and cons of the two approaches. I will add some comments later on.

pietroppeter avatar Sep 29 '21 06:09 pietroppeter

my current thoughts on how we should do this, and the related issue of being able to add an inline toc is to do post processing the html of each block, add anchor link to each header and update a toc element in nb.context. This should be doable automatically after this is completed: https://github.com/pietroppeter/nimib/pull/35

(to add the inline toc then one would have a nbToc or similar command to place it where you want.)

pietroppeter avatar Nov 18 '21 06:11 pietroppeter

after completing #78 I changed my mind and I think we could do like we do in cheatsheet, only making the api better and a bit more general.

pietroppeter avatar Mar 06 '22 15:03 pietroppeter

I think I figured out the api:

# add field to NbDoc:
type
  NbDoc = object
    ...
    headings: seq[Heading]
    ...
  Heading = object
    level: int
    title: str
    anchor: str

template nbHeading(text: string)
  let level = ... # count numbers of "#" chars at beginning of text
  assert level > 0, "nbHeading must start with at least one #"
  let firstLine = ... # first line of text
  let restLines = ... # other lines of text, if there are other
  let anchor = ... # derive from firstLine
  # create a new block with command nbHeading and anchor and firstLine as data
  # add a new Heading object to NbDoc
  # process restLines (if there are) as in nbText

# rendering of nbHeading is with a partial like this (headingAsHtml is processed from firstLine)
"""<a href="{{anchor}}">{{headingAsHtml}}</a>"""

# we could also have an overload that allows to provide a custom anchor
template nbHeading(anchor: string, text: string)

template nbToc # a placeholder block that when rendered accesses nb.headings and renders it
# it will likely have some TocOptions to customize appearance (how many levels? skip first level? numbered? ...)

Notes:

  • I would go with heading instead of header (googling one vs the other seems heading is better, considered also section but is usually a specific heading, see also toc on wikipedia)
  • having anchor outside of element is fine with html5, edit: on secound thougts maybe better anchor inside header
  • I thought of requiring nbHeading to have only one line, but I guess it is fine to have more lines that are treated like a nbText (one can always give one line and use nbText for the rest).

pietroppeter avatar Oct 26 '22 02:10 pietroppeter

This all sounds good to me :+1: I don't have any preferences regarding the anchor inside/outside the header tag. We will probably want to add some styling to it regardless.

HugoGranstrom avatar Oct 26 '22 08:10 HugoGranstrom

Yep it would be nice to have the link icon on hover like in GitHub

pietroppeter avatar Oct 26 '22 11:10 pietroppeter

as an additional remark, when generating anchor text from headers we might want to do as nim documentation does it, where the anchor will be generated from current heading and the parent heading, if it exists (check examples from manual...).

I guess this is done to help disambiguate common subsection names:

# Animals -> #animals
## birds -> # animals-birds
### what do they eat? -> #birds-what-do-they-eat
## cats -> #animals-cats
### what do they eat? -> #cats-what-do-they-eat

incidentally, ran into this feature while following up on an old "mistake" of mine, see https://github.com/nim-lang/Nim/pull/20688

pietroppeter avatar Oct 28 '22 10:10 pietroppeter

and it seems that github does not do that, though: https://github.com/nim-lang/nimble#tests I wonder if they manage somehow the collisions...

pietroppeter avatar Oct 28 '22 10:10 pietroppeter