Files
Toolbox/res/html/index.html
T
Yadciel c611b008af Fügt CLI-Toolverwaltung und erweiterte UI-Funktionen hinzu
Ermöglicht die Verwaltung (Erstellen, Auflisten, Ausführen) von Tools über eine Befehlszeilenschnittstelle für Automatisierung und Integration. Die Benutzeroberfläche wurde mit dedizierten Ansichten für Toolerstellung und -bearbeitung, In-App-Lua-Hilfe sowie kontextsensitiven Menüs erweitert. Neue Abhängigkeiten (CLI11, rang) wurden integriert und eine umfassende Testsuite hinzugefügt. Die Lizenzierung wurde auf AGPL-3.0 umgestellt und ein Kontributionsleitfaden bereitgestellt.
2026-07-17 17:22:15 +02:00

301 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Toolbox</title>
<link rel="stylesheet" href="saucer://embedded/html/styles.css">
</head>
<body>
<div id="shell">
<div class="header">
<div class="header-cluster header-left">
<button onclick="getNewContent()" class="button icon-button" id="reload-button">&#x21bb;</button>
</div>
<h1>Toolbox</h1>
<div class="header-cluster header-right">
<div class="button-group">
<button onclick="openCmd()" class="button icon-button" id="cmd-button">&#x1f4bb;</button>
<button onclick="openFileSystem()" id="file-system-button" class="button icon-button">&#x1f4c1;</button>
</div>
<button onclick="openEinstFirst()" class="button icon-button" id="option-button" style="display: none;">&#9881;</button>
<button onclick="toggleGeneralSettings()" class="button icon-button" id="general-settings-button" title="Einstellungen">&#9881;</button>
</div>
</div>
<div class="main" id="toolbox">
<!-- Tool Cards werden hier dynamisch geladen -->
<div class="add-tool-card" onclick="openAddTool()">
<span class="plus-icon">+</span>
</div>
</div>
<div class="footer">
<!--Schmidti.Digital &copy; 2024-->
</div>
</div>
<div id="settings-overlay" class="settings-overlay" hidden>
<div class="settings-panel">
<div class="settings-panel-header">
<h2>Einstellungen</h2>
<button type="button" class="settings-panel-close" onclick="toggleGeneralSettings()">&times;</button>
</div>
<div class="settings-panel-body">
<div class="settings-row">
<div class="settings-row-label">
<span class="settings-row-title">Fenster-Deckkraft</span>
<span class="settings-row-desc">70% bis 100% bei 100% ist das Fenster vollstaendig deckend.</span>
</div>
<div class="settings-row-control">
<input type="range" id="opacity-slider" min="70" max="100" value="100" step="1">
<span id="opacity-value" class="settings-row-value">100%</span>
</div>
</div>
</div>
</div>
</div>
<script src="saucer://embedded/html/tool-runtime.js"></script>
<script>
function getNewContent(){
saucer.exposed.getNewContent();
}
async function runLuaWithId(event) {
event.preventDefault();
if (event.target.closest('button')) {
return false;
}
const toolCard = event.currentTarget;
if (toolCard) {
const toolId = toolCard.getAttribute('data-tool-id');
const toolKey = toolCard.dataset.toolKey;
if (ToolRuntime.isCardRunBlocked(toolCard)) {
console.log(`Button is already disabled for tool ID: ${toolId}`);
return false;
}
try {
const response = JSON.parse(await saucer.exposed.run_lua(toolKey));
if (response.singleInstance === true) {
await loadToolboxItems();
}
} catch (error) {
console.error('Fehler beim Starten des Tools:', error);
}
}
}
function test(){
saucer.exposed.debug_print();
}
function openFileSystem() {
saucer.exposed.open_file_system();
}
function openCmd() {
saucer.exposed.open_cmd();
}
function openAddTool() {
saucer.exposed.openAddTool();
}
function createToolCard(item) {
const toolId = String(item.id);
const card = document.createElement('div');
card.className = 'tool-card';
card.dataset.url = String(item.url || '');
card.dataset.toolId = toolId;
card.dataset.toolKey = String(item.path || '');
card.addEventListener('click', runLuaWithId);
card.addEventListener('contextmenu', showContextMenu);
const icon = document.createElement('img');
const iconData = typeof item.icon === 'string' ? item.icon : '';
icon.src = iconData.startsWith('data:image/png;base64,')
? iconData
: `data:image/png;base64,${iconData}`;
icon.alt = String(item.name || '');
const info = document.createElement('div');
info.className = 'tool-info';
const name = document.createElement('h3');
name.textContent = String(item.name || '');
const description = document.createElement('p');
description.textContent = String(item.description || '');
const action = document.createElement('div');
action.className = 'tool-action';
const settingsButton = document.createElement('button');
settingsButton.type = 'button';
settingsButton.textContent = '⚙';
settingsButton.title = 'Tool bearbeiten';
settingsButton.setAttribute('aria-label', 'Tool bearbeiten');
settingsButton.addEventListener('click', event => {
openEinst(event, card.dataset.toolKey);
});
const runningStatus = document.createElement('span');
runningStatus.className = 'tool-running-status';
runningStatus.textContent = 'Läuft…';
runningStatus.hidden = true;
info.append(name, description);
action.append(runningStatus, settingsButton);
card.append(icon, info, action);
ToolRuntime.applyCardState(card, ToolRuntime.initialRunning(item));
return card;
}
function renderToolboxItems(items) {
const toolbox = document.getElementById('toolbox');
toolbox.querySelectorAll('.tool-card').forEach(card => card.remove());
const cards = document.createDocumentFragment();
items.forEach(item => cards.appendChild(createToolCard(item)));
toolbox.insertBefore(cards, toolbox.querySelector('.add-tool-card'));
}
function loadToolboxItems() {
return saucer.exposed.getToolboxItems()
.then(jsonString => {
const items = JSON.parse(jsonString);
renderToolboxItems(Array.isArray(items) ? items : []);
})
.catch(error => console.error('Fehler beim Abrufen der Toolbox-Elemente:', error));
}
function reloadContent() {
loadToolboxItems();
}
function setToolRunningByPath(toolKey, running) {
const card = Array.from(document.querySelectorAll('.tool-card'))
.find(candidate => candidate.dataset.toolKey === toolKey);
ToolRuntime.applyCardState(card, running);
}
function openEinst(event, toolPath){
if (event) {
event.stopPropagation();
event.preventDefault();
}
console.log('Einst Button geklickt!');
saucer.exposed.openEinst(toolPath);
}
function openEinstFirst(){
const firstCard = document.querySelector('.tool-card');
if (!firstCard) {
return;
}
saucer.exposed.openEinst(firstCard.dataset.toolKey);
}
let activeContextMenu = null;
function closeContextMenu() {
if (activeContextMenu) {
activeContextMenu.remove();
activeContextMenu = null;
}
}
function showContextMenu(event) {
event.preventDefault();
event.stopPropagation();
closeContextMenu();
const card = event.currentTarget;
const toolKey = card.dataset.toolKey;
const toolName = card.querySelector('h3')?.textContent || 'dieses Tool';
const menu = document.createElement('div');
menu.className = 'context-menu';
const editBtn = document.createElement('button');
editBtn.type = 'button';
editBtn.textContent = 'Bearbeiten';
editBtn.addEventListener('click', () => {
closeContextMenu();
openEinst(null, toolKey);
});
const deleteBtn = document.createElement('button');
deleteBtn.type = 'button';
deleteBtn.textContent = 'Löschen';
deleteBtn.className = 'context-menu-danger';
deleteBtn.addEventListener('click', () => {
closeContextMenu();
confirmDeleteTool(toolKey, toolName);
});
menu.append(editBtn, deleteBtn);
document.body.append(menu);
activeContextMenu = menu;
const mx = Math.min(event.clientX, window.innerWidth - 180);
const my = Math.min(event.clientY, window.innerHeight - 90);
menu.style.left = mx + 'px';
menu.style.top = my + 'px';
}
async function confirmDeleteTool(toolKey, toolName) {
if (!confirm(`"${toolName}" wirklich löschen?`)) {
return;
}
try {
const response = JSON.parse(await saucer.exposed.deleteTool(toolKey));
if (response.success) {
await loadToolboxItems();
} else {
alert(response.message || 'Löschen fehlgeschlagen.');
}
} catch (error) {
console.error('Fehler beim Löschen:', error);
alert('Löschen fehlgeschlagen.');
}
}
document.addEventListener('click', closeContextMenu);
let settingsOverlayVisible = false;
let currentOpacity = 100;
function toggleGeneralSettings() {
const overlay = document.getElementById('settings-overlay');
settingsOverlayVisible = !settingsOverlayVisible;
overlay.hidden = !settingsOverlayVisible;
if (settingsOverlayVisible) {
const slider = document.getElementById('opacity-slider');
const valueLabel = document.getElementById('opacity-value');
slider.value = currentOpacity;
valueLabel.textContent = currentOpacity + '%';
}
}
document.addEventListener('DOMContentLoaded', () => {
const slider = document.getElementById('opacity-slider');
const valueLabel = document.getElementById('opacity-value');
slider.addEventListener('input', () => {
const val = parseInt(slider.value, 10);
valueLabel.textContent = val + '%';
currentOpacity = val;
document.getElementById('shell').style.opacity = (val / 100).toString();
});
document.addEventListener('click', (e) => {
const link = e.target.closest('a');
if (link) {
e.preventDefault();
}
}, true);
loadToolboxItems();
});
</script>
</body>
</html>