Loading editor/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ add_executable(blogi-editor src/webedit_session.cpp src/webedit_server.cpp src/webedit_api.cpp src/htmlimport.cpp ) if(TARGET blogidev) Loading editor/html/css/editor.css +31 −0 Original line number Diff line number Diff line Loading @@ -618,3 +618,34 @@ dialog label { ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } /* Connection Manager */ .conn-list { max-height: 300px; overflow-y: auto; } .conn-group-header { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; color: var(--text-muted); padding: 0.5em 0.5em 0.2em; letter-spacing: 0.05em; } .conn-item { padding: 0.4em 0.5em; cursor: pointer; border-radius: 4px; font-size: 0.85rem; } .conn-item:hover { background: var(--bg-secondary); } .conn-item.selected { background: var(--accent); color: var(--bg-primary); } editor/html/index.html +156 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,12 @@ <div class="toolbar-group"> <button id="btn-import-xml" data-i18n-title="I18N_TITLE_IMPORT_XML">⬇ <span data-i18n="I18N_IMPORT_XML">Import XML</span></button> <button id="btn-export-xml" data-i18n-title="I18N_TITLE_EXPORT_XML">⬆ <span data-i18n="I18N_EXPORT_XML">Export XML</span></button> <button id="btn-import-html" data-i18n-title="I18N_IMPORT_HTML">⬇ <span data-i18n="I18N_IMPORT_HTML">Import HTML</span></button> <button id="btn-export-html" data-i18n-title="I18N_EXPORT_HTML">⬆ <span data-i18n="I18N_EXPORT_HTML">Export HTML</span></button> <button id="btn-publish" data-i18n-title="I18N_PUBLISH_TITLE">🌐 <span data-i18n="I18N_PUBLISH">Veröffentlichen</span></button> </div> <div class="toolbar-group"> <button id="btn-ai" data-i18n-title="I18N_AI_TITLE">🤖 <span data-i18n="I18N_AI">KI</span></button> </div> <div class="toolbar-group"> <span id="doc-name" class="doc-name">Untitled</span> Loading Loading @@ -110,12 +116,115 @@ </div> </dialog> <dialog id="import-html-dialog"> <h3 data-i18n="I18N_IMPORT_HTML">HTML importieren</h3> <textarea id="import-html-content" rows="15" placeholder="HTML hier einfügen..."></textarea> <div class="dialog-actions"> <button id="btn-import-html-confirm" data-i18n="I18N_IMPORT_HTML">Importieren</button> <button id="btn-import-html-cancel" data-i18n="I18N_CANCEL">Abbrechen</button> </div> </dialog> <dialog id="export-html-dialog"> <h3 data-i18n="I18N_EXPORT_HTML">HTML exportieren</h3> <textarea id="export-html-content" rows="15" readonly></textarea> <div class="dialog-actions"> <button id="btn-export-html-copy" data-i18n="I18N_COPY">Kopieren</button> <button id="btn-export-html-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="connection-manager-dialog" class="settings-dialog"> <div class="set-modal"> <div class="set-sidebar"> <h3 data-i18n="I18N_CONNECTIONS">Verbindungen</h3> <div id="conn-list" class="conn-list"></div> <button id="btn-conn-add" class="set-save-btn" style="margin-top:0.5em;width:100%">+ <span data-i18n="I18N_ADD">Hinzufügen</span></button> </div> <div class="set-content"> <div id="conn-form" style="display:none"> <h4 id="conn-form-title" data-i18n="I18N_CONNECTION">Verbindung</h4> <input type="hidden" id="conn-edit-id" value=""> <div class="set-field"> <label data-i18n="I18N_CONN_GROUP">Gruppe</label> <input type="text" id="conn-group" placeholder=""> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_NAME">Name</label> <input type="text" id="conn-name" placeholder=""> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_URL">URL</label> <input type="text" id="conn-url" placeholder="https://..."> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_API_KEY">API Key</label> <input type="password" id="conn-apikey" placeholder=""> </div> <div class="set-field"> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="conn-ignore-ssl"> <span data-i18n="I18N_IGNORE_SSL">SSL ignorieren</span> </label> </div> <div class="set-field" style="display:flex;gap:0.5em;flex-wrap:wrap"> <button id="btn-conn-save" class="set-save-btn" data-i18n="save">Speichern</button> <button id="btn-conn-test" class="set-save-btn" data-i18n="I18N_TEST_CONNECTION">Testen</button> <button id="btn-conn-publish" class="set-save-btn" data-i18n="I18N_PUBLISH">Veröffentlichen</button> <button id="btn-conn-delete" class="set-save-btn" style="background:#c00" data-i18n="I18N_DELETE">Löschen</button> </div> <span id="conn-status" class="set-status"></span> </div> <div id="conn-placeholder"> <p class="hint" data-i18n="I18N_SELECT_CONNECTION">Verbindung auswählen oder neue hinzufügen.</p> </div> </div> </div> <div class="dialog-actions"> <button id="btn-conn-manager-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="ai-dialog"> <h3 data-i18n="I18N_AI">KI-Assistent</h3> <div class="set-field"> <label data-i18n="I18N_AI_PROMPT">Prompt</label> <textarea id="ai-prompt" rows="5" data-i18n-placeholder="I18N_AI_PROMPT_PLACEHOLDER" placeholder="Beschreibe was die KI generieren soll..."></textarea> </div> <div class="set-field" style="display:flex;gap:1em;align-items:center;flex-wrap:wrap"> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-desktop" checked> <span data-i18n="I18N_AI_DESKTOP">Desktop</span> </label> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-mobile" checked> <span data-i18n="I18N_AI_MOBILE">Mobile</span> </label> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-include-doc"> <span data-i18n="I18N_AI_INCLUDE_DOC">Dokument anhängen</span> </label> </div> <div id="ai-result-container" style="display:none"> <label data-i18n="I18N_AI_RESULT">Ergebnis</label> <textarea id="ai-result" rows="10"></textarea> <div class="set-field" style="display:flex;gap:0.5em;flex-wrap:wrap"> <button id="btn-ai-import" class="set-save-btn" data-i18n="I18N_AI_IMPORT_HTML">Als HTML importieren</button> <button id="btn-ai-copy" class="set-save-btn" data-i18n="I18N_COPY">Kopieren</button> </div> </div> <div id="ai-status" class="set-status"></div> <div class="dialog-actions"> <button id="btn-ai-send" class="set-save-btn" data-i18n="I18N_AI_SEND">An KI senden</button> <button id="btn-ai-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="settings-dialog" class="settings-dialog"> <div class="set-modal"> <div class="set-sidebar"> <h3 data-i18n="Settings">Einstellungen</h3> <ul class="set-nav"> <li class="set-nav-item active" data-section="language" data-i18n="Language">Sprache</li> <li class="set-nav-item" data-section="ai" data-i18n="I18N_AI">KI</li> <li class="set-nav-item" data-section="connection" data-i18n="I18N_CONNECTION">Verbindung</li> </ul> </div> <div class="set-content" id="settings-content"> Loading @@ -134,6 +243,53 @@ <span id="settings-lang-status" class="set-status"></span> </div> </div> <!-- AI section --> <div id="settings-ai" class="set-section" style="display:none"> <h4 data-i18n="I18N_AI">KI</h4> <div class="set-field"> <label data-i18n="I18N_AI_URL">LLM URL</label> <input type="text" id="settings-ai-url" placeholder="http://localhost:11434"> </div> <div class="set-field"> <label data-i18n="I18N_AI_MODEL">Modell</label> <input type="text" id="settings-ai-model" placeholder="llama3"> </div> <div class="set-field"> <label data-i18n="I18N_AI_MAX_TOKENS">Max Tokens</label> <input type="number" id="settings-ai-max-tokens" value="16384" min="1" max="131072"> </div> <div class="set-field"> <label data-i18n="I18N_AI_API_KEY">API Key</label> <input type="password" id="settings-ai-apikey" placeholder=""> </div> <div class="set-field"> <button id="btn-settings-ai-save" class="set-save-btn" data-i18n="save">Speichern</button> <span id="settings-ai-status" class="set-status"></span> </div> </div> <!-- Connection section --> <div id="settings-connection" class="set-section" style="display:none"> <h4 data-i18n="I18N_CONNECTION">Verbindung</h4> <div class="set-field"> <label data-i18n="I18N_BLOG_NAME">Blog Name</label> <input type="text" id="settings-blog-name" placeholder="Mein Blog"> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_URL">Blog URL</label> <input type="text" id="settings-blog-url" placeholder="https://mein-blog.de"> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_API_KEY">API Key</label> <input type="password" id="settings-blog-apikey" placeholder=""> </div> <div class="set-field"> <button id="btn-settings-conn-save" class="set-save-btn" data-i18n="save">Speichern</button> <button id="btn-settings-conn-test" class="set-save-btn" data-i18n="I18N_TEST_CONNECTION">Verbindung testen</button> <span id="settings-conn-status" class="set-status"></span> </div> </div> </div> </div> <div class="dialog-actions"> Loading editor/html/js/api.js +74 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,80 @@ var EditorApi = (function() { return request('POST', '/api/settings/language', { language: language }); }, // AI endpoints getAiSettings: function() { return request('GET', '/api/ai/settings'); }, setAiSettings: function(url, model, maxTokens, apiKey) { return request('POST', '/api/ai/settings', { url: url, model: model, max_tokens: maxTokens, api_key: apiKey }); }, aiPrompt: function(prompt, desktop, mobile, includeDocument) { return request('POST', '/api/ai/prompt', { prompt: prompt, desktop: desktop, mobile: mobile, include_document: includeDocument }); }, // Blog connection endpoints getConnectionSettings: function() { return request('GET', '/api/connection/settings'); }, setConnectionSettings: function(name, url, apiKey) { return request('POST', '/api/connection/settings', { name: name, url: url, api_key: apiKey }); }, testConnection: function() { return request('POST', '/api/connection/test'); }, publish: function() { return request('POST', '/api/connection/publish'); }, // Connection manager listConnections: function() { return request('GET', '/api/connections'); }, saveConnection: function(conn) { return request('POST', '/api/connection/save', conn); }, deleteConnection: function(id) { return request('DELETE', '/api/connection/delete/' + id); }, testConnectionById: function(id) { return request('POST', '/api/connection/test/' + id); }, publishToConnection: function(id) { return request('POST', '/api/connection/publish/' + id); }, // HTML import/export importHtml: function(html) { return request('POST', '/api/document/import-html', { html: html }); }, exportHtml: function() { return request('GET', '/api/document/export-html'); } }; })(); editor/html/js/editor.js +370 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
editor/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ add_executable(blogi-editor src/webedit_session.cpp src/webedit_server.cpp src/webedit_api.cpp src/htmlimport.cpp ) if(TARGET blogidev) Loading
editor/html/css/editor.css +31 −0 Original line number Diff line number Diff line Loading @@ -618,3 +618,34 @@ dialog label { ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } /* Connection Manager */ .conn-list { max-height: 300px; overflow-y: auto; } .conn-group-header { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; color: var(--text-muted); padding: 0.5em 0.5em 0.2em; letter-spacing: 0.05em; } .conn-item { padding: 0.4em 0.5em; cursor: pointer; border-radius: 4px; font-size: 0.85rem; } .conn-item:hover { background: var(--bg-secondary); } .conn-item.selected { background: var(--accent); color: var(--bg-primary); }
editor/html/index.html +156 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,12 @@ <div class="toolbar-group"> <button id="btn-import-xml" data-i18n-title="I18N_TITLE_IMPORT_XML">⬇ <span data-i18n="I18N_IMPORT_XML">Import XML</span></button> <button id="btn-export-xml" data-i18n-title="I18N_TITLE_EXPORT_XML">⬆ <span data-i18n="I18N_EXPORT_XML">Export XML</span></button> <button id="btn-import-html" data-i18n-title="I18N_IMPORT_HTML">⬇ <span data-i18n="I18N_IMPORT_HTML">Import HTML</span></button> <button id="btn-export-html" data-i18n-title="I18N_EXPORT_HTML">⬆ <span data-i18n="I18N_EXPORT_HTML">Export HTML</span></button> <button id="btn-publish" data-i18n-title="I18N_PUBLISH_TITLE">🌐 <span data-i18n="I18N_PUBLISH">Veröffentlichen</span></button> </div> <div class="toolbar-group"> <button id="btn-ai" data-i18n-title="I18N_AI_TITLE">🤖 <span data-i18n="I18N_AI">KI</span></button> </div> <div class="toolbar-group"> <span id="doc-name" class="doc-name">Untitled</span> Loading Loading @@ -110,12 +116,115 @@ </div> </dialog> <dialog id="import-html-dialog"> <h3 data-i18n="I18N_IMPORT_HTML">HTML importieren</h3> <textarea id="import-html-content" rows="15" placeholder="HTML hier einfügen..."></textarea> <div class="dialog-actions"> <button id="btn-import-html-confirm" data-i18n="I18N_IMPORT_HTML">Importieren</button> <button id="btn-import-html-cancel" data-i18n="I18N_CANCEL">Abbrechen</button> </div> </dialog> <dialog id="export-html-dialog"> <h3 data-i18n="I18N_EXPORT_HTML">HTML exportieren</h3> <textarea id="export-html-content" rows="15" readonly></textarea> <div class="dialog-actions"> <button id="btn-export-html-copy" data-i18n="I18N_COPY">Kopieren</button> <button id="btn-export-html-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="connection-manager-dialog" class="settings-dialog"> <div class="set-modal"> <div class="set-sidebar"> <h3 data-i18n="I18N_CONNECTIONS">Verbindungen</h3> <div id="conn-list" class="conn-list"></div> <button id="btn-conn-add" class="set-save-btn" style="margin-top:0.5em;width:100%">+ <span data-i18n="I18N_ADD">Hinzufügen</span></button> </div> <div class="set-content"> <div id="conn-form" style="display:none"> <h4 id="conn-form-title" data-i18n="I18N_CONNECTION">Verbindung</h4> <input type="hidden" id="conn-edit-id" value=""> <div class="set-field"> <label data-i18n="I18N_CONN_GROUP">Gruppe</label> <input type="text" id="conn-group" placeholder=""> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_NAME">Name</label> <input type="text" id="conn-name" placeholder=""> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_URL">URL</label> <input type="text" id="conn-url" placeholder="https://..."> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_API_KEY">API Key</label> <input type="password" id="conn-apikey" placeholder=""> </div> <div class="set-field"> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="conn-ignore-ssl"> <span data-i18n="I18N_IGNORE_SSL">SSL ignorieren</span> </label> </div> <div class="set-field" style="display:flex;gap:0.5em;flex-wrap:wrap"> <button id="btn-conn-save" class="set-save-btn" data-i18n="save">Speichern</button> <button id="btn-conn-test" class="set-save-btn" data-i18n="I18N_TEST_CONNECTION">Testen</button> <button id="btn-conn-publish" class="set-save-btn" data-i18n="I18N_PUBLISH">Veröffentlichen</button> <button id="btn-conn-delete" class="set-save-btn" style="background:#c00" data-i18n="I18N_DELETE">Löschen</button> </div> <span id="conn-status" class="set-status"></span> </div> <div id="conn-placeholder"> <p class="hint" data-i18n="I18N_SELECT_CONNECTION">Verbindung auswählen oder neue hinzufügen.</p> </div> </div> </div> <div class="dialog-actions"> <button id="btn-conn-manager-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="ai-dialog"> <h3 data-i18n="I18N_AI">KI-Assistent</h3> <div class="set-field"> <label data-i18n="I18N_AI_PROMPT">Prompt</label> <textarea id="ai-prompt" rows="5" data-i18n-placeholder="I18N_AI_PROMPT_PLACEHOLDER" placeholder="Beschreibe was die KI generieren soll..."></textarea> </div> <div class="set-field" style="display:flex;gap:1em;align-items:center;flex-wrap:wrap"> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-desktop" checked> <span data-i18n="I18N_AI_DESKTOP">Desktop</span> </label> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-mobile" checked> <span data-i18n="I18N_AI_MOBILE">Mobile</span> </label> <label style="display:flex;align-items:center;gap:0.3em"> <input type="checkbox" id="ai-include-doc"> <span data-i18n="I18N_AI_INCLUDE_DOC">Dokument anhängen</span> </label> </div> <div id="ai-result-container" style="display:none"> <label data-i18n="I18N_AI_RESULT">Ergebnis</label> <textarea id="ai-result" rows="10"></textarea> <div class="set-field" style="display:flex;gap:0.5em;flex-wrap:wrap"> <button id="btn-ai-import" class="set-save-btn" data-i18n="I18N_AI_IMPORT_HTML">Als HTML importieren</button> <button id="btn-ai-copy" class="set-save-btn" data-i18n="I18N_COPY">Kopieren</button> </div> </div> <div id="ai-status" class="set-status"></div> <div class="dialog-actions"> <button id="btn-ai-send" class="set-save-btn" data-i18n="I18N_AI_SEND">An KI senden</button> <button id="btn-ai-close" data-i18n="Close">Schließen</button> </div> </dialog> <dialog id="settings-dialog" class="settings-dialog"> <div class="set-modal"> <div class="set-sidebar"> <h3 data-i18n="Settings">Einstellungen</h3> <ul class="set-nav"> <li class="set-nav-item active" data-section="language" data-i18n="Language">Sprache</li> <li class="set-nav-item" data-section="ai" data-i18n="I18N_AI">KI</li> <li class="set-nav-item" data-section="connection" data-i18n="I18N_CONNECTION">Verbindung</li> </ul> </div> <div class="set-content" id="settings-content"> Loading @@ -134,6 +243,53 @@ <span id="settings-lang-status" class="set-status"></span> </div> </div> <!-- AI section --> <div id="settings-ai" class="set-section" style="display:none"> <h4 data-i18n="I18N_AI">KI</h4> <div class="set-field"> <label data-i18n="I18N_AI_URL">LLM URL</label> <input type="text" id="settings-ai-url" placeholder="http://localhost:11434"> </div> <div class="set-field"> <label data-i18n="I18N_AI_MODEL">Modell</label> <input type="text" id="settings-ai-model" placeholder="llama3"> </div> <div class="set-field"> <label data-i18n="I18N_AI_MAX_TOKENS">Max Tokens</label> <input type="number" id="settings-ai-max-tokens" value="16384" min="1" max="131072"> </div> <div class="set-field"> <label data-i18n="I18N_AI_API_KEY">API Key</label> <input type="password" id="settings-ai-apikey" placeholder=""> </div> <div class="set-field"> <button id="btn-settings-ai-save" class="set-save-btn" data-i18n="save">Speichern</button> <span id="settings-ai-status" class="set-status"></span> </div> </div> <!-- Connection section --> <div id="settings-connection" class="set-section" style="display:none"> <h4 data-i18n="I18N_CONNECTION">Verbindung</h4> <div class="set-field"> <label data-i18n="I18N_BLOG_NAME">Blog Name</label> <input type="text" id="settings-blog-name" placeholder="Mein Blog"> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_URL">Blog URL</label> <input type="text" id="settings-blog-url" placeholder="https://mein-blog.de"> </div> <div class="set-field"> <label data-i18n="I18N_BLOG_API_KEY">API Key</label> <input type="password" id="settings-blog-apikey" placeholder=""> </div> <div class="set-field"> <button id="btn-settings-conn-save" class="set-save-btn" data-i18n="save">Speichern</button> <button id="btn-settings-conn-test" class="set-save-btn" data-i18n="I18N_TEST_CONNECTION">Verbindung testen</button> <span id="settings-conn-status" class="set-status"></span> </div> </div> </div> </div> <div class="dialog-actions"> Loading
editor/html/js/api.js +74 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,80 @@ var EditorApi = (function() { return request('POST', '/api/settings/language', { language: language }); }, // AI endpoints getAiSettings: function() { return request('GET', '/api/ai/settings'); }, setAiSettings: function(url, model, maxTokens, apiKey) { return request('POST', '/api/ai/settings', { url: url, model: model, max_tokens: maxTokens, api_key: apiKey }); }, aiPrompt: function(prompt, desktop, mobile, includeDocument) { return request('POST', '/api/ai/prompt', { prompt: prompt, desktop: desktop, mobile: mobile, include_document: includeDocument }); }, // Blog connection endpoints getConnectionSettings: function() { return request('GET', '/api/connection/settings'); }, setConnectionSettings: function(name, url, apiKey) { return request('POST', '/api/connection/settings', { name: name, url: url, api_key: apiKey }); }, testConnection: function() { return request('POST', '/api/connection/test'); }, publish: function() { return request('POST', '/api/connection/publish'); }, // Connection manager listConnections: function() { return request('GET', '/api/connections'); }, saveConnection: function(conn) { return request('POST', '/api/connection/save', conn); }, deleteConnection: function(id) { return request('DELETE', '/api/connection/delete/' + id); }, testConnectionById: function(id) { return request('POST', '/api/connection/test/' + id); }, publishToConnection: function(id) { return request('POST', '/api/connection/publish/' + id); }, // HTML import/export importHtml: function(html) { return request('POST', '/api/document/import-html', { html: html }); }, exportHtml: function() { return request('GET', '/api/document/export-html'); } }; })();
editor/html/js/editor.js +370 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes