---
title: Theme generator
description: Choose a style and palette, then export an editable theme.
---

Open the [theme generator](/themes) to compare Default, Glow, and Soft.
A style controls component design. A palette controls colors. A saved theme
records both choices. Templates supply page layouts and content separately.
Open **Design** in the header to change the preview style or palette.

```astro
---
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
} from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
} from "@/components/ui/select"
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
import {
  Accordion,
  AccordionItem,
  AccordionTrigger,
  AccordionContent,
} from "@/components/ui/accordion"
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from "@/components/ui/dialog"
---

<div class="@container/workbench mx-auto w-full max-w-4xl p-6 sm:p-10">
  <header class="mb-8 flex flex-wrap items-center justify-between gap-4">
    <div>
      <Badge variant="secondary">Workspace</Badge>
      <h2 class="mt-3 text-3xl font-semibold tracking-tight">
        Make room for good work.
      </h2>
    </div>
    <Dialog>
      <DialogTrigger variant="outline">Invite someone</DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Share your workspace</DialogTitle>
          <DialogDescription>
            Preview the dialog, input, and button styles together.
          </DialogDescription>
        </DialogHeader>
        <Label for="invite-email">Email address</Label>
        <Input id="invite-email" type="email" placeholder="you@example.com" />
        <Label for="invite-role">Role</Label>
        <Select defaultValue="member">
          <SelectTrigger id="invite-role" class="w-full">
            <SelectValue>Choose a role</SelectValue>
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="member">Member</SelectItem>
            <SelectItem value="viewer">Viewer</SelectItem>
          </SelectContent>
        </Select>
        <DialogClose>Done</DialogClose>
      </DialogContent>
    </Dialog>
  </header>
  <Tabs defaultValue="overview" class="w-full">
    <TabsList>
      <TabsTrigger value="overview">Overview</TabsTrigger>
      <TabsTrigger value="details">Details</TabsTrigger>
    </TabsList>
    <TabsContent value="overview">
      <div class="mt-6 grid gap-6 @min-xl/workbench:grid-cols-2">
        <Card>
          <CardHeader>
            <CardTitle>A new project</CardTitle>
            <CardDescription>
              Give your next idea a place to start.
            </CardDescription>
          </CardHeader>
          <CardContent class="grid gap-3">
            <Label for="project-name">Project name</Label>
            <Input id="project-name" placeholder="Your next idea" />
          </CardContent>
          <CardFooter class="flex flex-wrap gap-3">
            <Button>Create project</Button>
            <Button variant="outline">View projects</Button>
          </CardFooter>
        </Card>
        <Card>
          <CardHeader>
            <CardTitle>Built for your team</CardTitle>
            <CardDescription>One style across all the details.</CardDescription>
          </CardHeader>
          <CardContent>
            <Accordion collapsible>
              <AccordionItem value="colors">
                <AccordionTrigger>Can I change the colors?</AccordionTrigger>
                <AccordionContent>
                  Choose a palette above. The selected style stays the same.
                </AccordionContent>
              </AccordionItem>
              <AccordionItem value="source">
                <AccordionTrigger>Do I own the source?</AccordionTrigger>
                <AccordionContent>
                  Yes. The registry installs editable Astro and CSS files.
                </AccordionContent>
              </AccordionItem>
            </Accordion>
          </CardContent>
          <CardFooter>
            <Button size="sm" variant="secondary">
              Explore the components
            </Button>
          </CardFooter>
        </Card>
      </div>
    </TabsContent>
    <TabsContent value="details">
      <p class="py-6 text-muted-foreground">
        Try each style with the same palette, then use the site toggle to check
        light and dark modes.
      </p>
    </TabsContent>
  </Tabs>
</div>
```

## Use an exported theme

Save the theme JSON, then generate a site from this workspace:

```sh
bun run gnostic create ../my-site --template portfolio --theme ./my-theme.json --yes
```

Or select the same settings directly:

```sh
bun run gnostic create ../my-site --template portfolio --style glow --palette earth --yes
```

Run `bun run gnostic create` for guided setup. Add `--dry-run` to a command to
list the changes without writing files. The CLI is available from this private
workspace; it is not yet an npm package. The earlier `generate` command still works.

## Apply a theme to an existing site

The project needs Astro, Gnostic registry base styles, and `components.json`.
Run these commands from this workspace:

```sh
bun run gnostic theme check ./my-theme.json
bun run gnostic theme apply ./my-theme.json --cwd ../my-site --dry-run
bun run gnostic theme apply ./my-theme.json --cwd ../my-site
```

The CLI adds `gnostic-theme.css` beside the configured global stylesheet and
imports it after the layout's other imports. It sets the layout's appearance.
When several document layouts exist, add `--layout src/layouts/site.astro`.
This path is relative to the target project. The theme file path is relative
to the directory where you run the command.

Commit the `.gnostic/` folder with your theme. It records the applied recipe and
file hashes. The CLI stops before replacing a managed file with local edits.
Component files, content, and base styles stay intact. New generated templates
share the style through `src/lib/theme.ts`. Explicit appearance props in other
sites keep their value. A computed HTML appearance requires manual setup.

## Export CSS

```sh
bun run gnostic theme export ./my-theme.json --out ./my-theme.css
```

Check, apply, and export accept JSON, YAML, or a built-in preset such as `earth`.
Export writes CSS to stdout when `--out` is absent. Add `--format json` to export
normalized JSON. Use the CSS export to merge local theme edits manually.

To use the CSS export manually, import it **after**
`src/styles/global.css`. Set `data-appearance` on `<html>` to the exported style:
`default`, `glow`, or `soft`. The file contains the selected palette and style rules.
Install components from the registry as usual. The CSS does not include Astro
components or their browser behavior.

The Default palette uses the workspace `theme.css` without deriving new colors.
The site light/dark toggle controls both the documentation and the examples.
