# Template catalog

Browse 25 real examples from the public catalog and edit a detached copy.

There are **25 templates**: 10 Mermaid, 11 PlantUML and 4 Graphviz / DOT examples. Templates are starting points, not a restriction on the diagram types you can write by hand.

This catalog calls `textDiagramTemplates(locale)` directly, sharing its source with all three editors. Select a template to inspect the real source, then choose Try this template to edit, preview and download a detached copy. This temporary copy never writes to the playground's browser storage.

### templates/catalog.vue

```vue
<script setup lang="ts">
import { computed, onBeforeUnmount, ref } from "vue";
import { QuireButton, QuireSelect } from "@quirekit/ui/vue";
import { createTextDiagram, textDiagramTemplates } from "@quirekit/text-diagram";
import { openTextDiagramDialog, type TextDiagramDialogHandle } from "@quirekit/text-diagram-editor";
import "@quirekit/text-diagram-editor/styles.css";
import { createDiagramSession } from "../recipes/session";
import { exampleText } from "../shared/locale";
import { dialogTheme } from "../shared/theme";

const props = defineProps<{ /** Names and source labels of the unmodified template catalog. */ locale?: string }>();
const t = computed(() => exampleText(props.locale));
const language = ref("mermaid"), selected = ref<string>();
const languages = [{ value: "mermaid", label: "Mermaid" }, { value: "plantuml", label: "PlantUML" }, { value: "dot", label: "Graphviz / DOT" }];
const templates = computed(() => textDiagramTemplates(props.locale).filter(item => item.language === language.value));
const active = computed(() => templates.value.find(item => item.id === selected.value) ?? templates.value[0]!);
const items = computed(() => templates.value.map(item => ({ value: item.id, label: item.label })));
const lifetime = new AbortController();
let dialog: TextDiagramDialogHandle | undefined;

/** Opens a disposable editable copy; the library's template data remains immutable. */
function open(): void {
  dialog?.close();
  const sample = active.value, session = createDiagramSession(createTextDiagram(`template-${sample.id}`, sample.language, sample.source));
  dialog = openTextDiagramDialog({ request: session.capture(), ownerDocument: document, locale: props.locale, theme: dialogTheme(document), signal: lifetime.signal });
}
onBeforeUnmount(() => lifetime.abort());
</script>
<template>
  <section class="template-catalog" :aria-label="t.templates" data-template-catalog data-qk-not-prose>
    <div class="template-catalog__controls">
      <QuireSelect v-model="language" :items="languages" :label="t.language" width="170px" />
      <QuireSelect :model-value="active.id" :items="items" :label="t.template" width="190px" @update:model-value="selected = $event" />
      <QuireButton variant="outline" @click="open">{{ t.try }}</QuireButton>
    </div>
    <p>{{ t.selected }}</p>
    <ul><li v-for="item in templates" :key="item.id">{{ item.label }}</li></ul>
    <pre :aria-label="t.original">{{ active.source }}</pre>
  </section>
</template>
<style scoped>
.template-catalog { display:grid;gap:16px;min-width:0;padding:20px; }
.template-catalog__controls { display:flex;gap:12px;align-items:center;flex-wrap:wrap; }
p { margin:0;font-size:13px;color:var(--qk-color-text-secondary); }
ul { margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;font-size:13px;padding-inline-start:20px; }
pre { margin:0;padding:16px;max-height:380px;overflow:auto;background:var(--qk-color-surface-subtle);font-size:12px; }
</style>

```

### recipes/session.ts

```ts
import { readTextDiagram, serializeTextDiagram, type TextDiagramEmbed } from "@quirekit/text-diagram";
import type { DiagramSession } from "../shared/types";

/**
 * Creates a single-object host with compare-and-save semantics.
 * @param initial - Validated persisted object or new draft.
 * @param persist - Optional synchronous storage write; throwing leaves the baseline unchanged.
 * @returns A host whose requests cannot overwrite a newer accepted revision.
 */
export function createDiagramSession(initial: TextDiagramEmbed, persist?: (next: TextDiagramEmbed) => void): DiagramSession {
  let current = readTextDiagram(initial);
  return {
    /** @returns The immutable accepted revision. */
    read() { return current; },
    /** @returns A detached baseline with explicit commit and release callbacks. */
    capture() {
      const baseline = current, expected = serializeTextDiagram(baseline);
      let released = false;
      return {
        document: baseline,
        /** @param proposal - Source and preview proposed by the workbench. @returns Atomic host acceptance. */
        commit(proposal) {
          if (released) return "missing";
          if (serializeTextDiagram(current) !== expected) return "conflict";
          const next = readTextDiagram(proposal);
          if (next.id !== baseline.id || next.document.revision !== baseline.document.revision + 1 || !next.preview) {
            throw new TypeError("Invalid diagram save");
          }
          // Storage must succeed before publishing the new revision to the UI.
          persist?.(next);
          current = next;
          return "saved";
        },
        /** Closes this target without changing the accepted object. */
        release() { released = true; },
      };
    },
  };
}

```

