1
0
Files
auto-git-gui/settings.html

410 lines
14 KiB
HTML
Raw Permalink 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="de">
<head>
<meta charset="UTF-8">
<title>Einstellungen</title>
<style>
/* Grund-Reset */
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
/* Default-Modus: Weißes Panel mit Rosa-Akzenten */
--bg-main: #ffe4e6; /* Hintergrund Content */
--bg-sidebar: #fff1f2; /* Sidebar */
--accent: #9f1239; /* Rosa */
--border: #fff;
}
body.theme-sky {
/* Sky-Mode: Himmelshintergrund und passende Akzente */
--bg-main: rgb(173,216,230); /* sanftes Baby-Blau */
--bg-sidebar: rgb(200,220,240); /* etwas dunkleres Blau */
--accent: rgb(20,60,100); /* dunkles Marine-Blau als Akzent */
--border: rgb(180,200,220);
background: var(--border);
}
body.theme-grey {
--bg-main: #f5f5f5;
--bg-sidebar: #eceff1;
--accent: #374151;
--border: #d1d5db;
background: var(--bg-main);
}
html, body {
width: 100%; height: 100%;
overflow-x: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
transition: background 0.5s ease;
}
/* Sky-Mode Hintergrund */
body {
background: var(--bg-main);
}
/* Dialog-Box */
.dialog {
position: relative;
z-index: 10;
width: 100%;
color: var(--accent);
background: rgba(255,255,255,0.93);
border-radius: 5px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
padding: 1.8rem 1.8rem;
display: flex; flex-direction: column; gap: 1.2rem;
}
/* Optionen */
.options { display: flex; flex-direction: column; gap: 1.0rem; }
label {
display: flex; align-items: center; font-size: 0.9rem;
color: #1e293b;
}
label.option input[type="checkbox"] {
margin-right: 0.8rem;
width: 1.3em;
height: 1.3em;
accent-color: var(--accent);
flex-shrink: 0; /* <-- das ist wichtig! */
}
.row {
display: flex; align-items: center; justify-content: space-between;
}
.row > span {
flex: 1;
color: #1e293b;
font-weight: 600;
}
.row > input,
.row > select {
/* wenn Du es schmaler willst: */
min-width: 80px;
max-width: 180px;
padding: 0.4em 0.4em;
border: 1.2px solid #cbd5e1;
border-radius: 6px;
background: #f8fafc;
color: #334155;
font-size: 0.9rem;
transition: border-color 0.2s, box-shadow 0.2s;
}
.row > input:focus,
.row > select:focus {
box-shadow: 0 0 0 2px rgba(56,189,248,0.3);
outline: none;
}
select, input[type="number"] {
min-width: 30px;
max-width: 100%;
padding: 0.4em 0.6em;
border: 1.2px solid #cbd5e1;
border-radius: 6px;
font-size: 1rem;
color: #334155;
background: #f8fafc;
margin-left: 0.8rem;
margin-right: 0.8rem;
}
/* Buttons */
.buttons {
display: flex;
justify-content: flex-end;
gap: 0.5em;
}
button{
border-radius: 8px;
padding: 0.5em 1.2em;
display: flex;
align-items: center;
border: none;
cursor: pointer;
background: var(--bg-sidebar);
color: var(--accent);
}
button:hover{
background: var(--bg-border);
}
/* Infotext */
#ollama-model-selectors label {
display: flex;
align-items: center;
gap: 0.6em;
margin-bottom: 0.3em;
}
#ollama-model-selectors select {
min-width: 100px;
max-width: 180px;
padding: 0.35em 0.5em;
border-radius: 6px;
font-size: 1rem;
border: 1.2px solid #cbd5e1;
background: #f8fafc;
color: #334155;
}
.needs-relocation {
opacity: 0.4;
filter: grayscale(0.8);
/* oder: color: #aaa; oder wie du magst */
}
.warning-icon {
margin-left: 8px;
color: #eab308; /* schönes gelb/orange */
font-size: 1.2em;
vertical-align: middle;
}
</style>
<script src="tauriBridge.js"></script>
<script>
window.addEventListener('DOMContentLoaded', async () => {
const applyThemeClass = (theme) => {
document.body.classList.remove('theme-sky', 'theme-grey');
if (theme === 'sky') document.body.classList.add('theme-sky');
if (theme === 'grey') document.body.classList.add('theme-grey');
};
const VALID_THEMES = ['sky', 'default', 'grey'];
// Elemente holen
const themeSelect = document.getElementById('themeSelect');
const cbSkip = document.getElementById('skipPrompt');
const thresholdInput = document.getElementById('intelligentCommitThresholdInput');
const minutesInput = document.getElementById('intelligentCommitMinutesInput');
const rewordModeSelect = document.getElementById('rewordModeSelect');
const ok = document.getElementById('okBtn');
const cancel = document.getElementById('cancelBtn');
const cbAutostart = document.getElementById('autostart');
const cbCloseToTray = document.getElementById('closeToTray');
const giteaTokenInput = document.getElementById('giteaTokenInput');
const [initialAutostart, initialCloseToTray] = await Promise.all([
window.settingsAPI.getAutostart(),
window.settingsAPI.getCloseToTray()
]);
cbAutostart.checked = initialAutostart;
cbCloseToTray.checked = initialCloseToTray;
// Initialwerte parallel laden
const [initialTheme, initialSkip, initialThreshold, initialMinutes, initialRewordMode] = await Promise.all([
window.settingsAPI.getTheme(),
window.settingsAPI.getSkipPrompt(),
window.electronAPI.getIntelligentCommitThreshold(),
window.electronAPI.getMinutesCommitThreshold(),
window.settingsAPI.getRewordMode()
]);
const fallbackTheme = VALID_THEMES.includes(initialTheme) ? initialTheme : 'sky';
themeSelect.value = fallbackTheme;
applyThemeClass(fallbackTheme);
// Inputs setzen
cbSkip.checked = initialSkip;
thresholdInput.value = initialThreshold;
minutesInput.value = initialMinutes;
rewordModeSelect.value = ['ask', 'auto', 'manual'].includes(initialRewordMode)
? initialRewordMode
: 'ask';
// **Vorschau**: Theme sofort übernehmen
themeSelect.addEventListener('change', async () => {
const val = themeSelect.value || 'default';
await window.settingsAPI.setTheme(val);
applyThemeClass(val);
});
const initialToken = await window.settingsAPI.getGiteaToken();
giteaTokenInput.value = initialToken || '';
// OK: alles final speichern – eine fehlschlagende Einstellung darf die
// anderen nicht blockieren und das Fenster muss sich immer schließen.
ok.addEventListener('click', async () => {
const errors = [];
const safe = async (name, promise) => {
try { await promise; } catch (e) { errors.push(`${name}: ${e}`); }
};
await safe('Skip-Prompt', window.settingsAPI.setSkipPrompt(cbSkip.checked));
await safe('Autostart', window.settingsAPI.setAutostart(cbAutostart.checked));
await safe('Close-to-Tray', window.settingsAPI.setCloseToTray(cbCloseToTray.checked));
await safe('Theme', window.settingsAPI.setTheme(themeSelect.value || fallbackTheme));
await safe('Reword-Mode', window.settingsAPI.setRewordMode(rewordModeSelect.value || 'ask'));
// Threshold speichern (immer Wert aus Feld nehmen!)
let threshold = parseInt(thresholdInput.value, 10);
if (isNaN(threshold)) threshold = 10;
if (threshold < 1) threshold = 1;
if (threshold > 1000) threshold = 1000;
await safe('Commit-Threshold', window.settingsAPI.setIntelligentCommitThreshold(threshold));
let minutes = parseInt(minutesInput.value, 10);
if (isNaN(minutes)) minutes = 10;
if (minutes < 1) minutes = 1;
if (minutes > 1000) minutes = 60;
await safe('Minutes-Threshold', window.settingsAPI.setMinutesCommitThreshold(minutes));
// Dropdowns speichern
const commitSel = document.getElementById('commitModelSelect');
const readmeSel = document.getElementById('readmeModelSelect');
if (commitSel) await safe('Commit-Model', window.settingsAPI.setCommitModel(commitSel.value));
if (readmeSel) await safe('Readme-Model', window.settingsAPI.setReadmeModel(readmeSel.value));
await safe('Gitea-Token', window.settingsAPI.setGiteaToken(giteaTokenInput.value.trim()));
if (errors.length) {
alert('Nicht alle Einstellungen konnten gespeichert werden:\n\n' + errors.join('\n'));
}
window.settingsAPI.close();
});
// Cancel / Close: Theme zurücksetzen, dann schließen
const rollback = async () => {
await window.settingsAPI.setTheme(fallbackTheme);
applyThemeClass(fallbackTheme);
window.settingsAPI.close();
};
cancel.addEventListener('click', rollback);
const container = document.getElementById('ollama-model-selectors');
const res = await window.electronAPI.ollamaList();
if (res.status === 'no-cli') {
container.innerHTML = `
<div style="color:red;font-weight:bold;margin:1em 0;">
Ollama is not reachable. Start Ollama or install it to use the cool stuff !!
</div>`;
return;
}
if (res.status === 'error') {
container.innerHTML = `<div style="color:orange">Error fetching models: ${res.msg}</div>`;
return;
}
// Liste der Modell-Namen extrahieren
const names = [...new Set(res.models.map(m => m.name || m.model).filter(Boolean))];
const qwen = names.filter(n => /^qwen2\.5-coder(:[\w\-.]+)?$/.test(n));
if (!names.length) {
// keine lokalen Modelle → Pull-Buttons für die bisherigen Defaults
container.innerHTML = `
<button id="pullCommitModelBtn" style="margin-bottom:8px;">
ollama pull qwen2.5-coder:7b
</button><br>
<button id="pullReadmeModelBtn">
ollama pull qwen2.5-coder:32b
</button>`;
document.getElementById('pullCommitModelBtn').onclick = async () => {
await window.electronAPI.ollamaPull('qwen2.5-coder:7b');
location.reload();
};
document.getElementById('pullReadmeModelBtn').onclick = async () => {
await window.electronAPI.ollamaPull('qwen2.5-coder:32b');
location.reload();
};
return;
}
// Dropdowns aufbauen
const makeOpts = (arr, sel) =>
arr.map(m => `<option ${m===sel?'selected':''}>${m}</option>`).join('');
// Default-Auswahl aus Settings (oder erstes gefundenes)
const commitDefault = qwen.find(m=>m.includes('7b')) || names[0];
const readmeDefault= qwen.find(m=>m.includes('32b')) || names[0];
const currentCommit = await window.settingsAPI.getCommitModel?.() || commitDefault;
const currentReadme= await window.settingsAPI.getReadmeModel?.() || readmeDefault;
container.innerHTML = `
<div class="row">
<label>Model for commit message generation:
<select id="commitModelSelect">
${makeOpts(names, currentCommit)}
</select>
</label>
<label>Model for README generation:
<select id="readmeModelSelect">
${makeOpts(names, currentReadme)}
</select>
</label>
</div>`;
});
</script>
</head>
<body>
<div class="dialog">
<div class="options">
<label class="option">
<input type="checkbox" id="autostart" />
Launch on System start
</label>
<label class="option">
<input type="checkbox" id="closeToTray" checked />
Close to Tray
</label>
<label class="option" style="align-items:center;">
Theme:
<select id="themeSelect" style="margin-left:1em;">
<option value="sky">SkyMode</option>
<option value="default">Default</option>
<option value="grey">Grey</option>
</select>
</label>
<label class="option" style="align-items:center;">
Reword button:
<select id="rewordModeSelect" style="margin-left:1em;">
<option value="ask">Ask every time</option>
<option value="auto">Automatic (LLM)</option>
<option value="manual">Manual input</option>
</select>
</label>
<label class="option">
<input type="checkbox" id="skipPrompt" class="flex-none" />
Skip prompt asking to remove .git folder if it has only one commit and no changes
</label>
<label class="block mb-2 font-semibold">
Rewrite commits after
<input type="number" id="intelligentCommitThresholdInput" min="1" max="1000" value="10" step="1" class="border rounded px-2 py-1 w-20 mx-1" class="flex-none">
lines of diff or
<input type="number" id="intelligentCommitMinutesInput" min="1" max="1000" value="10" step="1" class="border rounded px-2 py-1 w-20 mx-1" class="flex-none">
minutes have passed
</label>
<div class="options">
<!-- Hier kommt das Model-Selector-HTML rein -->
<div id="ollama-model-selectors"></div>
</div>
<div class="row">
<label class="block mb-2 font-semibold">Gitea API Token:</label>
<input
type="password"
id="giteaTokenInput"
placeholder="Enter your Gitea token…"
class="border rounded px-2 py-1 w-20 mx-1" class="flex-none"
/>
</div>
<!-- Weitere Optionen in Zukunft hier hinzufügen -->
</div>
<div class="buttons">
<button id="cancelBtn" class="text-sm font-medium">
<svg width="18" height="18" viewBox="0 0 20 20" fill="none" class="icon-left">
<path d="M6 6l8 8M6 14L14 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</button>
<button id="okBtn" class="text-sm font-medium">
<svg width="18" height="18" viewBox="0 0 20 20" fill="none" class="icon-left">
<path d="M5 11l4 4L15 7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</button>
</div>
</div>
</body>
</html>