diff --git a/src/components/NotebookCard.tsx b/src/components/NotebookCard.tsx
index 84032eb..102b0ce 100644
--- a/src/components/NotebookCard.tsx
+++ b/src/components/NotebookCard.tsx
@@ -18,6 +18,7 @@ export interface Notebook {
authors: Author[]
date?: Date
seealso?: Notebook[]
+ showLinks?: boolean
links?: { label: string; href: string }[]
}
@@ -35,7 +36,7 @@ const NotebookCard: React.FC<{
"- title:",
notebook?.title,
"notebook.langModel",
- notebook.langModel
+ notebook.langModel,
)
return (
diff --git a/src/components/NotebookViewer.tsx b/src/components/NotebookViewer.tsx
index 5a7504f..74c5a83 100644
--- a/src/components/NotebookViewer.tsx
+++ b/src/components/NotebookViewer.tsx
@@ -1,3 +1,4 @@
+import React from "react"
import { Col, Container, Row } from "react-bootstrap"
import CodeSnippet from "./CodeSnippet"
import MarkdownSnipped from "./MarkdownSnippet"
@@ -14,16 +15,19 @@ export interface NotebookViewerProps {
raw?: string
}
-const splitTextWithCellInfo = (
- text: string
-): Array<{ cellNumber: number; cellType: string; content: string }> => {
- const cells: Array<{
- cellNumber: number
- cellType: string
- content: string
- idx: number
- l: number
- }> = []
+export type CellInfo = {
+ cellNumber: number
+ cellType: string
+ content: string
+ idx: number
+ l: number
+ // headingLevel
+ hl?: number
+ h: string
+}
+
+const splitTextWithCellInfo = (text: string): Array => {
+ const cells: Array = []
const regex = /\{\/*\*\s*cell:(\d+)\s*cell_type:(\w+)\s*\*\/\}/g
let match
while ((match = regex.exec(text)) !== null) {
@@ -33,6 +37,8 @@ const splitTextWithCellInfo = (
cellNumber: parseInt(match[1]),
cellType: match[2],
content: "",
+ hl: 0,
+ h: "",
})
}
@@ -40,18 +46,28 @@ const splitTextWithCellInfo = (
for (let i = 0; i < cells.length; i++) {
const start = cells[i].idx + cells[i].l
const end = cells[i + 1]?.idx
+
cells[i].content = text
.slice(start, end)
.trim()
.replace(/^```python/, "")
.replace(/```$/, "")
.trim()
+
+ // check if the cell is markdown and extract the heading level
+ if (cells[i].cellType === "markdown") {
+ const headingMatch = cells[i].content.match(/^#+ /)
+ if (headingMatch) {
+ cells[i].hl = headingMatch[0].length
+ cells[i].h = cells[i].content.split("\n")[0].replace(/^#+ /, "")
+ }
+ }
}
return cells
}
const getGithubIssuesUrl = (
- githubUrl: string
+ githubUrl: string,
): { url: string; account: string; repository: string } => {
const repoPattern = /github\.com\/([^/]+)\/([^/]+)/
const match = repoPattern.exec(githubUrl)
@@ -75,12 +91,31 @@ const NotebookViewer: React.FC = ({
const accessDateTime = DateTime.fromJSDate(accessTime)
const excerpt = notebook.excerpt ?? ""
+ const headings = cells.filter((cell) => cell.hl)
// Example usage:
const githubUrl = notebook.githubUrl ?? ""
const { url: issueUrl } = getGithubIssuesUrl(githubUrl)
+ const containerRef = React.useRef(null)
+
+ const scrollToHeading = (cellNumber: number) => {
+ const heading = document.getElementById(notebook.href + cellNumber)
+ if (heading) {
+ const offsetTop = heading.getBoundingClientRect().top
+
+ const container = containerRef.current?.parentElement
+ if (container) {
+ console.log("offsetTop", offsetTop)
+
+ container.scrollTo({
+ top: offsetTop,
+ behavior: "smooth",
+ })
+ }
+ }
+ }
return (
-
+
@@ -133,7 +168,7 @@ const NotebookViewer: React.FC = ({
-
+
Report an issue
@@ -149,17 +184,20 @@ const NotebookViewer: React.FC = ({
return true
})
.map((cell, i) => (
-
- {cell.cellType === "markdown" && (
- 0 ? "my-3" : "mb-3"}
- value={cell.content}
- />
- )}
- {cell.cellType === "code" && (
-
- )}
-
+
+ {cell.hl && }
+
+ {cell.cellType === "markdown" && (
+ 0 ? "my-3" : "mb-3"}
+ value={cell.content}
+ />
+ )}
+ {cell.cellType === "code" && (
+
+ )}
+
+
))}
@@ -169,12 +207,29 @@ const NotebookViewer: React.FC = ({
>
)}
+
+ {headings.length > 0 && (
+ <>
+
Table of contents
+
+ {headings.map((heading) => (
+ -
+
+ ))}
+
+ >
+ )}
{Array.isArray(notebook.seealso) ? (
<>
See also
@@ -192,7 +247,9 @@ const NotebookViewer: React.FC
= ({
>
) : null}
- {Array.isArray(notebook.links) && notebook.links.length > 0 ? (
+ {notebook.showLinks &&
+ Array.isArray(notebook.links) &&
+ notebook.links.length > 0 ? (
<>
Links