mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2026-08-24 02:34:19 -05:00
fix(svg): change studio render based on mode
Entire-Checkpoint: 642cd14ce7ad
This commit is contained in:
committed by
Jan De Dobbeleer
parent
8528d35a7a
commit
f6793cbedc
+12
-1
@@ -40,6 +40,17 @@ type windowGeometry struct {
|
||||
controlGap float64 // spacing between the three window controls
|
||||
}
|
||||
|
||||
// minStrokeWidth is the floor writeWindowChrome's border stroke never
|
||||
// scales below: below the default FontSize (16, scale ~0.33) the plain
|
||||
// 2*scale formula drops under 1px - thin enough that anti-aliasing fades it
|
||||
// to near-nothing, which is what left the window's rounded corners barely
|
||||
// visible at every FontSize this package is actually used at (the website's
|
||||
// theme gallery and Studio preview both render at the default). 1px is
|
||||
// still crisp at FontSize 48's own scale=1 (2*1 > 1, so the clamp is a
|
||||
// no-op there and TestNewWindowGeometryScalesWithFontSize's pinned value of
|
||||
// 2 is untouched).
|
||||
const minStrokeWidth = 1.0
|
||||
|
||||
func newWindowGeometry(opts *Options) windowGeometry {
|
||||
scale := opts.FontSize / 48.0
|
||||
|
||||
@@ -47,7 +58,7 @@ func newWindowGeometry(opts *Options) windowGeometry {
|
||||
padding: 48 * scale,
|
||||
titleOffset: 80 * scale,
|
||||
corner: 12 * scale,
|
||||
strokeWidth: 2 * scale,
|
||||
strokeWidth: max(2*scale, minStrokeWidth),
|
||||
}
|
||||
|
||||
geo.controlSize = geo.titleOffset * 0.55
|
||||
|
||||
@@ -25,9 +25,11 @@ import (
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/color"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/config"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/render"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/runtime"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/svg"
|
||||
"github.com/jandedobbeleer/oh-my-posh/src/terminal"
|
||||
)
|
||||
|
||||
@@ -170,6 +172,18 @@ func renderSVG(args []js.Value) (string, error) {
|
||||
|
||||
opts := render.SVGOptions(jsString(optionsGet(options, "fontFamily")), columns, metrics)
|
||||
|
||||
// A caller-supplied canvas background (the website's studio, switching between its own
|
||||
// dark/light color mode) only ever fills in for a theme that leaves its own terminal
|
||||
// background unset - withDefaults (svg.go) always prefers a real opts.TerminalBackground
|
||||
// over CanvasBackground when the theme sets one, so this can't paint over how the theme
|
||||
// would actually look in a real terminal. Same convention as the CLI's own
|
||||
// --background-color flag (cli/config_export_svg.go's exportSVG).
|
||||
if backgroundColor := jsString(optionsGet(options, "backgroundColor")); backgroundColor != "" {
|
||||
if rgb, ok := svg.ResolveStaticRGB(color.Ansi(backgroundColor), true, &opts); ok {
|
||||
opts.CanvasBackground = rgb
|
||||
}
|
||||
}
|
||||
|
||||
return render.SVG(eng, opts), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
// 2. wraps it as the lone segment of a minimal version-4 config, one "left"-aligned block;
|
||||
// 3. shells out to the oh-my-posh CLI (see buildPoshArgs below - same flags/font metrics as
|
||||
// export_themes.mjs, so a segment preview and a theme-gallery render use an identical grid)
|
||||
// to export that config to SVG, fed by the same website/segment_data.json every theme
|
||||
// to export that config to SVG twice - once unchanged, once with a light canvas background
|
||||
// (see CONFIG.LIGHT_BACKGROUND) - fed by the same website/segment_data.json every theme
|
||||
// preview already renders from;
|
||||
// 4. writes generated/segment-previews.json keyed by doc id (the frontmatter `id:`, exposed by
|
||||
// the doc page's own useDoc() as frontMatter.id - see Config.js), each entry a
|
||||
// { segment, svg } pair so Config.js can confirm which of a page's possibly-several
|
||||
// <Config/> blocks the preview actually belongs to (see the manifest-building comment in
|
||||
// main() below).
|
||||
// { segment, svg, svgLight } triple so Config.js can confirm which of a page's possibly-
|
||||
// several <Config/> blocks the preview actually belongs to (see the manifest-building
|
||||
// comment in main() below), and switch its static preview with the site's own color mode
|
||||
// the same way the theme gallery does (ThemeGallery/index.js).
|
||||
//
|
||||
// Output is gitignored under /generated (see .gitignore), regenerated on every build exactly
|
||||
// like generated/themes.json, and reached by Config.js via a plain static import - not
|
||||
@@ -34,7 +36,7 @@ import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { asyncPool } from '../export_themes.mjs';
|
||||
import { asyncPool, CONFIG as EXPORT_THEMES_CONFIG } from '../export_themes.mjs';
|
||||
import { VICTOR_MONO } from '../font-metrics.mjs';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
@@ -51,6 +53,11 @@ const CONFIG = {
|
||||
LINE_HEIGHT: VICTOR_MONO.LINE_HEIGHT,
|
||||
FILL_ASCENT: VICTOR_MONO.FILL_ASCENT,
|
||||
FILL_DESCENT: VICTOR_MONO.FILL_DESCENT,
|
||||
// Infima's own light-theme background - same value export_themes.mjs's LIGHT_BACKGROUND
|
||||
// renders the theme gallery/hero's light variant against, reused here so a segment doc's
|
||||
// static preview switches with the site's own dark/light toggle instead of always looking
|
||||
// like a dark-mode terminal (see Config.js's <EditableConfig/>).
|
||||
LIGHT_BACKGROUND: EXPORT_THEMES_CONFIG.LIGHT_BACKGROUND,
|
||||
};
|
||||
|
||||
// Same override hook export_themes.mjs offers: point at a locally built binary instead of
|
||||
@@ -63,7 +70,11 @@ const PREVIEW_COLUMNS = 64;
|
||||
|
||||
const NOT_A_SEGMENT_DOC = new Set(['overview.mdx']);
|
||||
|
||||
function buildPoshArgs(configPath, outputPath) {
|
||||
// backgroundColor is optional (see CONFIG.LIGHT_BACKGROUND) - it is what makes a segment's
|
||||
// light-mode render actually light when its theme sets no terminal background of its own; a
|
||||
// segment whose sample config does set one is unaffected either way, since --background-color
|
||||
// always loses to a real terminal background (config_export_image.go).
|
||||
function buildPoshArgs(configPath, outputPath, backgroundColor) {
|
||||
return [
|
||||
'config',
|
||||
'export',
|
||||
@@ -75,6 +86,7 @@ function buildPoshArgs(configPath, outputPath) {
|
||||
`--line-height=${CONFIG.LINE_HEIGHT}`,
|
||||
`--fill-ascent=${CONFIG.FILL_ASCENT}`,
|
||||
`--fill-descent=${CONFIG.FILL_DESCENT}`,
|
||||
...(backgroundColor ? [`--background-color=${backgroundColor}`] : []),
|
||||
// Narrower than the gallery's 120. A theme fills the width; one segment occupies a
|
||||
// fraction of it, so at 120 columns the preview is mostly empty terminal and the
|
||||
// segment renders small enough to squint at. 64 is the smallest width at which none of
|
||||
@@ -256,6 +268,30 @@ function buildPromptConfig(segment) {
|
||||
};
|
||||
}
|
||||
|
||||
// Shells out to the CLI once, rendering tmpConfigPath to tmpOutputPath and reading the result
|
||||
// back. label only ever appears in the stderr warning below, so callers can name which of a
|
||||
// segment's two renders (dark/light) produced it.
|
||||
async function renderOnce(tmpConfigPath, tmpOutputPath, label, backgroundColor) {
|
||||
let stderr;
|
||||
|
||||
try {
|
||||
({ stderr } = await execFileAsync(
|
||||
OMP_BIN,
|
||||
buildPoshArgs(tmpConfigPath, tmpOutputPath, backgroundColor),
|
||||
));
|
||||
} catch (error) {
|
||||
throw new Error(`CLI render failed (${label}): ${error.message}`);
|
||||
}
|
||||
|
||||
if (stderr) {
|
||||
// Non-zero exit already threw above; incidental stderr (e.g. the hand-written-data-file
|
||||
// warning export_themes.mjs also swallows) must not fail the build.
|
||||
console.warn(`${label}: ${stderr.trim()}`);
|
||||
}
|
||||
|
||||
return promises.readFile(tmpOutputPath, 'utf8');
|
||||
}
|
||||
|
||||
async function renderSegmentPreview(doc) {
|
||||
const content = await promises.readFile(doc.filePath, 'utf8');
|
||||
|
||||
@@ -273,31 +309,36 @@ async function renderSegmentPreview(doc) {
|
||||
|
||||
const tmpConfigPath = join(tmpdir(), `omp-preview-config-${randomUUID()}.omp.json`);
|
||||
const tmpOutputPath = join(tmpdir(), `omp-preview-${randomUUID()}.svg`);
|
||||
const tmpOutputPathLight = join(tmpdir(), `omp-preview-light-${randomUUID()}.svg`);
|
||||
|
||||
try {
|
||||
await promises.writeFile(tmpConfigPath, JSON.stringify(promptConfig));
|
||||
|
||||
let stderr;
|
||||
let svg;
|
||||
let svgLight;
|
||||
|
||||
try {
|
||||
({ stderr } = await execFileAsync(OMP_BIN, buildPoshArgs(tmpConfigPath, tmpOutputPath)));
|
||||
// Two renders of the same config, same as export_themes.mjs's own dark/light pair - so a
|
||||
// segment doc's static "Sample Configuration" preview switches with the site's own toggle
|
||||
// instead of always looking like a dark-mode terminal (see Config.js's <EditableConfig/>).
|
||||
svg = await renderOnce(tmpConfigPath, tmpOutputPath, doc.fileName);
|
||||
svgLight = await renderOnce(
|
||||
tmpConfigPath,
|
||||
tmpOutputPathLight,
|
||||
`${doc.fileName} (light)`,
|
||||
CONFIG.LIGHT_BACKGROUND,
|
||||
);
|
||||
} catch (error) {
|
||||
return { doc, error: `CLI render failed: ${error.message}` };
|
||||
return { doc, error: error.message };
|
||||
}
|
||||
|
||||
if (stderr) {
|
||||
// Non-zero exit already returned above; incidental stderr (e.g. the hand-written-data-file
|
||||
// warning export_themes.mjs also swallows) must not fail the build.
|
||||
console.warn(`${doc.fileName}: ${stderr.trim()}`);
|
||||
}
|
||||
|
||||
const svg = await promises.readFile(tmpOutputPath, 'utf8');
|
||||
|
||||
console.info(`Rendered preview for ${idResult.id} (${doc.group}/${doc.fileName})`);
|
||||
|
||||
return { doc, id: idResult.id, segment: configResult.segment, svg };
|
||||
return { doc, id: idResult.id, segment: configResult.segment, svg, svgLight };
|
||||
} finally {
|
||||
await promises.unlink(tmpConfigPath).catch(() => {});
|
||||
await promises.unlink(tmpOutputPath).catch(() => {});
|
||||
await promises.unlink(tmpOutputPathLight).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,14 +363,14 @@ async function main() {
|
||||
const rendered = results.filter((result) => !result.error);
|
||||
const failed = results.filter((result) => result.error);
|
||||
|
||||
// { segment, svg } rather than a bare svg string: six segment docs (see module comment)
|
||||
// render a second, illustrative <Config/> elsewhere on the page with the same doc id but a
|
||||
// different sample object. Config.js only shows the preview above the <Config/> whose own
|
||||
// `data` prop deep-equals `segment` here, so the generic preview never appears next to an
|
||||
// unrelated example further down the same page.
|
||||
// { segment, svg, svgLight } rather than a bare svg string: six segment docs (see module
|
||||
// comment) render a second, illustrative <Config/> elsewhere on the page with the same doc
|
||||
// id but a different sample object. Config.js only shows the preview above the <Config/>
|
||||
// whose own `data` prop deep-equals `segment` here, so the generic preview never appears
|
||||
// next to an unrelated example further down the same page.
|
||||
const manifest = {};
|
||||
for (const result of rendered) {
|
||||
manifest[result.id] = { segment: result.segment, svg: result.svg };
|
||||
manifest[result.id] = { segment: result.segment, svg: result.svg, svgLight: result.svgLight };
|
||||
}
|
||||
|
||||
await promises.writeFile(CONFIG.OUTPUT_FILE, JSON.stringify(manifest));
|
||||
|
||||
@@ -7,10 +7,15 @@ import classnames from 'classnames';
|
||||
import YAML from 'yaml';
|
||||
import TOML from 'smol-toml';
|
||||
import { useDoc } from '@docusaurus/plugin-content-docs/client';
|
||||
import { useColorMode } from '@docusaurus/theme-common';
|
||||
import ConfigEditor from './ConfigEditor';
|
||||
import WasmMessage from './ConfigEditor/WasmMessage';
|
||||
import { useWasmRenderer } from './ConfigEditor/useWasmRenderer';
|
||||
import { buildRenderOptions, RENDER_DATA_JSON } from './ConfigEditor/renderDefaults';
|
||||
import {
|
||||
buildRenderOptions,
|
||||
LIGHT_BACKGROUND_COLOR,
|
||||
RENDER_DATA_JSON,
|
||||
} from './ConfigEditor/renderDefaults';
|
||||
import { convertConfig, parseConfig, stringifyConfig } from './ConfigEditor/serialize';
|
||||
import { APPEND_KEY, trySessionStorageSet } from './ConfigEditor/studioHandoff';
|
||||
import styles from './Config.module.css';
|
||||
@@ -130,7 +135,7 @@ function AddToStudioButton({ format, configText, disabled }) {
|
||||
// The editable half of a segment doc's "Sample Configuration": the build-time static SVG shows
|
||||
// immediately (see Config below), and only turns into a live one once the reader edits the
|
||||
// config for the first time - see useWasmRenderer's `eager` doc comment for why that matters.
|
||||
function EditableConfig({ data, staticSvg }) {
|
||||
function EditableConfig({ data, staticSvg, staticSvgLight }) {
|
||||
// Only the default format's text is built up front. The other two used to be pre-rendered as
|
||||
// well, to be swapped in whole when the reader picked a different tab; handleFormatChange now
|
||||
// rewrites whatever is in the editor instead (see convertConfig), so they were never read.
|
||||
@@ -143,6 +148,13 @@ function EditableConfig({ data, staticSvg }) {
|
||||
const formatRef = useRef(SEGMENT_DEFAULT_FORMAT);
|
||||
const debounceRef = useRef(null);
|
||||
|
||||
// The site's own dark/light toggle (see Studio/index.js, which follows the same convention) -
|
||||
// the live preview's canvas background is switched to match it below, rather than always
|
||||
// rendering against the exporter's fixed dark default.
|
||||
const { colorMode } = useColorMode();
|
||||
const colorModeRef = useRef(colorMode);
|
||||
colorModeRef.current = colorMode;
|
||||
|
||||
const { svg, error, wasmStatus, wasmProgress, wasmErrorMessage, render, ensureLoaded } =
|
||||
useWasmRenderer({ eager: false });
|
||||
|
||||
@@ -159,22 +171,35 @@ function EditableConfig({ data, staticSvg }) {
|
||||
|
||||
setParseError(null);
|
||||
const wrappedText = stringifyConfig(fmt, buildPromptConfig(segment));
|
||||
render(wrappedText, fmt, RENDER_DATA_JSON, SEGMENT_RENDER_OPTIONS);
|
||||
|
||||
// A caller-supplied backgroundColor only ever fills in for a segment whose sample config
|
||||
// leaves its own terminal background unset (see src/wasm/main.go's renderSVG), so a
|
||||
// segment that does set one keeps looking like itself regardless of color mode.
|
||||
const options =
|
||||
colorModeRef.current === 'light'
|
||||
? { ...SEGMENT_RENDER_OPTIONS, backgroundColor: LIGHT_BACKGROUND_COLOR }
|
||||
: SEGMENT_RENDER_OPTIONS;
|
||||
|
||||
render(wrappedText, fmt, RENDER_DATA_JSON, options);
|
||||
},
|
||||
[render],
|
||||
);
|
||||
|
||||
// Mirrors the studio's own "render as soon as the module is ready" effect (Studio/index.js):
|
||||
// the module only starts loading on the reader's first edit (see handleChange below), so by
|
||||
// the time it actually becomes ready there is already something worth rendering.
|
||||
// the time it actually becomes ready there is already something worth rendering. colorMode is
|
||||
// also a dependency so that flipping the site's own dark/light toggle re-renders the current
|
||||
// config against the new canvas background immediately, instead of only picking it up on the
|
||||
// reader's next edit.
|
||||
useEffect(() => {
|
||||
if (wasmStatus === 'ready') {
|
||||
runRender(configText, format);
|
||||
}
|
||||
// configText/format intentionally excluded: this effect's only job is the one render that
|
||||
// happens the moment the module becomes ready, not every keystroke after.
|
||||
// configText/format intentionally excluded: this effect's job is the one render that
|
||||
// happens the moment the module becomes ready (or the color mode flips), not every
|
||||
// keystroke after.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [wasmStatus, runRender]);
|
||||
}, [wasmStatus, colorMode, runRender]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
@@ -232,10 +257,11 @@ function EditableConfig({ data, staticSvg }) {
|
||||
);
|
||||
|
||||
// Keeps the last good preview on screen instead of blanking it: before the first edit (or
|
||||
// while the module is still loading) that is the build-time static SVG; once a live render has
|
||||
// actually succeeded at least once, its own svg takes over and is itself kept across a later
|
||||
// parse/render error, same as the studio.
|
||||
const displaySvg = svg || staticSvg;
|
||||
// while the module is still loading) that is the build-time static SVG pair, switched by CSS
|
||||
// off the site's own color mode exactly like the theme gallery (see ThemeGallery/index.js);
|
||||
// once a live render has actually succeeded at least once, its own single svg - already
|
||||
// rendered for the current color mode, see runRender above - takes over and is itself kept
|
||||
// across a later parse/render error, same as the studio.
|
||||
const displayError = parseError || error;
|
||||
|
||||
return (
|
||||
@@ -248,8 +274,21 @@ function EditableConfig({ data, staticSvg }) {
|
||||
className={styles.wasmMessage}
|
||||
/>
|
||||
{displayError && <p className={styles.error}>{displayError}</p>}
|
||||
{displaySvg && (
|
||||
<span className={styles.svgWrapper} dangerouslySetInnerHTML={{ __html: displaySvg }} />
|
||||
{svg ? (
|
||||
<span className={styles.svgWrapper} dangerouslySetInnerHTML={{ __html: svg }} />
|
||||
) : (
|
||||
staticSvg && (
|
||||
<>
|
||||
<span
|
||||
className={`${styles.svgWrapper} omp-dark-only`}
|
||||
dangerouslySetInnerHTML={{ __html: staticSvg }}
|
||||
/>
|
||||
<span
|
||||
className={`${styles.svgWrapper} omp-light-only`}
|
||||
dangerouslySetInnerHTML={{ __html: staticSvgLight }}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<ConfigEditor
|
||||
@@ -289,10 +328,11 @@ function Config(props) {
|
||||
// the stored sample object against this instance's own `data` prop confirms this really is the
|
||||
// <Config/> the preview was rendered from - and, now, which instance gets to become editable:
|
||||
// an unmatched second block keeps the plain tabs below rather than turning into its own editor.
|
||||
const preview = entry && JSON.stringify(entry.segment) === JSON.stringify(data) ? entry.svg : null;
|
||||
const isMatch = entry && JSON.stringify(entry.segment) === JSON.stringify(data);
|
||||
const preview = isMatch ? entry.svg : null;
|
||||
|
||||
if (preview) {
|
||||
return <EditableConfig data={data} staticSvg={preview} />;
|
||||
return <EditableConfig data={data} staticSvg={preview} staticSvgLight={entry.svgLight} />;
|
||||
}
|
||||
|
||||
const patchTomlData = () => {
|
||||
|
||||
@@ -27,3 +27,12 @@ export function buildRenderOptions(columns) {
|
||||
fillDescent: VICTOR_MONO.FILL_DESCENT,
|
||||
};
|
||||
}
|
||||
|
||||
// Infima's own light-theme background (no --ifm-background-color override lives in
|
||||
// custom.css) - same value export_themes.mjs's LIGHT_BACKGROUND renders the gallery/hero's
|
||||
// light variant against, so the studio's live preview matches every other build-time render
|
||||
// that already follows the site's color mode. Passed as the wasm render() call's own
|
||||
// options.backgroundColor (see src/wasm/main.go), which only ever fills in for a theme that
|
||||
// leaves its own terminal background unset - a theme with its own background (e.g.
|
||||
// tokyonight_storm) keeps looking like itself in the studio regardless of color mode.
|
||||
export const LIGHT_BACKGROUND_COLOR = '#ffffff';
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { useColorMode } from '@docusaurus/theme-common';
|
||||
import ConfigEditor from '../ConfigEditor';
|
||||
import WasmMessage from '../ConfigEditor/WasmMessage';
|
||||
import { useWasmRenderer } from '../ConfigEditor/useWasmRenderer';
|
||||
import { buildRenderOptions, RENDER_DATA_JSON } from '../ConfigEditor/renderDefaults';
|
||||
import {
|
||||
buildRenderOptions,
|
||||
LIGHT_BACKGROUND_COLOR,
|
||||
RENDER_DATA_JSON,
|
||||
} from '../ConfigEditor/renderDefaults';
|
||||
import { convertConfig, parseConfig, stringifyConfig } from '../ConfigEditor/serialize';
|
||||
import {
|
||||
APPEND_KEY,
|
||||
@@ -82,14 +87,31 @@ function Studio() {
|
||||
const { svg, error, wasmStatus, wasmProgress, wasmErrorMessage, render, ensureLoaded } =
|
||||
useWasmRenderer({ eager: true });
|
||||
|
||||
// The site's own dark/light toggle (the same @docusaurus/theme-common hook ConfigEditor's
|
||||
// syntax-highlighting theme already follows) - the preview's canvas background is switched to
|
||||
// match it below, rather than always rendering against the exporter's fixed dark default.
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
const debounceRef = useRef(null);
|
||||
// runRender is a useCallback with no deps, so reading `format` from the closure would pin
|
||||
// it to whatever was selected on first render. The ref is what the render call reads.
|
||||
// runRender is a useCallback with no deps, so reading `format`/`colorMode` from the closure
|
||||
// would pin them to whatever was selected on first render. The refs are what the render call
|
||||
// actually reads.
|
||||
const formatRef = useRef(CONFIG_FORMAT);
|
||||
const colorModeRef = useRef(colorMode);
|
||||
colorModeRef.current = colorMode;
|
||||
|
||||
const runRender = useCallback(
|
||||
(text) => {
|
||||
render(text, formatRef.current, RENDER_DATA_JSON, RENDER_OPTIONS);
|
||||
// A caller-supplied backgroundColor only ever fills in for a theme that leaves its own
|
||||
// terminal background unset (see src/wasm/main.go's renderSVG), so a theme with its own
|
||||
// background keeps looking like itself regardless of color mode - only the default,
|
||||
// background-less starter actually changes with the toggle.
|
||||
const options =
|
||||
colorModeRef.current === 'light'
|
||||
? { ...RENDER_OPTIONS, backgroundColor: LIGHT_BACKGROUND_COLOR }
|
||||
: RENDER_OPTIONS;
|
||||
|
||||
render(text, formatRef.current, RENDER_DATA_JSON, options);
|
||||
},
|
||||
[render],
|
||||
);
|
||||
@@ -224,16 +246,18 @@ function Studio() {
|
||||
}, [format, configText]);
|
||||
|
||||
// Render the starter config as soon as the module is ready, so a prompt appears on first
|
||||
// paint without the user having to touch the editor.
|
||||
// paint without the user having to touch the editor. colorMode is also a dependency so that
|
||||
// flipping the site's own dark/light toggle re-renders the current config against the new
|
||||
// canvas background immediately, instead of only picking it up on the reader's next edit.
|
||||
useEffect(() => {
|
||||
if (wasmStatus === 'ready') {
|
||||
runRender(configText);
|
||||
}
|
||||
// configText is intentionally not a dependency: this effect's only job is the one render
|
||||
// that happens the moment the module becomes ready, not every keystroke after - the
|
||||
// editor's onChange handles that, debounced.
|
||||
// configText is intentionally not a dependency: this effect's job is the one render that
|
||||
// happens the moment the module becomes ready (or the color mode flips), not every
|
||||
// keystroke after - the editor's onChange handles that, debounced.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [wasmStatus, runRender]);
|
||||
}, [wasmStatus, colorMode, runRender]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
|
||||
Reference in New Issue
Block a user