Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table of contents / Automatic enumeration of Markdown headers? #51

Closed
Datseris opened this issue Aug 18, 2020 · 13 comments
Closed

Table of contents / Automatic enumeration of Markdown headers? #51

Datseris opened this issue Aug 18, 2020 · 13 comments

Comments

@Datseris
Copy link

Hi there,

I use Jupyter (specifically Jupyter Lab) to make project reports every 3 months or so. As a result, the reports get quite large. I structure them in detail with markdown headers and sections. Jupyter provides an excellent extension, called simply "table of contents" that does two things:

  1. Enables a table of contents sidebar that is clickable and brings you to the markdown header that you clicked (very useful)
  2. Optionally enumerates all markdown headers with 1., 1.1, 1.2.1, etc. (nice to have, but not as crucial as the above).

Example:

image

Is this possible to be done in Pluto.jl? Is it planned?

@fonsp
Copy link
Member

fonsp commented Aug 18, 2020

For anyone who wants to take this on:

This can be done entirely inside a Pluto notebook - we don't need to modify Pluto itself. I think this should be a PlutoUI.TableOfContents().

Try this:

md"# Hello"
md"# World!"
html"""
<script>
const headers = Array.from(
	document.querySelectorAll(
		"pluto-notebook pluto-output h1"
	)
)

return html`<ul>${headers.map(h1 => 
			html`<li>${h1.innerText}</li>`
	)}</ul>`

</script>
"""

Up to you to figure out how MutationObserver works. If needed we can add a custom cellOutputChanged event to document.

@Datseris
Copy link
Author

Notice that in my example headers of any level get linked, not just h1 (just in case h1 means header level)

@shashankp
Copy link
Contributor

shashankp commented Sep 9, 2020

pluto-cell id can be used to link

image

html"""
html"""
<script>

const elementsOfType = (type) => Array.from(
	document.querySelectorAll(
		"pluto-notebook pluto-output " + type
	)
).map(el => {
	const parentCellId = function(el) {
		while (el.nodeName != 'PLUTO-CELL') {
			el = el.parentNode;
			if (!el) return null;
		}
		return el.id;
	}

	return {
		"el": el,
		"parentCellId": parentCellId(el)
	}
})

const plutoCellIds = Array.from(
	document.querySelectorAll(
		"pluto-notebook pluto-cell"
	)
).map(el => el.id)

const headers = [...elementsOfType("h1"), ...elementsOfType("h2"),...elementsOfType("h3"),...elementsOfType("h4"), ...elementsOfType("h5"),...elementsOfType("h6")] 
headers.sort((a,b) => plutoCellIds.indexOf(a.parentCellId)-plutoCellIds.indexOf(b.parentCellId))

return html`<div>Table of Contents</div><br/><div>
${headers.map(h => html`<div>
	<a class="${h.el.nodeName}" href="#${h.parentCellId}">${h.el.innerText}</a>	 </div>`
	)}
</div>`

</script>
<style>
a {
	text-decoration: none;
}
.H1 {
    padding: 0px 0px;
}
.H2 {
    padding: 0px 10px;
}
.H3 {
    padding: 0px 20px;
}
.H4 {
    padding: 0px 30px;
}
.H5 {
    padding: 0px 40px;
}
.H6 {
    padding: 0px 50px;
}
</style>
"""
"""

But I guess this is not reactive as its html 😕

@fonsp
Copy link
Member

fonsp commented Sep 10, 2020

Cool! Maybe you could add the cell_output_changed event to the <pluto-notebook> node and use that to make it reactive?

@dralletje dralletje transferred this issue from fonsp/Pluto.jl Oct 4, 2020
@dralletje
Copy link
Member

Welcomeeeee to this now fancy thread in PlutoUI 🎉

I made it work with a hybrid event/mutation observer solution, but then @Pocket-titan inspired me to use mutation observer all the way down (it is possible anyway).

Table of Content Notebook

Right now it only links to cells, but it does index all cells. It uses one mutation observer to track when cells are added or removed, and then it uses a second mutation observer to track changes inside the output.

Removes the need for fonsp/Pluto.jl#445 :)

@dralletje
Copy link
Member

(Doesn't work on current Pluto release (the notebook link runs on my branch with javascript enhancements) but this will work in couple of days)

@fonsp
Copy link
Member

fonsp commented Oct 7, 2020

Let's combine this into the PR?

@dralletje Here's a fix for the CSS counters:
https://gist.github.com/fonsp/5dd2648500e348112a1de532f14d3a77

@dralletje
Copy link
Member

I will... TOMORROW

@pbouffard
Copy link

I had to search for the PR for some reason. Sparing the next person 0.5 seconds: it's #30. :)

@DhruvaSambrani
Copy link

Close?

@fonsp
Copy link
Member

fonsp commented Feb 10, 2021

#30 thanks!

@fonsp fonsp closed this as completed Feb 10, 2021
@kapple19
Copy link

Hi all, I've been trying to follow the discussions in this and related issues, and am a bit confused.

Did you guys decide to have the notebook author manually input the header/section numbers? Or has this been automated?

@g-gundam
Copy link

@kapple19 - Hopefully you've figured it out by now, but in case anyone is curious:

using PlutoUI
TableOfContents()

PlutoUI exports a function TableOfContents that will generate a table of contents for you notebook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants