diff --git a/.gitignore b/.gitignore index 2127592..1c26641 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ data.json # Exclude macOS Finder (System Explorer) View States .DS_Store + +main.js diff --git a/main.js b/main.js deleted file mode 100644 index ade69b2..0000000 --- a/main.js +++ /dev/null @@ -1,403 +0,0 @@ -/* -THIS IS A GENERATED/BUNDLED FILE BY ESBUILD -if you want to view the source, please visit the github repository of this plugin -*/ - -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// src/main.ts -var main_exports = {}; -__export(main_exports, { - default: () => PromptCrafterPlugin -}); -module.exports = __toCommonJS(main_exports); -var import_obsidian5 = require("obsidian"); - -// src/pcBlock.ts -var import_obsidian4 = require("obsidian"); - -// src/prompt-resolver.ts -var import_obsidian = require("obsidian"); - -// src/markdown-leveler.ts -function relevelMarkdownHeaders(markdown, targetBaseLevel) { - const lines = markdown.split("\n"); - let adjustedMarkdown = ""; - let minCurrentLevel = Infinity; - lines.forEach((line) => { - const match = line.match(/^(#+)/); - if (match) { - const level = match[0].length; - if (level < minCurrentLevel) { - minCurrentLevel = level; - } - } - }); - const levelOffset = targetBaseLevel - minCurrentLevel; - lines.forEach((line) => { - const match = line.match(/^(#+)(\s+.*)/); - if (match) { - let newLevel = match[1].length + levelOffset; - if (newLevel < 1) - newLevel = 1; - if (newLevel > 6) { - const boldText = `**${newLevel - 6}. ${match[2].trim()}**`; - adjustedMarkdown += boldText + "\n"; - } else { - const newHeader = `${"#".repeat(newLevel)}${match[2]}`; - adjustedMarkdown += newHeader + "\n"; - } - } else { - adjustedMarkdown += line + "\n"; - } - }); - return adjustedMarkdown.trim(); -} -function computePlaceHoldersMarkdownLevel(markdown) { - const lines = markdown.split("\n"); - let currentLevel = 0; - let result = {}; - lines.forEach((line) => { - const headerMatch = line.match(/^(#+)/); - if (headerMatch) { - currentLevel = headerMatch[0].length; - } - const placeholderMatches = [...line.matchAll(new RegExp(PLACEHOLDER_REGEX, "g"))]; - placeholderMatches.forEach((match) => { - const placeholderName = match[1]; - if (placeholderName && !(placeholderName in result)) { - result[placeholderName] = currentLevel; - } - }); - if (!headerMatch && !line.trim().startsWith("{{")) { - currentLevel = 0; - } - }); - return result; -} - -// src/prompt.ts -var PLACEHOLDER_REGEX = "\\{\\{([\\w-]+)\\}\\}"; -var Prompt = class { - constructor(template, filepath, section = void 0) { - this.template = template; - this.filepath = filepath; - this.section = section; - } - remplacePlaceholders(variables) { - const placeholdersLevels = computePlaceHoldersMarkdownLevel(this.template); - return this.template.replace(new RegExp(PLACEHOLDER_REGEX, "g"), (match, variableName) => { - if (!variables.hasOwnProperty(variableName)) { - throw new Error(`Variable '${variableName}' not found`); - } - const placeholderLevel = placeholdersLevels[variableName]; - const markdown = variables[variableName]; - return relevelMarkdownHeaders(markdown, placeholderLevel + 1); - }); - } - isEqual(other) { - return this.filepath === other.filepath && this.section === other.section; - } - getPromptId() { - return !!this.section ? `${this.filepath}#${this.section}` : this.filepath; - } -}; - -// src/pc-block-utils.ts -function getCodeBloc(content) { - const regex = /^\s*```(\w*)\n([\s\S]*?)\n```\s*$/; - const correspondance = content.match(regex); - if (correspondance) { - return { - content: correspondance[2].trim(), - blocType: correspondance[1] === "" ? void 0 : correspondance[1] - }; - } - return void 0; -} -function removeFrontmatter(content) { - const regex = /^---[\s\S]+?---\n?/; - return content.replace(regex, ""); -} - -// src/prompt-resolver.ts -var PromptResolver = class { - constructor(app, promptHistory = []) { - this.app = app; - this.promptHistory = promptHistory; - } - async resolvePrompt(prompt, sourceFile) { - const newPromptHistory = this.promptHistory.concat(prompt); - if (this.promptHistory.some((p) => p.isEqual(prompt))) { - const chainDescription = newPromptHistory.map((p) => { - if (p.isEqual(prompt)) { - return `*${p.getPromptId()}*`; - } - return p.getPromptId(); - }).join(" -> "); - throw new Error(`Circular reference detected: ${chainDescription}`); - } - const file = this.app.vault.getAbstractFileByPath(sourceFile); - const variables = {}; - if (!(file instanceof import_obsidian.TFile)) { - throw new Error("no instance of TFile"); - } - const fileCache = this.app.metadataCache.getFileCache(file); - if (!fileCache) { - throw new Error("Aucun cache de fichier trouv\xE9."); - } - const frontmatter = fileCache.frontmatter || {}; - for (const key in frontmatter) { - const linktext = frontmatter[key]; - const linkTargetContent = await this.determineVariableValue(linktext, file.path); - if (!linkTargetContent) { - variables[key] = linktext; - } else { - const withoutFrontmatter = removeFrontmatter(linkTargetContent.content); - const codeBlock = getCodeBloc(withoutFrontmatter); - if (codeBlock) { - if (codeBlock.blocType === BLOCK_NAME) { - const newPrompt = new Prompt( - codeBlock.content, - linkTargetContent.filepath, - linkTargetContent.section - ); - const promptResolver = new PromptResolver(this.app, newPromptHistory); - variables[key] = await promptResolver.resolvePrompt(newPrompt, linkTargetContent.filepath); - } else { - variables[key] = codeBlock.content; - } - } else { - variables[key] = withoutFrontmatter; - } - } - } - return prompt.remplacePlaceholders(variables); - } - async determineVariableValue(linktext, mainfilePath) { - const parsed = this.parseLinktext(linktext); - if (!parsed) { - return void 0; - } - const { path, subpath } = parsed; - const destFile = this.app.metadataCache.getFirstLinkpathDest(path, mainfilePath); - if (!destFile) { - throw new Error(`File '${path}' not found`); - } - const linkedFile = this.app.vault.getAbstractFileByPath(destFile.path); - if (!(linkedFile instanceof import_obsidian.TFile)) { - throw new Error("no instance of TFile"); - } - let content = await this.app.vault.read(linkedFile); - let result; - if (subpath) { - result = this.extractSectionContent(content, subpath); - } else { - result = content; - } - return { - content: result, - filepath: destFile.path, - section: subpath - }; - } - parseLinktext(linktext) { - const match = linktext.match(/\[\[([^\]]+?)(#([^#]+?))?\]\]/); - if (match) { - const linkAndLabel = match[1].split("|"); - return { path: linkAndLabel[0], subpath: match[3] }; - } - return void 0; - } - extractSectionContent(content, subpath) { - const lines = content.split("\n"); - let sectionContent = ""; - let inSection = false; - let currentLevel = 0; - for (const line of lines) { - const headerMatch = line.match(/^(#+)\s+(.*)/); - if (headerMatch) { - const level = headerMatch[1].length; - const title = headerMatch[2].trim(); - if (inSection && level <= currentLevel) { - break; - } - if (title === subpath) { - inSection = true; - currentLevel = level; - continue; - } - } - if (inSection) { - sectionContent += line + "\n"; - } - } - return sectionContent.trim(); - } -}; - -// src/CopyPromptModal.ts -var import_obsidian2 = require("obsidian"); -var CopyPromptModal = class extends import_obsidian2.Modal { - constructor(app, prompt, onSubmit) { - super(app); - this.onSubmit = onSubmit; - this.prompt = prompt; - } - onOpen() { - const { contentEl } = this; - contentEl.createEl("h1", { text: "Prompt" }); - const textarea = contentEl.createEl("textarea", { - attr: { - style: "width: 100%; box-sizing: border-box; margin-bottom: 20px;" - // Assure que le textarea prend toute la largeur et ajoute un peu d'espace en dessous - } - }); - textarea.value = this.prompt; - textarea.rows = 10; - const buttonContainer = contentEl.createEl("div", { - attr: { - style: "text-align: right;" - // Alignement du bouton à droite - } - }); - const button = buttonContainer.createEl("button", { text: "Copy" }); - button.addClass("mod-cta"); - button.addEventListener("click", () => { - this.close(); - this.onSubmit(textarea.value); - }); - } - onClose() { - let { contentEl } = this; - contentEl.empty(); - } -}; - -// src/ErrorModal.ts -var import_obsidian3 = require("obsidian"); -var ErrorModal = class extends import_obsidian3.Modal { - constructor(app, message) { - super(app); - this.message = message; - } - onOpen() { - const { contentEl } = this; - const messageEl = contentEl.createEl("p"); - messageEl.setText(this.message); - const okButton = contentEl.createEl("button", { - text: "OK", - cls: "mod-cta" - // Utilise une classe pour ajouter des styles spécifiques si nécessaire - }); - okButton.addEventListener("click", () => { - this.close(); - }); - contentEl.style.display = "flex"; - contentEl.style.flexDirection = "column"; - contentEl.style.alignItems = "center"; - contentEl.style.justifyContent = "center"; - } - onClose() { - const { contentEl } = this; - contentEl.empty(); - } -}; - -// src/pcBlock.ts -var BLOCK_NAME = "pc"; -var PcBlock = class { - constructor(plugin) { - this.plugin = plugin; - this.plugin.registerMarkdownCodeBlockProcessor( - BLOCK_NAME, - async (source, el, ctx) => { - this.blockTgHandler(source, el, ctx); - } - ); - } - async blockTgHandler(source, container, { sourcePath: path }) { - setTimeout(async () => { - const preElement = document.createElement("pre"); - preElement.style.whiteSpace = "pre-wrap"; - const codeElement = document.createElement("code"); - codeElement.textContent = source; - preElement.appendChild(codeElement); - container.appendChild(preElement); - this.addTGMenu(container, source, path); - }, 100); - } - addTGMenu(el, source, sourcePath) { - var _a; - const div = document.createElement("div"); - div.classList.add("plug-tg-tgmenu", "plug-tg-flex", "plug-tg-justify-end"); - const generateSVG = ``; - const button = this.createRunButton("Generate Text", generateSVG); - button.addEventListener("click", async () => { - console.log("trigger"); - try { - const promptResolver = new PromptResolver(this.plugin.app); - let resolvedPrompt = await promptResolver.resolvePrompt(new Prompt(source, sourcePath), sourcePath); - new CopyPromptModal(this.plugin.app, resolvedPrompt, (result) => { - this.copyToClipboard(result); - new import_obsidian4.Notice("Prompt copied to clipboard", 3e3); - }).open(); - } catch (e) { - new ErrorModal(this.plugin.app, e.message).open(); - throw e; - } - }); - div.appendChild(button); - (_a = el.parentElement) == null ? void 0 : _a.appendChild(div); - } - async copyToClipboard(texte) { - try { - await navigator.clipboard.writeText(texte); - console.log("Texte copi\xE9 dans le presse-papier"); - } catch (err) { - console.error("Erreur lors de la copie dans le presse-papier", err); - } - } - createRunButton(label, svg) { - const button = document.createElement("div"); - button.classList.add("clickable-icon"); - button.setAttribute("aria-label", label); - button.innerHTML = svg; - return button; - } -}; - -// src/main.ts -var DEFAULT_SETTINGS = { - mySetting: "default" -}; -var PromptCrafterPlugin = class extends import_obsidian5.Plugin { - async onload() { - await this.loadSettings(); - new PcBlock(this); - } - onunload() { - } - async loadSettings() { - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); - } - async saveSettings() { - await this.saveData(this.settings); - } -}; diff --git a/src/ErrorModal.ts b/src/ErrorModal.ts index dba1cb6..c6be879 100644 --- a/src/ErrorModal.ts +++ b/src/ErrorModal.ts @@ -24,11 +24,8 @@ export class ErrorModal extends Modal { this.close(); }); - // Style optionnel pour améliorer l'apparence - contentEl.style.display = 'flex'; - contentEl.style.flexDirection = 'column'; - contentEl.style.alignItems = 'center'; - contentEl.style.justifyContent = 'center'; + // Ajouter une classe CSS au conteneur pour appliquer les styles définis + contentEl.addClass('error-modal-content'); } onClose() { diff --git a/src/pcBlock.ts b/src/pcBlock.ts index 52abf77..52905c3 100644 --- a/src/pcBlock.ts +++ b/src/pcBlock.ts @@ -14,19 +14,20 @@ export default class PcBlock { this.plugin.registerMarkdownCodeBlockProcessor( BLOCK_NAME, async (source, el, ctx) => { - this.blockTgHandler(source, el, ctx); + this.blockPcHandler(source, el, ctx); } ); } - async blockTgHandler( + async blockPcHandler( source: string, container: HTMLElement, { sourcePath: path }: MarkdownPostProcessorContext ) { setTimeout(async () => { const preElement = document.createElement('pre'); - preElement.style.whiteSpace = 'pre-wrap'; // Garde les sauts de ligne et espaces + + preElement.classList.add('pc-pre'); // Création d'un élément code qui contiendra le texte const codeElement = document.createElement('code'); @@ -38,20 +39,19 @@ export default class PcBlock { // Ajoute l'élément pre au container pour l'affichage container.appendChild(preElement); - this.addTGMenu(container, source, path); + this.addPCMenu(container, source, path); }, 100); } - private addTGMenu( + private addPCMenu( el: HTMLElement, source: string, sourcePath: string ) { const div = document.createElement("div"); - div.classList.add("plug-tg-tgmenu", "plug-tg-flex", "plug-tg-justify-end"); - const generateSVG = ``; + div.classList.add("plug-pc-pcmenu", "plug-pc-flex", "plug-pc-justify-end"); - const button = this.createRunButton("Generate Text", generateSVG); + const button = this.createRunButton("Generate Text"); button.addEventListener("click", async () => { console.log('trigger'); @@ -83,12 +83,91 @@ export default class PcBlock { } } - createRunButton(label: string, svg: string) { + createRunButton(label: string) { + // Création du bouton avec createEl() pour plus de sécurité const button = document.createElement("div"); button.classList.add("clickable-icon"); button.setAttribute("aria-label", label); - //aria-label-position="right" - button.innerHTML = svg; + + // Création sécurisée de l'élément SVG + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("viewBox", "0 0 100 100"); + svg.classList.add("svg-icon", "GENERATE_ICON"); + + // Création du groupe principal + const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); + g.setAttribute("id", "Layer_2"); + g.setAttribute("data-name", "Layer 2"); + + // Création du sous-groupe + const vectorGroup = document.createElementNS("http://www.w3.org/2000/svg", "g"); + vectorGroup.setAttribute("id", "VECTOR"); + + // Définir les styles communs + const style = document.createElementNS("http://www.w3.org/2000/svg", "style"); + style.textContent = ".cls-1{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:4px;}"; + svg.appendChild(style); + + // Création de chaque élément SVG + const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.setAttribute("class", "cls-1"); + rect.setAttribute("x", "74.98"); + rect.setAttribute("y", "21.55"); + rect.setAttribute("width", "18.9"); + rect.setAttribute("height", "37.59"); + + const path1 = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path1.setAttribute("class", "cls-1"); + path1.setAttribute("d", "M38.44,27.66a8,8,0,0,0-8.26,1.89L24.8,34.86a25.44,25.44,0,0,0-6,9.3L14.14,56.83C11.33,64.7,18.53,67.3,21,60.9"); + + const polyline1 = document.createElementNS("http://www.w3.org/2000/svg", "polyline"); + polyline1.setAttribute("class", "cls-1"); + polyline1.setAttribute("points", "74.98 25.58 56.61 18.72 46.72 15.45"); + + const path2 = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path2.setAttribute("class", "cls-1"); + path2.setAttribute("d", "M55.45,46.06,42.11,49.43,22.76,50.61c-8.27,1.3-5.51,11.67,4.88,12.8L46.5,65.78,53,68.4a23.65,23.65,0,0,0,17.9,0l6-2.46"); + + const path3 = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path3.setAttribute("class", "cls-1"); + path3.setAttribute("d", "M37.07,64.58v5.91A3.49,3.49,0,0,1,33.65,74h0a3.49,3.49,0,0,1-3.45-3.52V64.58"); + + const path4 = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path4.setAttribute("class", "cls-1"); + path4.setAttribute("d", "M48,66.58v5.68a3.4,3.4,0,0,1-3.34,3.46h0a3.4,3.4,0,0,1-3.34-3.45h0V65.58"); + + const polyline2 = document.createElementNS("http://www.w3.org/2000/svg", "polyline"); + polyline2.setAttribute("class", "cls-1"); + polyline2.setAttribute("points", "28.75 48.05 22.66 59.3 13.83 65.61 14.41 54.5 19.11 45.17"); + + const polyline3 = document.createElementNS("http://www.w3.org/2000/svg", "polyline"); + polyline3.setAttribute("class", "cls-1"); + polyline3.setAttribute("points", "25.17 34.59 43.75 0.25 52.01 5.04 36.39 33.91"); + + const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); + line.setAttribute("class", "cls-1"); + line.setAttribute("x1", "0.25"); + line.setAttribute("y1", "66.92"); + line.setAttribute("x2", "13.83"); + line.setAttribute("y2", "66.92"); + + // Ajout des éléments au groupe vecteur + vectorGroup.appendChild(rect); + vectorGroup.appendChild(path1); + vectorGroup.appendChild(polyline1); + vectorGroup.appendChild(path2); + vectorGroup.appendChild(path3); + vectorGroup.appendChild(path4); + vectorGroup.appendChild(polyline2); + vectorGroup.appendChild(polyline3); + vectorGroup.appendChild(line); + + // Ajout du groupe vecteur au groupe principal + g.appendChild(vectorGroup); + svg.appendChild(g); + + // Ajout de l'élément SVG au bouton + button.appendChild(svg); return button; } diff --git a/src/reference-plugin-code.ts b/src/reference-plugin-code.ts index ca4741b..c821b3a 100644 --- a/src/reference-plugin-code.ts +++ b/src/reference-plugin-code.ts @@ -1,80 +1,32 @@ import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from "obsidian"; -interface MyPluginSettings { - mySetting: string; +interface PromptCrafterSettings { + label: string; } -const DEFAULT_SETTINGS: MyPluginSettings = { - mySetting: 'default' +const DEFAULT_SETTINGS: PromptCrafterSettings = { + label: 'default' } export default class PluginCode extends Plugin { - settings: MyPluginSettings; + settings: PromptCrafterSettings; async onload() { await this.loadSettings(); - // This creates an icon in the left ribbon. - const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => { - // Called when the user clicks the icon. - new Notice('This is a notice!'); - }); - // Perform additional things with the ribbon - ribbonIconEl.addClass('my-plugin-ribbon-class'); - // This adds a status bar item to the bottom of the app. Does not work on mobile apps. const statusBarItemEl = this.addStatusBarItem(); statusBarItemEl.setText('Status Bar Text'); - // This adds a simple command that can be triggered anywhere - this.addCommand({ - id: 'open-sample-modal-simple', - name: 'Open sample modal (simple)', - callback: () => { - new SampleModal(this.app).open(); - } - }); - // This adds an editor command that can perform some operation on the current editor instance - this.addCommand({ - id: 'sample-editor-command', - name: 'Sample editor command', - editorCallback: (editor: Editor, view: MarkdownView) => { - console.log(editor.getSelection()); - editor.replaceSelection('Sample Editor Command'); - } - }); - // This adds a complex command that can check whether the current state of the app allows execution of the command - this.addCommand({ - id: 'open-sample-modal-complex', - name: 'Open sample modal (complex)', - checkCallback: (checking: boolean) => { - // Conditions to check - const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); - if (markdownView) { - // If checking is true, we're simply "checking" if the command can be run. - // If checking is false, then we want to actually perform the operation. - if (!checking) { - new SampleModal(this.app).open(); - } - - // This command will only show up in Command Palette when the check function returns true - return true; - } - } - }); - // This adds a settings tab so the user can configure various aspects of the plugin - this.addSettingTab(new SampleSettingTab(this.app, this)); + this.addSettingTab(new PromptCrafterSettingTab(this.app, this)); // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) // Using this function will automatically remove the event listener when this plugin is disabled. this.registerDomEvent(document, 'click', (evt: MouseEvent) => { console.log('click', evt); }); - - // When registering intervals, this function will automatically clear the interval when the plugin is disabled. - this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); } onunload() { @@ -90,24 +42,7 @@ export default class PluginCode extends Plugin { } } - -class SampleModal extends Modal { - constructor(app: App) { - super(app); - } - - onOpen() { - const {contentEl} = this; - contentEl.setText('Woah!'); - } - - onClose() { - const {contentEl} = this; - contentEl.empty(); - } -} - -class SampleSettingTab extends PluginSettingTab { +class PromptCrafterSettingTab extends PluginSettingTab { plugin: PluginCode; constructor(app: App, plugin: PluginCode) { @@ -125,9 +60,9 @@ class SampleSettingTab extends PluginSettingTab { .setDesc('It\'s a secret') .addText(text => text .setPlaceholder('Enter your secret') - .setValue(this.plugin.settings.mySetting) + .setValue(this.plugin.settings.label) .onChange(async (value) => { - this.plugin.settings.mySetting = value; + this.plugin.settings.label = value; await this.plugin.saveSettings(); })); } diff --git a/styles.css b/styles.css index 71cc60f..d62cfc9 100644 --- a/styles.css +++ b/styles.css @@ -6,3 +6,46 @@ available in the app when your plugin is enabled. If your plugin does not need CSS, delete this file. */ + +/* Error Modal */ +.error-modal-content { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; +} + +.mod-cta { + /* Styles spécifiques pour le bouton 'OK' */ + background-color: #007bff; + color: white; + border: none; + padding: 10px 20px; + cursor: pointer; + border-radius: 4px; +} + +.mod-cta:hover { + background-color: #0056b3; +} + + +/* PC Block */ + +/* Style pour les éléments 'pre' dans le bloc 'pc' */ +.pc-pre { + white-space: pre-wrap; /* Garde les sauts de ligne et espaces */ +} + +/* Autres styles qui pourraient être nécessaires */ +.plug-pc-tgmenu { + /* styles existants pour plug-pc-tgmenu */ +} + +.plug-pc-flex { + display: flex; +} + +.plug-pc-justify-end { + justify-content: flex-end; +}