Skip to content

dashboard theme + theme and style documentation #448

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

Merged
merged 4 commits into from
Jan 8, 2024
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
59 changes: 56 additions & 3 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,70 @@ The path to the source root; defaults to `docs`.

The path to the output root; defaults to `dist`.

## theme

The theme names, if any; defaults to `auto`. Themes affect the visual appearance of pages by specifying colors and fonts, and possibly by augmenting default styles. The theme option is a convenient shorthand alternative to specifying a [custom stylesheet](#style).

The current built-in themes are:

- *auto* (default) - *light* or *dark* depending on the user’s preferred color scheme
- *auto-alt* - *light-alt* or *dark* depending on the user’s preferred color scheme
- *light* - light mode
- *dark* - dark mode
- *wide* - allows the main column to go full width; to be used with one of the above

You can combine themes like so:

```js
theme: ["auto-alt", "wide"]
```

A theme can be also configured for individual pages via the [front matter](./markdown.md#front-matter):

```yaml
---
theme: [auto-alt, wide]
---
```

## style

The path to the project’s stylesheet. This is typically set to `docs/style.css` to override or augment the default stylesheet, or to apply a theme. For example, to use the *light* theme:
The path to a custom stylesheet. This option takes precedence over [themes](#theme) (if any), providing more control by allowing you to remove or alter the default stylesheet and define a custom theme.

The custom stylesheet should typically import the `"observablehq:default.css"` to build on the default styles. You can also import any of the built-in themes. For example, to create a stylesheet that builds up on the *light* theme, create a `custom-style.css` file in the `docs` folder, then set the **style** option to `"custom-style.css"`:

```css
@import url("observablehq:theme-light.css");
@import url("observablehq:default.css");

:root {
--theme-foreground-focus: green;
}
```

The current built-in themes are: *auto* (default), *light*, and *dark*.
If you build on the *auto* or *auto-alt* themes, make sure that colors are chosen according to the user’s [preferred color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme).

The default styles are implemented using CSS custom properties. These properties are designed to be defined by themes or custom stylesheets. The following custom properties are supported:

- `--theme-foreground` - foreground color, _e.g._ black
- `--theme-background` - background color, _e.g._ white
- `--theme-background-alt` - alternative background color, _e.g._ light gray
- `--theme-foreground-alt` - alternative foreground color, used for titles and section titles, _e.g._ brown
- `--theme-foreground-muted` - muted foreground color, _e.g._ dark gray
- `--theme-foreground-faint` - faint foreground color, _e.g._ middle gray
- `--theme-foreground-fainter` - fainter foreground color, _e.g._ light gray
- `--theme-foreground-faintest` - fainter foreground color, _e.g._ almost white
- `--theme-foreground-focus` - focus color, _e.g._ blue

The style property is also configurable for a single page by indicating its relative path in the front-matter:

```yaml
---
style: custom-style.css
---
```

In this case, the path to the stylesheet is resolved relative to the page’s Markdown file rather than the config file.

## title

Expand All @@ -62,7 +116,6 @@ export interface Section {
}
```


If a section’s **open** option is not set, it defaults to true.

Projects can have “unlisted” pages that are not included in the pages list. These pages will still be accessible if linked from other pages or visited directly, but they won’t be listed in the sidebar or linked to via the previous & next footer.
Expand Down
2 changes: 1 addition & 1 deletion src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export async function build(
files.push(...render.files.map(resolveFile));
imports.push(...render.imports.filter((i) => i.type === "local").map(resolveFile));
await effects.writeFile(outputPath, render.html);
const style = mergeStyle(render.data?.style, render.data?.theme, config.style);
const style = mergeStyle(path, render.data?.style, render.data?.theme, config.style);
if (style) {
if ("path" in style) style.path = resolvePath(sourceFile, style.path);
if (!styles.some((s) => styleEquals(s, style))) styles.push(style);
Expand Down
5 changes: 3 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {readFile} from "node:fs/promises";
import {basename, dirname, extname, join} from "node:path";
import {visitFiles} from "./files.js";
import {parseMarkdown} from "./markdown.js";
import {resolvePath} from "./url.js";

export interface Page {
name: string;
Expand Down Expand Up @@ -118,12 +119,12 @@ export function mergeToc(spec: any, toc: TableOfContents): TableOfContents {
return {label, show};
}

export function mergeStyle(style: any, theme: any, defaultStyle: null | Style): null | Style {
export function mergeStyle(path: string, style: any, theme: any, defaultStyle: null | Style): null | Style {
return style === undefined && theme === undefined
? defaultStyle
: style === null
? null // disable
: style !== undefined
? {path: String(style)} // TODO resolve path?
? {path: resolvePath(path, style)}
: {theme: normalizeTheme(theme)};
}
6 changes: 3 additions & 3 deletions src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {ParseResult, ReadMarkdownResult} from "./markdown.js";
import {renderPreview} from "./render.js";
import {bundleStyles, getClientPath, rollupClient} from "./rollup.js";
import {bold, faint, green, underline} from "./tty.js";
import {relativeUrl, resolvePath} from "./url.js";
import {relativeUrl} from "./url.js";

const publicRoot = join(dirname(fileURLToPath(import.meta.url)), "..", "public");

Expand Down Expand Up @@ -257,11 +257,11 @@ function getWatchPaths(parseResult: ParseResult): string[] {
}

export function getPreviewStylesheet(path: string, data: ParseResult["data"], style: Config["style"]): string | null {
style = mergeStyle(data?.style, data?.theme, style);
style = mergeStyle(path, data?.style, data?.theme, style);
return !style
? null
: "path" in style
? relativeUrl(path, `/_import/${resolvePath(path, style.path)}`)
? relativeUrl(path, `/_import/${style.path}`)
: relativeUrl(path, `/_observablehq/theme-${style.theme.join(",")}.css`);
}

Expand Down