# Installation

Install @makeplane/propel and wire up its styles.

## Install

```bash
pnpm add @makeplane/propel
```

### Peer dependencies

```bash
pnpm add react react-dom tailwindcss
```

## Import styles

`@makeplane/propel` ships a Tailwind v4 source file, not pre-built CSS — import it from your own
Tailwind entry so its tokens and utilities compile alongside your app's:

```css
@import "tailwindcss";
@import "@makeplane/propel/styles";
```

## Set a theme

Propel's color tokens are scoped to a `data-theme` attribute — set one on `<html>` or the app
root, or every semantic color resolves to nothing. Valid values are `light`, `dark`,
`light-contrast`, and `dark-contrast`:

```html
<html data-theme="light"></html>
```

Propel ships no theme-switching JavaScript; toggling is your app's concern — swap the attribute
and every token follows.

## Load the fonts

The tokens name **Inter Variable** (headings and body) and **IBM Plex Mono** (code) as their first
choices but don't bundle the files. Self-host them with Fontsource — or skip this and the stacks
fall back to the system fonts:

```bash
pnpm add @fontsource-variable/inter @fontsource/ibm-plex-mono
```

```css
@import "@fontsource-variable/inter";
@import "@fontsource/ibm-plex-mono/400.css";
@import "@fontsource/ibm-plex-mono/500.css";
```

## Import components

There's no root barrel — each component is imported from its own subpath, so you only pull in
(and tree-shake to) what you use:

```tsx
import { Button } from "@makeplane/propel/components/button";
```

## Assets

Propel is otherwise asset-free — every component is markup, tokens, and CSS. The one exception is
[`LogoSpinner`](/components/logo-spinner), whose animated Plane mark is a designed GIF (one per
theme) with a PNG still of the fully drawn mark beside it for reduced motion. It statically imports
those files, so it needs a bundler that turns an asset import into a URL — Vite, webpack 5+,
Parcel, or Rollup with an asset plugin. Every other component works without that support.

If you render on the server (SSR, or a prerendered SPA shell), also stop your bundler from
externalizing propel, or the asset import reaches Node — which cannot load a `.gif` — and the
render fails:

```ts
// vite.config.ts
export default defineConfig({
  ssr: { noExternal: ["@makeplane/propel"] },
});
```

The GIFs and stills are also exported raw
(`@makeplane/propel/components/logo-spinner/logo-spinner-light.gif`,
`…/logo-spinner-light-still.png`), so an app's own pre-hydration splash CSS can point at the same
artwork instead of keeping a copy.
