Install
The system ships as four packages under the @upmo-ai scope. They are not on npm yet. Install them from a release tag of this repository.
| Package | What it holds |
|---|---|
@upmo-ai/tokens |
tokens.css, the CSS variables for the light, dark and high-contrast themes, and a typed object of every token |
@upmo-ai/ui |
upmoTheme, the Mantine theme built from the tokens. Components follow later. |
@upmo-ai/icons |
The map from interface concepts to Tabler Icons names, and the caret and status SVGs |
@upmo-ai/brands |
The marks of the services Upmo connects to, as SVG, with a manifest |
Add the packages
Section titled “Add the packages”Point each package at a release tag and its folder in the repository:
{ "dependencies": { "@upmo-ai/tokens": "git+https://github.com/upmo-ai/design-system.git#v0.1.0&path:/packages/tokens", "@upmo-ai/ui": "git+https://github.com/upmo-ai/design-system.git#v0.1.0&path:/packages/ui", "@mantine/core": "^9.4.0", "@mantine/hooks": "^9.4.0", "react": "^19.2.0", "react-dom": "^19.2.0" }}Use the same tag for every @upmo-ai package. The releases are in the changelog. @upmo-ai/icons and @upmo-ai/brands install the same way, with their own path:.
The shorthand github:upmo-ai/design-system#v0.1.0&path:/packages/ui works too.
Each package builds its dist folder when pnpm installs it from git. pnpm 11 runs build scripts of git dependencies only when you allow them, so add every @upmo-ai package you install to pnpm-workspace.yaml:
allowBuilds: '@upmo-ai/tokens@git+https://github.com/upmo-ai/design-system.git': true '@upmo-ai/ui@git+https://github.com/upmo-ai/design-system.git': true '@upmo-ai/icons@git+https://github.com/upmo-ai/design-system.git': true '@upmo-ai/brands@git+https://github.com/upmo-ai/design-system.git': trueUse pnpm 11.19 or later. Older versions of pnpm 11 do not match these keys for packages from GitHub and stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED. The keys stay in the git+https form when you use the github: shorthand. A package name on its own never allows the build of a git dependency.
@upmo-ai/ui needs @mantine/core and @mantine/hooks 9.4 or later, and react and react-dom 19.2 or later.
Load the styles
Section titled “Load the styles”Import Mantine’s styles first, then the tokens, then one small file that points Mantine’s surface and text variables at the tokens. That file is the CSS block in Mantine mapping.
import '@mantine/core/styles.css';import '@upmo-ai/tokens/tokens.css';import './upmo-mantine.css';Wrap the app
Section titled “Wrap the app”import { MantineProvider } from '@mantine/core';import { upmoTheme } from '@upmo-ai/ui';
export function App({ children }: { children: React.ReactNode }) { return <MantineProvider theme={upmoTheme}>{children}</MantineProvider>;}Keep the themes in sync
Section titled “Keep the themes in sync”The tokens switch on data-theme; Mantine switches on data-mantine-color-scheme. Drive both from Mantine’s colour scheme:
import { useComputedColorScheme } from '@mantine/core';import { useEffect } from 'react';
export function ThemeSync() { const scheme = useComputedColorScheme('light'); useEffect(() => { document.documentElement.setAttribute('data-theme', scheme); }, [scheme]); return null;}The high-contrast theme is data-theme="hc" with Mantine’s light scheme. See High contrast and colour vision.
Load Manrope (400 to 700) and Fira Code, from Google Fonts or self-hosted, with font-display: swap. Familjen Grotesk 700 is for marketing pages only.
Icons and marks
Section titled “Icons and marks”import { icons } from '@upmo-ai/icons';import { brands, languages } from '@upmo-ai/brands';
icons['action.send']; // 'caret': use the Upmo caret, not a Tabler glyphbrands.find((b) => b.id === 'slack'); // { id: 'slack', file: 'slack.svg', deep: true, currentColor: false }languages.find((l) => l.id === 'go'); // { id: 'go', file: 'languages/go.svg', deep: false, currentColor: false }The SVG files are at @upmo-ai/icons/svg/<name>.svg, @upmo-ai/brands/svg/<id>.svg and @upmo-ai/brands/svg/languages/<id>.svg. Tabler glyphs come from @tabler/icons-react, size={20} and stroke={1.75}. Read Icons, Brands and Languages before placing any of them.