Skip to content

Commit

Permalink
improvement: multi-column in app view, docs, GA (#3454)
Browse files Browse the repository at this point in the history
![Screenshot 2025-01-15 at 4 25
37 PM](https://github.com/user-attachments/assets/c1dc9740-0a4e-4dba-9b8c-82f543515021)

![docs-multi-column](https://github.com/user-attachments/assets/86faaa61-4fc4-47aa-926a-80c3e74b644e)


- multi-column in app view (its basic, same width, no background color)
- docs on app widths
- remove feature flag
  • Loading branch information
mscolnick authored Jan 16, 2025
1 parent 13e3045 commit 9139495
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 70 deletions.
Binary file added docs/_static/docs-multi-column.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions docs/guides/editor_features/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ Hit `Cmd/Ctrl+K` to open the command palette.
_Missing a command? File a
[GitHub issue](https://github.com/marimo-team/marimo/issues)._

## Editor widths

You can set the width of the editor in the notebook settings:

- **Compact**: A narrow width with generous margins, ideal for reading
- **Wide**: A wider layout that gives more space for content
- **Full**: Uses the full width of your browser window, ideal for dashboard-style notebooks
- **Multi-column**: Splits your notebook into multiple columns, letting you view and edit cells side-by-side. This is only possible because marimo models your notebook as a directed acyclic graph (DAG) and the [execution order](../reactivity.md#execution-order) is determined by the relationships between
cells and their variables, not by the order of cells on the page.

<div align="center">
<figure>
<img src="/_static/docs-multi-column.png"/>
<figcaption>Multi-column notebook</figcaption>
</figure>
</div>

## Share on our online playground

Get a link to share your notebook via our [online playground](../wasm.md):
Expand Down
25 changes: 0 additions & 25 deletions frontend/src/components/app-config/user-config-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1065,31 +1065,6 @@ export const UserConfigForm: React.FC = () => {
⚠️ These features are experimental and may require restarting your
notebook to take effect.
</p>
<FormField
control={form.control}
name="experimental.multi_column"
render={({ field }) => (
<div className="flex flex-col gap-y-1">
<FormItem className={formItemClasses}>
<FormLabel className="font-normal">
Multi-column layout
</FormLabel>
<FormControl>
<Checkbox
data-testid="multi-column-checkbox"
checked={field.value === true}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
<FormDescription>
Enable experimental support for multi-column notebook
layouts. This adds a new width setting to the notebook
settings menu.
</FormDescription>
</div>
)}
/>
<FormField
control={form.control}
name="experimental.chat_sidebar"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* Copyright 2024 Marimo. All rights reserved. */
import type React from "react";
import { memo, useRef, useState } from "react";
import type { CellRuntimeState } from "@/core/cells/types";
import type { CellData, CellRuntimeState } from "@/core/cells/types";
import { type CellId, HTMLCellId } from "@/core/cells/ids";
import { OutputArea } from "@/components/editor/Output";
import type { ICellRendererPlugin, ICellRendererProps } from "../types";
Expand Down Expand Up @@ -86,41 +86,73 @@ const VerticalLayoutRenderer: React.FC<VerticalLayoutProps> = ({

const canShowCode = evaluateCanShowCode();

const verticalCells = (
<>
{cells.map((cell) => (
<VerticalCell
key={cell.id}
cellId={cell.id}
output={cell.output}
consoleOutputs={cell.consoleOutputs}
status={cell.status}
code={cell.code}
config={cell.config}
cellOutputArea={userConfig.display.cell_output}
stopped={cell.stopped}
showCode={showCode && canShowCode}
errored={cell.errored}
mode={mode}
runStartTimestamp={cell.runStartTimestamp}
interrupted={cell.interrupted}
staleInputs={cell.staleInputs}
name={cell.name}
kiosk={kioskMode}
/>
))}
</>
);
const renderCell = (cell: CellRuntimeState & CellData) => {
return (
<VerticalCell
key={cell.id}
cellId={cell.id}
output={cell.output}
consoleOutputs={cell.consoleOutputs}
status={cell.status}
code={cell.code}
config={cell.config}
cellOutputArea={userConfig.display.cell_output}
stopped={cell.stopped}
showCode={showCode && canShowCode}
errored={cell.errored}
mode={mode}
runStartTimestamp={cell.runStartTimestamp}
interrupted={cell.interrupted}
staleInputs={cell.staleInputs}
name={cell.name}
kiosk={kioskMode}
/>
);
};

const renderCells = () => {
if (appConfig.width === "columns") {
// Group cells by column
const cellsByColumn = new Map<number, typeof cells>();
cells.forEach((cell) => {
const column = cell.config.column ?? 0;
if (!cellsByColumn.has(column)) {
cellsByColumn.set(column, []);
}
cellsByColumn.get(column)?.push(cell);
});

// Sort columns by index
const sortedColumns = [...cellsByColumn.entries()].sort(
([a], [b]) => a - b,
);

return (
<div className="flex flex-row gap-8 w-full">
{sortedColumns.map(([columnIndex, columnCells]) => (
<div
key={columnIndex}
className="flex-1 flex flex-col gap-2 w-contentWidth"
>
{columnCells.map(renderCell)}
</div>
))}
</div>
);
}

return <>{cells.map(renderCell)}</>;
};

// in read mode (required for canShowCode to be true), we need to insert
// spacing between cells to prevent them from colliding; in edit mode,
// spacing is handled elsewhere
return (
<VerticalLayoutWrapper invisible={invisible} appConfig={appConfig}>
{showCode && canShowCode ? (
<div className="flex flex-col gap-5"> {verticalCells}</div>
<div className="flex flex-col gap-5"> {renderCells()}</div>
) : (
verticalCells
renderCells()
)}
{mode === "read" && (
<ActionButtons
Expand Down
1 change: 0 additions & 1 deletion frontend/src/core/config/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export const UserConfigSchema = z
experimental: z
.object({
markdown: z.boolean().optional(),
multi_column: z.boolean().optional(),
rtc: z.boolean().optional(),
// Add new experimental features here
})
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/core/config/feature-flag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export interface ExperimentalFeatures {
markdown: boolean;
wasm_layouts: boolean;
scratchpad: boolean;
multi_column: boolean;
chat_sidebar: boolean;
tracing: boolean;
rtc: boolean;
Expand All @@ -21,7 +20,6 @@ const defaultValues: ExperimentalFeatures = {
markdown: true,
wasm_layouts: false,
scratchpad: true,
multi_column: import.meta.env.DEV,
chat_sidebar: import.meta.env.DEV,
tracing: import.meta.env.DEV,
rtc: false,
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/core/config/widths.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/* Copyright 2024 Marimo. All rights reserved. */
import { getFeatureFlag } from "./feature-flag";

export function getAppWidths() {
return getFeatureFlag("multi_column")
? (["compact", "medium", "full", "columns"] as const)
: (["compact", "medium", "full"] as const);
return ["compact", "medium", "full", "columns"] as const;
}
25 changes: 15 additions & 10 deletions marimo/_smoke_tests/2d-cells.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
import marimo

__generated_with = "0.9.0"
__generated_with = "0.10.13"
app = marimo.App(width="columns")


@app.cell(column=0)
def __():
def _():
import marimo as mo
import altair as alt
from vega_datasets import data
return alt, data, mo


@app.cell
def __(dataset, mo, plot, x, y):
def _(dataset, mo, plot, x, y):
mo.vstack([dataset, x, y, plot])
return


@app.cell
def __(selected_dataset):
def _(selected_dataset):
df = selected_dataset()
df
return (df,)


@app.cell(column=1)
def __(plot_type, x, y):
def _(plot_type, x, y):
plot_type().encode(
x=x.value,
y=y.value,
).interactive()
).interactive().properties(width="container")
return


@app.cell
def __(data, mo):
def _(data, mo):
dataset = mo.ui.dropdown(
label="Choose dataset", options=data.list_datasets(), value="iris"
)
return (dataset,)


@app.cell
def __(df, mo):
def _(df, mo):
x = mo.ui.dropdown(
label="Choose X value", options=df.columns.to_list(), value=df.columns[0]
)
Expand All @@ -59,16 +59,21 @@ def __(df, mo):


@app.cell
def __(data, dataset):
def _(data, dataset):
selected_dataset = getattr(data, dataset.value)
return (selected_dataset,)


@app.cell
def __(alt, df, plot):
def _(alt, df, plot):
plot_type = getattr(alt.Chart(df), plot.value)
return (plot_type,)


@app.cell(column=2)
def _():
return


if __name__ == "__main__":
app.run()

0 comments on commit 9139495

Please sign in to comment.