Appearance
AppearanceControls
The "Appearance" settings panel from @digitalcrew/ui: density, button finish, motion, background effect and intensity, the splash cursor, and a live preview of the result.
Guidelines#
Use it for the personal preferences page of Crew OS (and Max): the signed-in user's choices, per product, in this browser.
What you provide: wrap it in AppearanceProvider with product ("crew-os" or "max") and userId (null when signed out: nothing is read or saved). AppearanceControls takes only className. useAppearance() gives other components preferences, updatePreferences, ready and reducedMotion; SettingsSection is the bordered layout it is built on.
Anatomy: a crew-settings-section card (1px border, 12px radius, card background, 24px padding and gaps; 16px when density is compact) with a "Reset appearance" outline button. Five native selects, at least 44px tall, in a two-column grid (one column below 640px), each with a 13px help line. The splash cursor is a switch row. The preview is at least 272px (17rem) tall and runs the chosen BackgroundEffect behind a sample title, input and primary button.
Behaviour: preferences are stored under digitalcrew:appearance:v1:<product>:<userId> as { version: 1, preferences } and saved only after an explicit change; other tabs follow via the storage event. The provider sets data-density, data-button-finish and data-motion on a display: contents root so primitives restyle. Reduced motion (the choice or the OS setting) disables the splash cursor and stills the background. (The preview seeds "Neon flow" for a first visit.)
Don't save preferences server-side through this component, or render it without a user id.
Facts#
| Group | Appearance |
|---|---|
| Product | Crew OS |
| Global | window.DigitalCrew.AppearanceControls |
| Source | digitalcrew-orchestrator: packages/ui/src/appearance-controls.tsx |
| Import in the app | import { AppearanceControls } from "@/packages/ui/src/appearance-controls"; |
API#
TypeScript declarations emitted from packages/ui/src/appearance-controls.tsx (the module also exports AppearanceControls, SettingsSection).
type SettingsSectionProps = Omit<React.ComponentProps<"section">, "title"> & {
title: string;
description?: string;
actions?: React.ReactNode;
};
/** Shared settings layout; applications retain save actions and authorization. */
export declare function SettingsSection({ title, description, actions, children, className, ...props }: SettingsSectionProps): any;
export declare function AppearanceControls({ className }: {
className?: string;
}): any;Example#
The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.
<div id="root" class="p-6"></div>
<script>
(function () {
var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
var userId = "user_julie_martin";
// Demo only: start this viewer on the "Neon flow" background unless they already chose something here.
try {
var key = "digitalcrew:appearance:v1:crew-os:" + encodeURIComponent(userId);
if (!window.localStorage.getItem(key)) window.localStorage.setItem(key, JSON.stringify({ version: 1, preferences: { background: "neon-flow", intensity: "medium" } }));
} catch (e) {}
function App() { return h(DC.AppearanceProvider, { product: "crew-os", userId: userId }, h(DC.AppearanceControls)); }
ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>