Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions frontend/src/plugins/layout/OutlinePlugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* Copyright 2024 Marimo. All rights reserved. */
import { Provider, useAtomValue } from "jotai";
import type { JSX } from "react";
import { z } from "zod";
import { notebookOutline } from "@/core/cells/cells";
import { store } from "@/core/state/jotai";
import { OutlineList } from "../../components/editor/chrome/panels/outline/floating-outline";
import {
findOutlineElements,
useActiveOutline,
} from "../../components/editor/chrome/panels/outline/useActiveOutline";
import type {
IStatelessPlugin,
IStatelessPluginProps,
} from "../stateless-plugin";

interface Data {
label?: string;
}

const OutlineContent: React.FC<{ label?: string }> = ({ label }) => {
const { items } = useAtomValue(notebookOutline);
const headerElements = findOutlineElements(items);
const { activeHeaderId, activeOccurrences } =
useActiveOutline(headerElements);

if (items.length === 0) {
return (
<div className="text-muted-foreground text-sm p-4 border border-dashed border-border rounded-lg">
No outline found. Add markdown headings to your notebook to create an
outline.
</div>
);
}

return (
<div className="border border-border rounded-lg">
{label && (
<div className="px-4 py-2 border-b border-border font-medium text-sm">
{label}
</div>
)}
<OutlineList
className="max-h-[400px]"
items={items}
activeHeaderId={activeHeaderId}
activeOccurrences={activeOccurrences}
/>
</div>
);
};

export class OutlinePlugin implements IStatelessPlugin<Data> {
tagName = "marimo-outline";

validator = z.object({
label: z.string().optional(),
});

render(props: IStatelessPluginProps<Data>): JSX.Element {
const { label } = props.data;

return (
<Provider store={store}>
<OutlineContent label={label} />
</Provider>
);
}
}
2 changes: 2 additions & 0 deletions frontend/src/plugins/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { JsonOutputPlugin } from "./layout/JsonOutputPlugin";
import { LazyPlugin } from "./layout/LazyPlugin";
import { MimeRendererPlugin } from "./layout/MimeRenderPlugin";
import { MermaidPlugin } from "./layout/mermaid/MermaidPlugin";
import { OutlinePlugin } from "./layout/OutlinePlugin";
import { ProgressPlugin } from "./layout/ProgressPlugin";
import { RoutesPlugin } from "./layout/RoutesPlugin";
import { StatPlugin } from "./layout/StatPlugin";
Expand Down Expand Up @@ -99,6 +100,7 @@ const LAYOUT_PLUGINS: Array<IStatelessPlugin<unknown>> = [
new MimeRendererPlugin(),
new MermaidPlugin(),
new NavigationMenuPlugin(),
new OutlinePlugin(),
new ProgressPlugin(),
new RoutesPlugin(),
new StatPlugin(),
Expand Down
2 changes: 2 additions & 0 deletions marimo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"nav_menu",
"notebook_dir",
"notebook_location",
"outline",
"output",
"pdf",
"persistent_cache",
Expand Down Expand Up @@ -98,6 +99,7 @@
from marimo._output.hypertext import Html
from marimo._output.justify import center, left, right
from marimo._output.md import latex, md
from marimo._output.outline import outline
from marimo._output.show_code import show_code
from marimo._plugins import ui
from marimo._plugins.stateless import mpl, status
Expand Down
38 changes: 38 additions & 0 deletions marimo/_output/outline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2024 Marimo. All rights reserved.
from __future__ import annotations

from marimo._output.hypertext import Html
from marimo._output.rich_help import mddoc
from marimo._plugins.core.web_component import build_stateless_plugin


@mddoc
def outline(*, label: str = "") -> Html:
"""Display a table of contents outline showing all markdown headers in the notebook.

The outline automatically extracts all markdown headers from executed cells
and displays them in a hierarchical structure with clickable navigation.

Examples:
Basic outline:
```python
mo.outline()
```

With custom label:
```python
mo.outline(label="Table of Contents")
```

Args:
label (str, optional): A descriptive label for the outline. Defaults to "".

Returns:
Html: An HTML object that renders the outline component.
"""
return Html(
build_stateless_plugin(
component_name="marimo-outline",
args={"label": label},
)
)
1 change: 1 addition & 0 deletions tests/snapshots/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ mpl
nav_menu
notebook_dir
notebook_location
outline
output
append
clear
Expand Down
Loading