Skip to content

Commit be01854

Browse files
mikolajruraclaude
andcommitted
feat: add command palette modal for SMILES input
Opens a floating modal via Ctrl+P → "Otwórz podgląd molekuły". Live preview renders as you type (300ms debounce) using the same RDKit renderer. Input auto-focused for instant paste. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1a94ecd commit be01854

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

src/main.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Plugin, MarkdownPostProcessorContext } from "obsidian";
22
import { loadRDKit, RDKitModule } from "./rdkit-loader";
33
import { renderMolecule } from "./molecule-renderer";
4+
import { MoleculeModal } from "./molecule-modal";
45

56
export default class MoleculeViewerPlugin extends Plugin {
67
private rdkit: RDKitModule | null = null;
@@ -16,6 +17,15 @@ export default class MoleculeViewerPlugin extends Plugin {
1617
return mod;
1718
});
1819

20+
this.addCommand({
21+
id: "open-molecule-viewer",
22+
name: "Otwórz podgląd molekuły (SMILES)",
23+
callback: async () => {
24+
if (!this.rdkit) await this.rdkitLoading;
25+
new MoleculeModal(this.app, this.rdkit!).open();
26+
},
27+
});
28+
1929
this.registerMarkdownCodeBlockProcessor(
2030
"smiles",
2131
this.processBlock.bind(this)

src/molecule-modal.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { App, Modal } from "obsidian";
2+
import { RDKitModule } from "./rdkit-loader";
3+
import { renderMolecule } from "./molecule-renderer";
4+
5+
export class MoleculeModal extends Modal {
6+
private rdkit: RDKitModule;
7+
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
8+
9+
constructor(app: App, rdkit: RDKitModule) {
10+
super(app);
11+
this.rdkit = rdkit;
12+
}
13+
14+
onOpen() {
15+
const { contentEl } = this;
16+
contentEl.addClass("mol-modal");
17+
18+
const input = contentEl.createEl("input", {
19+
type: "text",
20+
placeholder: "Wklej SMILES…",
21+
cls: "mol-modal-input",
22+
});
23+
24+
const preview = contentEl.createDiv({ cls: "mol-modal-preview" });
25+
26+
input.addEventListener("input", () => {
27+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
28+
this.debounceTimer = setTimeout(() => {
29+
const smiles = input.value.trim();
30+
if (smiles) renderMolecule(smiles, preview, this.rdkit);
31+
else preview.empty();
32+
}, 300);
33+
});
34+
35+
// Focus immediately so user can paste right away
36+
input.focus();
37+
}
38+
39+
onClose() {
40+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
41+
this.contentEl.empty();
42+
}
43+
}

styles.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
/* Molecule Viewer Plugin — dark theme */
22

3+
/* ── Command palette modal ── */
4+
.mol-modal {
5+
padding: 0;
6+
}
7+
8+
.mol-modal-input {
9+
width: 100%;
10+
background: #111;
11+
border: 1px solid #333;
12+
border-radius: 6px;
13+
color: #ddd;
14+
font-family: var(--font-monospace);
15+
font-size: 14px;
16+
padding: 8px 12px;
17+
box-sizing: border-box;
18+
outline: none;
19+
margin-bottom: 12px;
20+
}
21+
22+
.mol-modal-input:focus {
23+
border-color: #555;
24+
}
25+
26+
.mol-modal-preview {
27+
min-height: 200px;
28+
}
29+
330
.mol-container {
431
background: #000000;
532
border-radius: 8px;

0 commit comments

Comments
 (0)