mirror of
https://github.com/sbuffkin/hexmaker.git
synced 2026-07-22 14:30:24 +00:00
Adds a unified export pipeline under src/export/ with exporters for single notes,
structured hexes, maps (with reference table), random tables, and workflows
(with rolled samples). PDF rendering reuses Obsidian's MarkdownRenderer + theme
CSS; map PNG/PDF goes through a dedicated canvas renderer.
UI surface:
- "Export" tab in MapModal (PNG/PDF with overlay + size options)
- "Export" link in HexEditorModal + HexExportModal
- "Export PDF/Markdown" links in RandomTableView header
- "Export…" button in WorkflowEditorModal + WorkflowExportModal
- Commands: export current note (PDF/MD), current hex, current workflow
- File-menu items on any .md file: Export to PDF / Markdown
Other:
- New `exportFolder` setting (defaults to {worldFolder}/exports)
- hexGeometry: add hexSize / hexCenter / hexPolygonPoints / gridBoundingBox
- HexTableView + HexEditorModal: first-wins on duplicate palette names
(matches HexMapView's .find() behaviour)
- Tests: unit + integration suites for all exporters; sim-vault fixture
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
115 lines
3.7 KiB
TypeScript
115 lines
3.7 KiB
TypeScript
/**
|
|
* Export options modal for a single hex (Phase 1.5).
|
|
*
|
|
* Currently exposes file name + GM-sections toggle + format buttons. The
|
|
* architecture is set up to grow: future options (per-section toggles,
|
|
* "include related random tables", linked-note expansions, etc.) slot in as
|
|
* new rows in `renderOptions`. The orchestrator wires those toggles into
|
|
* `SingleHexExportOptions` without needing structural changes.
|
|
*/
|
|
|
|
import { App, TFile } from "obsidian";
|
|
import { HexmakerModal } from "../HexmakerModal";
|
|
import type HexmakerPlugin from "../HexmakerPlugin";
|
|
import {
|
|
exportHexAsPdf,
|
|
exportHexAsMarkdown,
|
|
} from "../export/exporters/singleHex";
|
|
|
|
export class HexExportModal extends HexmakerModal {
|
|
constructor(
|
|
app: App,
|
|
private plugin: HexmakerPlugin,
|
|
private hexFile: TFile,
|
|
private defaultName?: string,
|
|
) {
|
|
super(app);
|
|
}
|
|
|
|
onOpen(): void {
|
|
this.titleEl.setText(`Export hex: ${this.hexFile.basename}`);
|
|
this.makeDraggable();
|
|
this.render();
|
|
}
|
|
|
|
private render(): void {
|
|
const { contentEl } = this;
|
|
contentEl.empty();
|
|
contentEl.addClass("duckmage-hex-export-modal");
|
|
|
|
const baseName = this.defaultName ?? this.hexFile.basename;
|
|
|
|
contentEl.createEl("p", {
|
|
cls: "duckmage-export-tab-hint",
|
|
text: "Export this hex as a structured PDF or Markdown file. Each section is rendered as its own block with generous spacing.",
|
|
});
|
|
|
|
const optsForm = contentEl.createDiv({ cls: "duckmage-export-tab-options" });
|
|
|
|
// File name
|
|
const nameRow = optsForm.createDiv({ cls: "duckmage-export-tab-row" });
|
|
nameRow.createEl("label", {
|
|
text: "File name",
|
|
cls: "duckmage-export-tab-label",
|
|
});
|
|
const nameInput = nameRow.createEl("input", {
|
|
type: "text",
|
|
cls: "duckmage-export-tab-text",
|
|
attr: { placeholder: baseName },
|
|
});
|
|
nameInput.value = baseName;
|
|
|
|
// Include-GM toggle. Default OFF — GM-only sections should be opt-in.
|
|
const gmRow = optsForm.createDiv({ cls: "duckmage-export-tab-row" });
|
|
const gmCb = gmRow.createEl("input", {
|
|
type: "checkbox",
|
|
cls: "duckmage-export-tab-checkbox",
|
|
});
|
|
gmCb.checked = false;
|
|
/* eslint-disable obsidianmd/ui/sentence-case -- GM is an acronym; Hidden/Secret are section names */
|
|
gmRow.createEl("label", {
|
|
text: "Include GM-only sections (Hidden, Secret)",
|
|
cls: "duckmage-export-tab-label",
|
|
});
|
|
/* eslint-enable obsidianmd/ui/sentence-case */
|
|
gmRow.addEventListener("click", (e) => {
|
|
if (e.target instanceof HTMLInputElement) return;
|
|
gmCb.checked = !gmCb.checked;
|
|
});
|
|
|
|
// Live filename preview
|
|
const preview = contentEl.createDiv({ cls: "duckmage-export-tab-preview" });
|
|
const buildStem = (): string =>
|
|
nameInput.value.trim() || baseName;
|
|
const updatePreview = () => {
|
|
preview.setText(`Output: ${buildStem()}.pdf / ${buildStem()}.md`);
|
|
};
|
|
nameInput.addEventListener("input", updatePreview);
|
|
updatePreview();
|
|
|
|
// Action buttons
|
|
const actions = contentEl.createDiv({ cls: "duckmage-export-tab-actions" });
|
|
const pdfBtn = actions.createEl("button", {
|
|
cls: "mod-cta",
|
|
text: "Export PDF",
|
|
});
|
|
pdfBtn.addEventListener("click", () => {
|
|
void exportHexAsPdf(this.plugin, this.hexFile, {
|
|
outputName: buildStem(),
|
|
includeGmSections: gmCb.checked,
|
|
});
|
|
this.close();
|
|
});
|
|
const mdBtn = actions.createEl("button", {
|
|
cls: "mod-cta",
|
|
text: "Export Markdown",
|
|
});
|
|
mdBtn.addEventListener("click", () => {
|
|
void exportHexAsMarkdown(this.plugin, this.hexFile, {
|
|
outputName: buildStem(),
|
|
includeGmSections: gmCb.checked,
|
|
});
|
|
this.close();
|
|
});
|
|
}
|
|
}
|