Official

themes

The stock themes: presets of every colour, type size, corner and density token, chosen per light and dark mode and edited in Settings.

The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/themes@0.3.0

Permissions in 0.3.0

  • Change app settings settings.writeHighChanges the app settings.Apply the chosen theme to the window

Files

settings-model.ts1.2 KB
// The plugin's settings read safely: a hand-edited file with a bad shape
// keeps the defaults instead of failing the plugin.
import * as z from "zod";
import type { SettingValue } from "convergence";
import { allPresets, chosen, duplicate, STOCK } from "./presets.ts";
import type { Preset, ThemeSettings } from "./presets.ts";

export { allPresets, chosen, duplicate, STOCK };
export type { Preset, ThemeSettings };

const presetSchema = z.object({
  name: z.string(),
  mode: z.enum(["light", "dark"]),
  tokens: z.record(z.string(), z.unknown()),
});

/** The settings, with anything malformed dropped. */
export function readSettings(values: Readonly<Record<string, SettingValue>>): ThemeSettings {
  const presets: Record<string, Omit<Preset, "id" | "stock">> = {};
  const rawPresets = z.record(z.string(), z.unknown()).safeParse(values["presets"]);
  for (const [id, raw] of Object.entries(rawPresets.success ? rawPresets.data : {})) {
    const parsed = presetSchema.safeParse(raw);
    if (parsed.success) presets[id] = parsed.data as Omit<Preset, "id" | "stock">;
  }
  const active = z.object({ light: z.string().optional(), dark: z.string().optional() }).safeParse(values["active"]);
  return { presets, active: active.success ? active.data : {} };
}

Versions

VersionPublishedPlugin APISizePermissionsStatus
0.3.0latestOct 5, 2026>=2 <37.9 KB1 permissionListed

Reviews and comments

0 threads · 0 reviews

No comments yet.