---
title: "Preferences, layouts, and theming"
description: "initPreferences, layout modes, Pohon unstyled theme, and UnoCSS setup for Taman UI."
canonical_url: "https://vinicunca.dev/taman/guides/preferences-layouts-theming"
---
# Preferences, layouts, and theming

> initPreferences, layout modes, Pohon unstyled theme, and UnoCSS setup for Taman UI.

## Preferences

Call `initPreferences` **before** mounting Vue (`apps/web/src/main.ts`):

```ts
const env = import.meta.env.PROD ? 'prod' : 'dev';
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;

await initPreferences({
  namespace,
  overrides: overridesPreferences,
});
```

`namespace` isolates `StorageManager` keys so two apps (or dev vs prod) do not share prefs.

`apps/web/src/preferences.ts`:

```ts
export const overridesPreferences = defineOverridesPreferences({
  app: {
    defaultHomePath: '/todos/manage',
    name: import.meta.env.VITE_APP_TITLE,
  },
});
```

taman-core defaults (when you do not override) include:

| Key | Default |
| --- | --- |
| `app.accessMode` | `'frontend'` |
| `app.defaultHomePath` | `'/dashboard'` — **no such route** in this template |
| `app.timezone` | `'Asia/Makassar'` |
| `app.layout` | `'sidebar-nav'` |
| `app.locale` | `'en-US'` |
| `app.name` | `'Taman Admin'` |

Clear the cached `preferences` key after changing overrides or they may not apply (cache fills fields you did not set).

### API (`@vinicunca/taman-core/preferences`)

```ts
import {
  clearCache,
  defineOverridesPreferences,
  getPreferences,
  initPreferences,
  preferences,
  preferencesManager,
  resetPreferences,
  updatePreferences,
  usePreferences,
} from '@vinicunca/taman-core/preferences';
```

- `updatePreferences(partial)` — merge + persist (debounced 150 ms)
- `resetPreferences()` — back to the init snapshot
- `usePreferences()` — computed `isDark`, `layout`, `locale`, `isMobile`, shortcut flags, button placement, …

`usePreferences().app` is a **snapshot** of `appPreferences.value` at setup time, not a computed. Prefer `getPreferences()` or the dedicated computeds for reactive reads.

## Layouts

`TamanCoreLayout` (`@vinicunca/taman-ui/layout`) is the admin chrome. The web app wraps it in `apps/web/src/layouts/core.vue`. Auth pages use `layouts/auth.vue`.

`app.layout` values (from preferences types): `sidebar-nav`, `sidebar-mixed-nav`, `header-nav`, `header-mixed-nav`, `header-sidebar-nav`, `mixed-nav`, `full-content`. On mobile, layout is forced to `sidebar-nav`.

Auth page layouts: `panel-left` | `panel-right` (default) | `panel-center`.

## Theming

`apps/web/vite.config.ts` uses Pohon **unstyled**:

```ts
vitePohon({
  colorMode: false,
  theme: { unstyled: true },
  ui: { colors: { primary: 'blue', /* … */ }, ...ui },
  scanPackages: ['@vinicunca/taman-ui', '@taman/app-ui'],
});
```

`@taman/designs` supplies tokens and `vitePohonTheme`. Bootstrap imports `virtual:uno.css`, `@taman/designs/styles`, and `virtual:pohon-theme`.

For a **standalone** taman-ui consumer (the template already does all four in `apps/web`):

1. `vitePohon({ scanPackages: ['@vinicunca/taman-ui'] })`
2. `optimizeDeps.exclude: ['pohon-ui', '@vinicunca/taman-ui']`
3. `resolve.dedupe: ['pohon-ui', 'vue']`
4. UnoCSS `content.pipeline.include` must contain `TAMAN_UI_CONTENT` from `@vinicunca/taman-ui/unocss` (`/@vinicunca[\\/]taman-ui[\\/]dist[\\/].*\.mjs$/`)

Without `TAMAN_UI_CONTENT`, compiled components render without their utilities.

Color CSS variables are generated with `generatorColorVariables` (`@vinicunca/taman-core/color`) as `--taman-color-<name>-<shade>`.


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
