hinunher fertig und anderen kram jetyt in die andere richtung
This commit is contained in:
parent
8202d64c13
commit
257331bb5b
5 changed files with 810 additions and 0 deletions
2
.directory
Normal file
2
.directory
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[Desktop Entry]
|
||||
Icon=folder-cyan
|
||||
16
VAULT/aufbeitungsverfahren.md
Normal file
16
VAULT/aufbeitungsverfahren.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
„Aufgebotsverfahren" (manche Ämter schreiben auch „Aufbietungsverfahren" – gleiche Sache, nur unterschiedliche Bezeichnung je nach Bundesland/Behörde) ist ein offizielles Verfahren, mit dem ein fehlendes Kfz-Dokument für ungültig erklärt und durch ein neues ersetzt wird. Bevor ich dir sage, was deine Freundin konkret braucht, muss ich aber kurz einordnen, worum es bei ihr überhaupt geht – denn hier steckt der wichtigste Punkt:
|
||||
|
||||
Es gibt zwei ganz unterschiedliche Dokumente, und nur eins davon braucht das förmliche Aufgebotsverfahren:
|
||||
|
||||
Zulassungsbescheinigung Teil I (früher „Fahrzeugschein", das Papier fürs Handschuhfach) → wenn nur das fehlt: einfache eidesstattliche Versicherung direkt bei der Zulassungsstelle, ca. 22 €, meist in 1–3 Werktagen erledigt. Kein Gericht, kein Aufgebotsverfahren nötig.
|
||||
Zulassungsbescheinigung Teil II (früher „Fahrzeugbrief", der Eigentumsnachweis) → wenn das fehlt: hier greift das eigentliche Aufgebotsverfahren – Meldung bei der Zulassungsstelle, die das Kraftfahrt-Bundesamt einschaltet, Veröffentlichung im Verkehrsblatt, Wartefrist von ca. 14 Tagen, danach Neuausstellung. Dauert insgesamt oft 3–6 Wochen.
|
||||
|
||||
Der Begriff „Fahrzeugschein", den du benutzt, meint eigentlich Teil I – aber bei 1,5 Jahren Wartezeit nach einem Autokauf klingt das für mich nicht nach einem klassischen „ist verloren gegangen"-Fall, sondern eher nach einem hängenden Vorgang beim Verkäufer, Händler oder der Zulassungsstelle. Das ändert, welcher Weg der richtige ist.
|
||||
|
||||
Deshalb brauche ich noch ein paar Infos von dir, um dir die genauen Schritte und Unterlagen zu nennen, statt dir eine pauschale Anleitung zu geben, die am Ende vielleicht am eigentlichen Problem vorbeigeht:
|
||||
|
||||
Welches Dokument fehlt genau – die Zulassungsbescheinigung Teil I (das kleine Scheckkarten-Dokument, das man im Auto mitführt) oder Teil II (der „Brief", der das Eigentum belegt)? Oder beide?
|
||||
Ist das Auto überhaupt schon auf den Namen deiner Freundin zugelassen – hat es ein eigenes Kennzeichen und fährt sie damit?
|
||||
Hat sie das Auto privat oder über einen Händler gekauft, und was sagt der Verkäufer, wenn sie ihn danach fragt?
|
||||
Gibt es einen schriftlichen Kaufvertrag, in dem die Übergabe des Dokuments festgehalten ist?
|
||||
Hat sie in den 1,5 Jahren schon einmal bei der Zulassungsstelle direkt nachgefragt, was der Stand ist?
|
||||
741
VAULT/task-manager.html
Normal file
741
VAULT/task-manager.html
Normal file
|
|
@ -0,0 +1,741 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ADHS-Friendly Task List</title>
|
||||
<style>
|
||||
:root {
|
||||
--lavender: #B8A9C9;
|
||||
--lavender-dark: #9788AD;
|
||||
--blue: #A8D8EA;
|
||||
--blue-dark: #7CB8D0;
|
||||
--yellow: #FFEAA7;
|
||||
--yellow-dark: #FDD835;
|
||||
--purple: #D4A5FF;
|
||||
--purple-dark: #B57EDC;
|
||||
--orange: #FFB4A2;
|
||||
--orange-dark: #E8967E;
|
||||
--white: #FAFAFA;
|
||||
--beige: #F5F0E8;
|
||||
--text-dark: #2D2D2D;
|
||||
--text-light: #F5F5F5;
|
||||
--card-bg: #FFFFFF;
|
||||
--shadow: rgba(0, 0, 0, 0.1);
|
||||
--progress-bg: #E8E8E8;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--white: #1A1A2E;
|
||||
--beige: #16213E;
|
||||
--text-dark: #F5F5F5;
|
||||
--card-bg: #1F1F3A;
|
||||
--shadow: rgba(0, 0, 0, 0.3);
|
||||
--progress-bg: #2A2A4A;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: var(--beige);
|
||||
color: var(--text-dark);
|
||||
line-height: 1.6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, var(--lavender), var(--purple));
|
||||
border-radius: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dark-mode-toggle {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.dark-mode-toggle:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.progress-section {
|
||||
background: var(--card-bg);
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 15px var(--shadow);
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 20px;
|
||||
background-color: var(--progress-bg);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--blue), var(--lavender));
|
||||
border-radius: 10px;
|
||||
transition: width 0.5s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 12px;
|
||||
color: var(--text-dark);
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 15px;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
background: var(--beige);
|
||||
border-radius: 10px;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: var(--lavender-dark);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.8em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.add-task-form {
|
||||
background: var(--card-bg);
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 15px var(--shadow);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid var(--beige);
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: var(--white);
|
||||
color: var(--text-dark);
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus,
|
||||
.form-group select:focus {
|
||||
outline: none;
|
||||
border-color: var(--lavender);
|
||||
}
|
||||
|
||||
.add-button {
|
||||
background: linear-gradient(135deg, var(--lavender), var(--purple));
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 25px;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.add-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 20px var(--shadow);
|
||||
}
|
||||
|
||||
.task-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.task-card {
|
||||
background: var(--card-bg);
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 15px var(--shadow);
|
||||
transition: all 0.3s ease;
|
||||
border-left: 5px solid var(--lavender);
|
||||
}
|
||||
|
||||
.task-card[data-status="todo"] {
|
||||
border-left-color: var(--orange);
|
||||
}
|
||||
|
||||
.task-card[data-status="in-progress"] {
|
||||
border-left-color: var(--purple);
|
||||
}
|
||||
|
||||
.task-card[data-status="done"] {
|
||||
border-left-color: var(--blue);
|
||||
}
|
||||
|
||||
.task-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px var(--shadow);
|
||||
}
|
||||
|
||||
.task-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.task-priority {
|
||||
padding: 5px 12px;
|
||||
border-radius: 15px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.priority-high {
|
||||
background: var(--yellow);
|
||||
color: var(--text-dark);
|
||||
}
|
||||
|
||||
.priority-medium {
|
||||
background: var(--orange);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.priority-low {
|
||||
background: var(--blue);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
color: var(--text-dark);
|
||||
opacity: 0.8;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.task-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-action-button {
|
||||
padding: 8px 15px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.status-button {
|
||||
background: var(--beige);
|
||||
color: var(--text-dark);
|
||||
}
|
||||
|
||||
.status-button:hover {
|
||||
background: var(--lavender);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
background: var(--orange);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.delete-button:hover {
|
||||
background: var(--orange-dark);
|
||||
}
|
||||
|
||||
.timer-display {
|
||||
background: var(--yellow);
|
||||
color: var(--text-dark);
|
||||
font-weight: 600;
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.set-timer-button {
|
||||
background: var(--purple);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.set-timer-button:hover {
|
||||
background: var(--purple-dark);
|
||||
}
|
||||
|
||||
.timer-input {
|
||||
display: none;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.timer-input input {
|
||||
padding: 8px;
|
||||
border: 2px solid var(--beige);
|
||||
border-radius: 10px;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.timer-input.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: var(--text-dark);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-state-icon {
|
||||
font-size: 4em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.task-actions {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.task-action-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stats {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.completed {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.completed .task-title {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>📋 Meine Aufgaben</h1>
|
||||
<button class="dark-mode-toggle" onclick="toggleDarkMode()">🌙 Dark Mode</button>
|
||||
</div>
|
||||
|
||||
<div class="progress-section">
|
||||
<div class="progress-header">
|
||||
<h3>Fortschritt</h3>
|
||||
<span id="progress-percentage">0%</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="progress-fill" style="width: 0%">
|
||||
<span class="progress-text">0%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-number" id="total-count">0</div>
|
||||
<div class="stat-label">Gesamt</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number" id="todo-count">0</div>
|
||||
<div class="stat-label">Zu tun</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number" id="in-progress-count">0</div>
|
||||
<div class="stat-label">In Arbeit</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number" id="done-count">0</div>
|
||||
<div class="stat-label">Erledigt</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="add-task-form">
|
||||
<h3>Neue Aufgabe hinzufügen</h3>
|
||||
<div class="form-group">
|
||||
<label for="task-title">Titel</label>
|
||||
<input type="text" id="task-title" placeholder="Was muss erledigt werden?">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="task-description">Beschreibung</label>
|
||||
<textarea id="task-description" rows="3" placeholder="Optionale Beschreibung..."></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="task-priority">Priorität</label>
|
||||
<select id="task-priority">
|
||||
<option value="high">🔴 Hoch (Dringend)</option>
|
||||
<option value="medium" selected>🟡 Mittel</option>
|
||||
<option value="low">🔵 Niedrig</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="add-button" onclick="addTask()">➕ Aufgabe hinzufügen</button>
|
||||
</div>
|
||||
|
||||
<div class="task-list" id="task-list">
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">📝</div>
|
||||
<p>Noch keine Aufgaben vorhanden</p>
|
||||
<p>Füge deine erste Aufgabe hinzu!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let tasks = [];
|
||||
let timers = {};
|
||||
|
||||
function generateId() {
|
||||
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||
}
|
||||
|
||||
function addTask() {
|
||||
const title = document.getElementById('task-title').value.trim();
|
||||
const description = document.getElementById('task-description').value.trim();
|
||||
const priority = document.getElementById('task-priority').value;
|
||||
|
||||
if (!title) {
|
||||
alert('Bitte gib einen Titel ein!');
|
||||
return;
|
||||
}
|
||||
|
||||
const task = {
|
||||
id: generateId(),
|
||||
title: title,
|
||||
description: description,
|
||||
priority: priority,
|
||||
status: 'todo',
|
||||
createdAt: new Date().toISOString(),
|
||||
timerSeconds: 0
|
||||
};
|
||||
|
||||
tasks.push(task);
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
clearForm();
|
||||
}
|
||||
|
||||
function clearForm() {
|
||||
document.getElementById('task-title').value = '';
|
||||
document.getElementById('task-description').value = '';
|
||||
document.getElementById('task-priority').value = 'medium';
|
||||
}
|
||||
|
||||
function deleteTask(id) {
|
||||
if (confirm('Möchtest du diese Aufgabe wirklich löschen?')) {
|
||||
tasks = tasks.filter(task => task.id !== id);
|
||||
if (timers[id]) {
|
||||
clearInterval(timers[id]);
|
||||
delete timers[id];
|
||||
}
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
}
|
||||
|
||||
function changeStatus(id) {
|
||||
const task = tasks.find(t => t.id === id);
|
||||
if (!task) return;
|
||||
|
||||
const statusOrder = ['todo', 'in-progress', 'done'];
|
||||
const currentIndex = statusOrder.indexOf(task.status);
|
||||
task.status = statusOrder[(currentIndex + 1) % statusOrder.length];
|
||||
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function setTimer(id) {
|
||||
const timerInput = document.querySelector(`#timer-${id}`);
|
||||
const minutes = parseInt(timerInput.querySelector('input').value);
|
||||
|
||||
if (minutes > 0) {
|
||||
task = tasks.find(t => t.id === id);
|
||||
task.timerSeconds = minutes * 60;
|
||||
|
||||
if (timers[id]) {
|
||||
clearInterval(timers[id]);
|
||||
}
|
||||
|
||||
timers[id] = setInterval(() => {
|
||||
if (task.timerSeconds > 0) {
|
||||
task.timerSeconds--;
|
||||
updateTimerDisplay(id);
|
||||
} else {
|
||||
clearInterval(timers[id]);
|
||||
alert('⏰ Zeit abgelaufen!');
|
||||
}
|
||||
saveTasks();
|
||||
}, 1000);
|
||||
}
|
||||
timerInput.classList.remove('active');
|
||||
renderTasks();
|
||||
}
|
||||
|
||||
function updateTimerDisplay(id) {
|
||||
const task = tasks.find(t => t.id === id);
|
||||
if (!task) return;
|
||||
|
||||
const hours = Math.floor(task.timerSeconds / 3600);
|
||||
const minutes = Math.floor((task.timerSeconds % 3600) / 60);
|
||||
const seconds = task.timerSeconds % 60;
|
||||
|
||||
const timerDisplay = document.querySelector(`#timer-display-${id}`);
|
||||
if (timerDisplay) {
|
||||
timerDisplay.textContent = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderTasks() {
|
||||
const taskList = document.getElementById('task-list');
|
||||
|
||||
if (tasks.length === 0) {
|
||||
taskList.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">📝</div>
|
||||
<p>Noch keine Aufgaben vorhanden</p>
|
||||
<p>Füge deine erste Aufgabe hinzu!</p>
|
||||
</div>
|
||||
`;
|
||||
updateStats();
|
||||
return;
|
||||
}
|
||||
|
||||
taskList.innerHTML = tasks.map(task => {
|
||||
const statusEmoji = {
|
||||
'todo': '⚪',
|
||||
'in-progress': '🟣',
|
||||
'done': '✅'
|
||||
};
|
||||
|
||||
const statusLabel = {
|
||||
'todo': 'Zu tun',
|
||||
'in-progress': 'In Arbeit',
|
||||
'done': 'Erledigt'
|
||||
};
|
||||
|
||||
const priorityLabel = {
|
||||
'high': 'Dringend',
|
||||
'medium': 'Mittel',
|
||||
'low': 'Niedrig'
|
||||
};
|
||||
|
||||
const hours = Math.floor(task.timerSeconds / 3600);
|
||||
const minutes = Math.floor((task.timerSeconds % 3600) / 60);
|
||||
const seconds = task.timerSeconds % 60;
|
||||
|
||||
return `
|
||||
<div class="task-card fade-in ${task.status === 'done' ? 'completed' : ''}" data-status="${task.status}">
|
||||
<div class="task-header">
|
||||
<span class="task-title">${statusEmoji[task.status]} ${task.title}</span>
|
||||
<span class="task-priority priority-${task.priority}">${priorityLabel[task.priority]}</span>
|
||||
</div>
|
||||
${task.description ? `<div class="task-description">${task.description}</div>` : ''}
|
||||
<div class="task-actions">
|
||||
<button class="task-action-button status-button" onclick="changeStatus('${task.id}')">
|
||||
${statusEmoji[task.status]} ${statusLabel[task.status]}
|
||||
</button>
|
||||
<button class="task-action-button set-timer-button" onclick="toggleTimerInput('${task.id}')">
|
||||
⏰ Timer setzen
|
||||
</button>
|
||||
<div class="timer-input" id="timer-${task.id}">
|
||||
<input type="number" placeholder="Min" min="1" max="180">
|
||||
<button class="task-action-button" onclick="setTimer('${task.id}')">OK</button>
|
||||
</div>
|
||||
<span class="timer-display" id="timer-display-${task.id}">
|
||||
${task.timerSeconds > 0 ? `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}` : '00:00:00'}
|
||||
</span>
|
||||
<button class="task-action-button delete-button" onclick="deleteTask('${task.id}')">
|
||||
🗑️ Löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
updateStats();
|
||||
}
|
||||
|
||||
function toggleTimerInput(id) {
|
||||
const timerInput = document.getElementById(`timer-${id}`);
|
||||
timerInput.classList.toggle('active');
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
const totalCount = tasks.length;
|
||||
const todoCount = tasks.filter(t => t.status === 'todo').length;
|
||||
const inProgressCount = tasks.filter(t => t.status === 'in-progress').length;
|
||||
const doneCount = tasks.filter(t => t.status === 'done').length;
|
||||
const progressPercent = totalCount > 0 ? Math.round((doneCount / totalCount) * 100) : 0;
|
||||
|
||||
document.getElementById('total-count').textContent = totalCount;
|
||||
document.getElementById('todo-count').textContent = todoCount;
|
||||
document.getElementById('in-progress-count').textContent = inProgressCount;
|
||||
document.getElementById('done-count').textContent = doneCount;
|
||||
document.getElementById('progress-percentage').textContent = `${progressPercent}%`;
|
||||
document.getElementById('progress-fill').style.width = `${progressPercent}%`;
|
||||
document.querySelector('.progress-fill .progress-text').textContent = `${progressPercent}%`;
|
||||
}
|
||||
|
||||
function toggleDarkMode() {
|
||||
const html = document.documentElement;
|
||||
const isDark = html.getAttribute('data-theme') === 'dark';
|
||||
html.setAttribute('data-theme', isDark ? 'light' : 'dark');
|
||||
localStorage.setItem('darkMode', isDark ? 'false' : 'true');
|
||||
}
|
||||
|
||||
function saveTasks() {
|
||||
localStorage.setItem('adhs-tasks', JSON.stringify(tasks));
|
||||
}
|
||||
|
||||
function loadTasks() {
|
||||
const saved = localStorage.getItem('adhs-tasks');
|
||||
if (saved) {
|
||||
tasks = JSON.parse(saved);
|
||||
}
|
||||
}
|
||||
|
||||
function loadDarkMode() {
|
||||
const isDark = localStorage.getItem('darkMode') === 'true';
|
||||
if (isDark) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
loadTasks();
|
||||
loadDarkMode();
|
||||
renderTasks();
|
||||
|
||||
// Add some sample tasks if empty
|
||||
if (tasks.length === 0) {
|
||||
tasks = [
|
||||
{
|
||||
id: generateId(),
|
||||
title: 'Projektplan erstellen',
|
||||
description: 'Entwickle einen detaillierten Fahrplan für das neue Projekt',
|
||||
priority: 'high',
|
||||
status: 'in-progress',
|
||||
createdAt: new Date().toISOString(),
|
||||
timerSeconds: 0
|
||||
},
|
||||
{
|
||||
id: generateId(),
|
||||
title: 'E-Mails beantworten',
|
||||
description: 'Überprüfe deinen Posteingang und beantworte wichtige Nachrichten',
|
||||
priority: 'medium',
|
||||
status: 'todo',
|
||||
createdAt: new Date().toISOString(),
|
||||
timerSeconds: 0
|
||||
},
|
||||
{
|
||||
id: generateId(),
|
||||
title: 'Mittagessen vorbereiten',
|
||||
description: 'Gesundes Mittagessen für den Tag zubereiten',
|
||||
priority: 'low',
|
||||
status: 'done',
|
||||
createdAt: new Date().toISOString(),
|
||||
timerSeconds: 0
|
||||
}
|
||||
];
|
||||
saveTasks();
|
||||
renderTasks();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
25
build_deps_headers_vs_runtime.md
Normal file
25
build_deps_headers_vs_runtime.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
## Compile-Time Headers vs. Runtime Libraries
|
||||
|
||||
### What we did
|
||||
- Hit two build failures in a row while compiling llama.cpp with Vulkan support: first missing `vulkan-headers`, then missing `spirv-headers` — despite the Vulkan *driver* (`vulkan-radeon`) and *loader* (`vulkan-icd-loader`) already being installed and working fine (games, desktop compositor, etc.).
|
||||
- Installed the missing header packages and the build proceeded cleanly.
|
||||
|
||||
### Key distinction / Mental model
|
||||
Two separate concerns get bundled under "I have Vulkan installed," but they're not the same thing:
|
||||
- **Runtime pieces** (`vulkan-icd-loader`, `vulkan-radeon`) let an *already-compiled* program talk to the GPU right now.
|
||||
- **Build-time pieces** (`vulkan-headers`, `spirv-headers`) are plain-text `.h` files with function/type declarations that the *compiler* needs to translate new source code calling those functions into machine code.
|
||||
|
||||
A working driver does not imply the headers are present, and vice versa — different packages, different points in the software lifecycle. This generalizes beyond Vulkan: any "-dev" / "-headers" package split (common across Linux libraries) follows the same pattern.
|
||||
|
||||
### Commands / syntax
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `pacman -Q <pkg>` | Check if a package is installed (fails loudly if not — good for audits) |
|
||||
| `pacman -Ql <pkg>` | List files a package provides, to see whether it's headers, a library, or both |
|
||||
| `sudo pacman -S vulkan-headers spirv-headers` | Install Vulkan build-time dependencies on Arch |
|
||||
|
||||
### When to use this
|
||||
When a build fails with "could not find X headers" or "unknown type/function" errors for a library you're sure is "installed" — check whether you have the runtime package, the headers package, or both.
|
||||
|
||||
### Index line
|
||||
`build_deps_headers_vs_runtime.md` — Compile-time headers vs. runtime libraries: why a working driver doesn't mean a package's headers are installed too (Vulkan/SPIRV example).
|
||||
26
llama_cpp_vulkan_rx9070xt.md
Normal file
26
llama_cpp_vulkan_rx9070xt.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
## llama.cpp Vulkan Build on RDNA4 (RX 9070 XT)
|
||||
|
||||
### What we did
|
||||
- Chose plain llama.cpp (not Ollama) for local LLM inference — built from source for full control, targeting coding + agent work via Continue.dev.
|
||||
- Faced a real backend choice: HIP/ROCm (AMD's "official" compute stack) vs. Vulkan. For this exact GPU generation (RDNA4, `gfx1201`), current community data showed Vulkan can *outperform* HIP/ROCm right now, since ROCm kernel support for gfx1201 only landed officially with ROCm 7.2 (March 2026) and is still maturing — the opposite of the usual pattern on older AMD cards. HIP also has a known bug on RDNA4 where the GPU never returns to idle power once the HIP runtime initializes — relevant for a machine meant to stay on 24/7.
|
||||
- Ran a readiness audit *before* installing anything (kernel driver, Vulkan packages, build tools, disk space, kernel version, group membership) to avoid mid-build surprises.
|
||||
- Installed missing pieces: `cmake`, `vulkan-headers`, `spirv-headers`, `ninja`.
|
||||
- Built with `-DGGML_VULKAN=ON`, verified with a smoke-test model — GPU offload confirmed via `-ngl 99`, ~150–260 t/s generation (well above CPU-only range for the model size used).
|
||||
|
||||
### Key distinction / Mental model
|
||||
On brand-new GPU architectures, "the official vendor compute stack" isn't automatically the fastest or most stable choice — driver/kernel maturity for a *specific chip* can lag behind a more generic API that's had years of broad hardware support baked in. Worth checking current benchmarks per-GPU-generation rather than assuming the "proper" stack wins by default.
|
||||
|
||||
### Commands / syntax
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `lspci -k \| grep -A3 VGA` | Confirm which kernel driver (e.g. `amdgpu`) is bound to the GPU |
|
||||
| `pacman -Q vulkan-icd-loader vulkan-radeon vulkan-headers shaderc` | Check Vulkan runtime + build stack presence |
|
||||
| `cmake -B build -G Ninja -DGGML_VULKAN=ON -DCMAKE_BUILD_TYPE=Release` | Configure llama.cpp for a Vulkan-accelerated, optimized, Ninja-driven build |
|
||||
| `cmake --build build -j$(nproc)` | Compile using all CPU threads |
|
||||
| `./llama-cli -hf <repo> -p "..." -n 50 -ngl 99` | Quick GPU smoke test — pulls a model from Hugging Face and runs it fully offloaded to GPU |
|
||||
|
||||
### When to use this
|
||||
Reference this when setting up llama.cpp (or similar GPU-inference tools) on a new/recent AMD GPU — check current-generation ROCm vs. Vulkan performance data first rather than defaulting to ROCm.
|
||||
|
||||
### Index line
|
||||
`llama_cpp_vulkan_rx9070xt.md` — Building llama.cpp with Vulkan backend on RDNA4 (RX 9070 XT/gfx1201); why Vulkan was chosen over HIP/ROCm for this GPU generation; build commands and smoke-test verification.
|
||||
Loading…
Add table
Reference in a new issue