Browse Source

add a menu item

master
Silberengel 1 week ago
parent
commit
966b25b54c
  1. 105
      src/main.ts
  2. 83
      src/ui/newDocumentModal.ts

105
src/main.ts

@ -3,6 +3,7 @@ import { ScriptoriumSettings, EventKind, EventMetadata, DEFAULT_SETTINGS } from @@ -3,6 +3,7 @@ import { ScriptoriumSettings, EventKind, EventMetadata, DEFAULT_SETTINGS } from
import { ScriptoriumSettingTab } from "./ui/settingsTab";
import { MetadataModal } from "./ui/metadataModal";
import { StructurePreviewModal } from "./ui/structurePreviewModal";
import { NewDocumentModal } from "./ui/newDocumentModal";
import { readMetadata, writeMetadata, createDefaultMetadata, validateMetadata, mergeWithHeaderTitle } from "./metadataManager";
import { buildEvents } from "./eventManager";
import { saveEvents, loadEvents, eventsFileExists } from "./eventStorage";
@ -47,6 +48,17 @@ export default class ScriptoriumPlugin extends Plugin { @@ -47,6 +48,17 @@ export default class ScriptoriumPlugin extends Plugin {
callback: () => this.handleEditMetadata(),
});
this.addCommand({
id: "new-nostr-document",
name: "New Nostr Document",
callback: () => this.handleNewDocument(),
});
// Add ribbon icon for creating new documents
this.addRibbonIcon("file-plus", "New Nostr Document", () => {
this.handleNewDocument();
});
// Status bar
this.addStatusBarItem().setText("Scriptorium");
}
@ -316,4 +328,97 @@ export default class ScriptoriumPlugin extends Plugin { @@ -316,4 +328,97 @@ export default class ScriptoriumPlugin extends Plugin {
safeConsoleError("Error editing metadata:", error);
}
}
private async handleNewDocument() {
new NewDocumentModal(this.app, async (kind: EventKind, title: string) => {
try {
// Sanitize filename from title
const sanitizedTitle = this.sanitizeFilename(title);
// Determine file extension based on kind
let extension = "md";
if (kind === 30040 || kind === 30041 || kind === 30818) {
extension = "adoc";
}
// Get current folder or root
const activeFile = this.app.workspace.getActiveFile();
let folderPath = "";
if (activeFile) {
const folder = this.app.vault.getAbstractFileByPath(activeFile.path);
if (folder && folder.parent) {
folderPath = folder.parent.path;
}
}
// Create file path
const filename = `${sanitizedTitle}.${extension}`;
const filePath = folderPath ? `${folderPath}/${filename}` : filename;
// Check if file already exists
const existingFile = this.app.vault.getAbstractFileByPath(filePath);
if (existingFile) {
new Notice(`File ${filename} already exists`);
return;
}
// Create default content based on kind
let content = "";
if (kind === 30040) {
// AsciiDoc document header for 30040
content = `= ${title}\n\n`;
} else if (kind === 30023 || kind === 30817 || kind === 30818) {
// Add title as heading for other kinds that require title
if (kind === 30817 || kind === 30818) {
content = `# ${title}\n\n`;
} else {
content = `# ${title}\n\n`;
}
}
// Create the file
const file = await this.app.vault.create(filePath, content);
// Create metadata
const metadata = createDefaultMetadata(kind);
if (metadata.title === "" && title) {
(metadata as any).title = title;
}
await writeMetadata(file, metadata, this.app);
// Open the new file
await this.app.workspace.openLinkText(filePath, "", true);
new Notice(`Created ${filename} with metadata`);
} catch (error: any) {
const safeMessage = error?.message ? String(error.message).replace(/nsec1[a-z0-9]{58,}/gi, "[REDACTED]").replace(/[0-9a-f]{64}/gi, "[REDACTED]") : "Unknown error";
new Notice(`Error creating document: ${safeMessage}`);
safeConsoleError("Error creating document:", error);
}
}).open();
}
/**
* Sanitize a string to be used as a filename
*/
private sanitizeFilename(title: string): string {
// Remove or replace invalid filename characters
let sanitized = title
.replace(/[<>:"/\\|?*]/g, "-") // Replace invalid chars with dash
.replace(/\s+/g, "-") // Replace spaces with dash
.replace(/-+/g, "-") // Replace multiple dashes with single
.replace(/^-+|-+$/g, ""); // Remove leading/trailing dashes
// Limit length
if (sanitized.length > 100) {
sanitized = sanitized.substring(0, 100);
}
// Ensure it's not empty
if (!sanitized) {
sanitized = "untitled";
}
return sanitized;
}
}

83
src/ui/newDocumentModal.ts

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
import { App, Modal, Setting } from "obsidian";
import { EventKind } from "../types";
import { createDefaultMetadata, writeMetadata } from "../metadataManager";
/**
* Modal for creating a new Nostr document
*/
export class NewDocumentModal extends Modal {
private selectedKind: EventKind;
private title: string;
private onSubmit: (kind: EventKind, title: string) => void;
constructor(app: App, onSubmit: (kind: EventKind, title: string) => void) {
super(app);
this.onSubmit = onSubmit;
this.selectedKind = 1;
this.title = "";
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h2", { text: "Create New Nostr Document" });
// Event kind selection
new Setting(contentEl)
.setName("Event Kind")
.setDesc("Select the type of Nostr event to create")
.addDropdown((dropdown) => {
dropdown
.addOption("1", "1 - Normal Note")
.addOption("11", "11 - Discussion Thread OP")
.addOption("30023", "30023 - Long-form Article")
.addOption("30040", "30040 - Publication Index (AsciiDoc)")
.addOption("30041", "30041 - Publication Content (AsciiDoc)")
.addOption("30817", "30817 - Wiki Page (Markdown)")
.addOption("30818", "30818 - Wiki Page (AsciiDoc)")
.setValue(String(this.selectedKind))
.onChange((value) => {
this.selectedKind = parseInt(value) as EventKind;
});
});
// Title input
new Setting(contentEl)
.setName("Title / Filename")
.setDesc("Enter a title for your document (will be used as filename)")
.addText((text) => {
text.setPlaceholder("My Document Title")
.setValue(this.title)
.onChange((value) => {
this.title = value.trim();
});
text.inputEl.focus();
});
// Buttons
const buttonContainer = contentEl.createDiv({ cls: "scriptorium-modal-buttons" });
const createButton = buttonContainer.createEl("button", {
text: "Create",
cls: "mod-cta",
});
createButton.addEventListener("click", () => {
if (!this.title) {
// Use default title if empty
this.title = "Untitled";
}
this.onSubmit(this.selectedKind, this.title);
this.close();
});
const cancelButton = buttonContainer.createEl("button", { text: "Cancel" });
cancelButton.addEventListener("click", () => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
Loading…
Cancel
Save