### shared/types.ts

```ts
import type { TextDiagramEditRequest, TextDiagramEmbed, TextDiagramSnapshot, TextDiagramRaster } from "@quirekit/text-diagram";

/** Minimal synchronous host; durable storage belongs to its caller. */
export interface DiagramSession {
  /** @returns The last accepted immutable object. */
  read(): TextDiagramEmbed;
  /** @returns A new edit request capturing the current baseline. */
  capture(): TextDiagramEditRequest;
}

/** Two output formats generated from exactly the same source. */
export interface DiagramFiles {
  /** Sanitized vector snapshot. */
  readonly vector: TextDiagramSnapshot;
  /** Bounded PNG projection. */
  readonly raster: TextDiagramRaster;
}

```

### shared/locale.ts

```ts
/** @param locale - Host interface language. @returns Demonstration labels; source is never translated. */
export function exampleText(locale = "zh-CN") {
  return locale.startsWith("en") ? {
    saved: "Saved in this browser", restored: "Restored the last saved diagram", cancelled: "Draft cancelled; showing the last saved version",
    unsaved: "No saved diagram yet", storage: "The saved diagram could not be read. You can edit a new draft; saving will replace that local entry.",
    persistence: "Save diagram stores the source and PNG in this browser. Unsaved edits are discarded when you leave this page.",
    result: "Last saved Markdown", json: "Download saved JSON", revision: "Revision", open: "Open diagram editor",
    close: "Editor closed", memory: "This dialog example keeps accepted changes until you leave the page.",
    templates: "Template catalog", language: "Language", template: "Template", try: "Try this template",
    original: "Template source", selected: "The dialog uses a detached copy; the template stays unchanged.",
  } : {
    saved: "已保存到当前浏览器", restored: "已恢复上次保存的图形", cancelled: "草稿已取消，已回到上次保存的版本",
    unsaved: "尚未保存图形", storage: "无法读取已保存的图形。可以编辑新草稿；保存将替换这一条本地记录。",
    persistence: "“保存图形”将源码与 PNG 保存在当前浏览器。离开本页会丢弃尚未保存的修改。",
    result: "上次保存的 Markdown", json: "下载已保存 JSON", revision: "修订号", open: "打开绘图编辑器",
    close: "编辑器已关闭", memory: "此弹窗示例在离开页面前保留已保存的修改。",
    templates: "模板目录", language: "绘图语言", template: "模板", try: "试用这个模板",
    original: "模板源码", selected: "弹窗使用独立副本，不会修改原模板。",
  };
}

```

### shared/theme.ts

```ts
import { createTheme, type QuireKitTheme } from "@quirekit/ui";

/** @param owner - Document with a host-controlled CSS color scheme. @returns Theme snapshot for an independent dialog root. */
export function dialogTheme(owner: Document): QuireKitTheme {
  const scheme = owner.defaultView!.getComputedStyle(owner.documentElement).colorScheme;
  return createTheme({ scheme: scheme === "dark" ? "dark" : "light" });
}

```

## Included examples

- Mermaid: flowchart, sequence, mind map, class, state, entity relationship, Gantt, pie, user journey and Git graph.
- PlantUML: sequence, class, activity, use case, component, state, deployment, object, entity relationship, mind map and work breakdown.
- DOT: directed graph, undirected graph, clustered architecture and dependency graph.

`id` is stable. `label` and human-readable labels inside sample source follow the requested language. Changing the interface language never rewrites an open draft. The shared workbench replaces source only after an explicit Apply template action, which can be undone.

## Syntax and engines

Explore the [Mermaid documentation](https://mermaid.js.org/intro/), [PlantUML documentation](https://plantuml.com/) and [Graphviz documentation](https://graphviz.org/documentation/) for language syntax. Upstream features are not automatically enabled in this browser build, especially external resources and optional PlantUML libraries. This integration's [support boundaries](/en/reference/support) take precedence.
