Brilliance menu
A card for the display brightness and the palette.
On this page
Dusk: dark surfaces for twilight and a dim saloon.
Display at 62 %, set from the menu.
Code
import {
BrillianceMenu,
ObcPalette,
Readout,
ReadoutPriority,
ReadoutSize,
type BrilliancePalette,
} from "@bosunkit/instruments";
import { useState } from "react";
import type { CSSProperties, Dispatch, ReactElement, SetStateAction } from "react";
export const description: string =
"The menu drives a helm display beside it: choosing Night, Dusk, Day or Bright restyles the whole panel, and the slider and step buttons dim the readouts in steps of 1 and 10 percent.";
const PALETTE_NOTES: Record<BrilliancePalette, string> = {
auto: "Auto: follows the system light or dark setting.",
[ObcPalette.night]: "Night: amber on black, so the watch keeps its dark adaptation.",
[ObcPalette.dusk]: "Dusk: dark surfaces for twilight and a dim saloon.",
[ObcPalette.day]: "Day: light surfaces for the cockpit under cloud.",
[ObcPalette.bright]: "Bright: full contrast for direct sunlight on the screen.",
};
const NOTE_STYLE: CSSProperties = { margin: 0, fontSize: 12, color: "var(--element-neutral-color)", maxWidth: 260 };
export default function Showcase(): ReactElement {
const [palette, setPalette]: [BrilliancePalette, Dispatch<SetStateAction<BrilliancePalette>>] =
useState<BrilliancePalette>(ObcPalette.dusk);
const [brightness, setBrightness]: [number, Dispatch<SetStateAction<number>>] = useState<number>(62);
// The display's backlight never goes fully dark: 0 percent still leaves a fifth of full brightness.
const backlight: number = 0.2 + (0.8 * brightness) / 100;
return (
<div
data-theme={palette === "auto" ? undefined : palette}
style={{
display: "flex",
flexWrap: "wrap",
gap: 20,
alignItems: "flex-start",
justifyContent: "center",
padding: 16,
borderRadius: 10,
background: "var(--container-background-color)",
color: "var(--element-active-color)",
}}
>
<BrillianceMenu
palette={palette}
brightness={brightness}
brightnessUnit="%"
brightnessMax={100}
brightnessMinorStep={1}
brightnessMajorStep={10}
showBrightness
showPalette
onBrightnessChange={setBrightness}
onThemeSelect={setPalette}
onReset={(): void => {
setPalette("auto");
}}
/>
<div style={{ display: "grid", gap: 12 }}>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, auto)",
gap: "12px 24px",
padding: 16,
borderRadius: 8,
background: "var(--container-section-color)",
filter: `brightness(${backlight.toFixed(2)})`,
}}
>
<Readout
label="Depth"
unit="m"
src="Echosounder"
value={12.4}
fractionDigits={1}
size={ReadoutSize.large}
priority={ReadoutPriority.enhanced}
/>
<Readout label="SOG" unit="kn" src="GPS" value={6.2} fractionDigits={1} size={ReadoutSize.large} />
<Readout label="HDG" value={214} hasDegree src="Compass" size={ReadoutSize.medium} />
<Readout label="TWS" unit="kn" src="Masthead" value={17.8} fractionDigits={1} size={ReadoutSize.medium} />
</div>
<p style={NOTE_STYLE}>{PALETTE_NOTES[palette]}</p>
<p style={NOTE_STYLE}>Display at {brightness} %, set from the menu.</p>
</div>
</div>
);
}
The brilliance menu lets the crew dim the display and choose the palette for the light they are in. A slider and four
step buttons set the brightness: the buttons move it by brightnessMinorStep and brightnessMajorStep, 5 and 25 by
default. Five buttons choose the palette: Auto first, following the device's light or dark setting, then the night,
dusk, day and bright palettes.
With controlled props, the menu shows brightness and palette as given and reports a change through onBrightnessChange
and onThemeSelect. The four palettes report their ObcPalette; the automatic choice reports 'auto', so a
controlled caller restores its automatic theme without a button of its own. showBrightness and showPalette hide
either section. paletteIcons supplies the palette glyphs by choice, auto included; a missing entry keeps its
built-in glyph.
Reset restores resetBrightness (50 by default, clamped to the range) and the automatic theme: Day for a light
system setting and Dusk for dark. Auto continues following system changes. A controlled caller handles onReset
by setting its theme preference to auto; the brightness change uses onBrightnessChange as usual. With
resetPalette={false}, Reset restores the brightness alone, keeps the palette, does not call onReset, and is named
"Reset brightness"; the status strip uses it so Reset never takes the crew out of
Night. Reset leaves other display settings alone.
The slider is the shared Slider with variant="brilliance". Arrow keys use the minor step,
Page Up/Down use the major step, and Home/End reach the bounds. Its narrow grip keeps a full touch target.
Examples
Holding its own brightness
Without brightness or palette, the menu keeps its own, starting at defaultBrightness and defaultPalette. Pass
the value and its handler instead when the app keeps the display's brightness, as the showcase does.
Code
import { BrillianceMenu } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string =
"The menu holding its own brightness, starting at 75 percent: the slider and the step buttons move it.";
export default function ThreeQuarters(): ReactElement {
return <BrillianceMenu defaultBrightness={75} />;
}
Application preference and recovery
The menu emits display preferences; it does not prove that the panel's hardware backlight changed. The application owns any brightness adapter and persistence. Keep the controlled value synchronized with confirmed settings and make Reset reachable even at the extremes of the supported range.
Test reset with both light and dark system preferences and after reloading a saved preference. A report or embedded specimen uses its own presentation scope and must not change the vessel's brightness. Keep the visible palette choice consistent with the scope actually displaying the controls.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| palette | BrilliancePalette | undefined | – | The selected palette, held by the caller ('night', 'dusk', 'day', 'bright', or 'auto' for the device's light/dark setting). Leave it unset for the menu
to hold its own, starting at defaultPalette. |
| defaultPalette | BrilliancePalette | undefined | ObcPalette.day | The palette the menu starts on when the caller does not hold palette. Defaults to 'day'. |
| brightness | number | undefined | – | The brightness (0 to brightnessMax), held by the caller. Leave it unset for the menu to hold its own, starting at
defaultBrightness. |
| defaultBrightness | number | undefined | 50 | The brightness the menu starts at when the caller does not hold brightness. Defaults to 50. |
| resetBrightness | number | undefined | 50 | The brightness restored by Reset, clamped to the range. Defaults to 50. |
| resetPalette | boolean | undefined | true | If true (the default), Reset also restores the automatic theme. If false, Reset restores the brightness alone and is named for it, and the palette stays as it was. |
| brightnessUnit | string | undefined | "%" | The unit of the brightness value. |
| brightnessMax | number | undefined | 100 | The maximum value of the brightness slider. |
| brightnessMinorStep | number | undefined | 5 | The minor step of the brightness buttons (and the slider step). |
| brightnessMajorStep | number | undefined | 25 | The major step of the brightness buttons. |
| showBrightness | boolean | undefined | true | If true, shows the brightness slider and step buttons in the menu. |
| showPalette | boolean | undefined | true | If true, shows the palette selector in the menu. |
| onBrightnessChange | ((value: number) => void) | undefined | – | Fired when the brightness is changed (upstream brightness-changed). |
| onReset | (() => void) | undefined | – | Called on Reset so a controlled caller can restore its automatic theme. Brightness also reports through onBrightnessChange. |
| onThemeSelect | ((theme: BrilliancePalette) => void) | undefined | – | Fired when a palette is selected (upstream palette-changed). |
| paletteIcons | Partial<Record<BrilliancePalette, ReactNode>> | undefined | {} | Decorative icons that replace the built-in palette glyphs, by choice; auto covers the automatic choice. Missing entries keep their glyph. |
| className | string | undefined | – | Class name added to the root element. |
Related
- Themes: the four palettes the menu chooses between.
- Instruments: the other instruments.