upd commandbar
This commit is contained in:
parent
22d811716d
commit
2cb4c24e40
|
|
@ -63,16 +63,17 @@ Scope-dynamische Commands verwenden den aktuell aktiven Scope (Privat/Firma). Sc
|
|||
| `/page [Titel]` | Neue Wiki-Seite erstellen (aktiver Scope) |
|
||||
| `/ppage [Titel]` | Neue Wiki-Seite erstellen (Privat) |
|
||||
| `/bpage [Titel]` | Neue Wiki-Seite erstellen (Firma) |
|
||||
| `/person [Name]` | Neuen Personen-Kontext erstellen (aktiver Scope) |
|
||||
| `/pperson [Name]` | Neuen Personen-Kontext erstellen (Privat) |
|
||||
| `/bperson [Name]` | Neuen Personen-Kontext erstellen (Firma) |
|
||||
| `/firma [Name]` | Neuen Firmen-Kontext erstellen (aktiver Scope) |
|
||||
| `/pfirma [Name]` | Neuen Firmen-Kontext erstellen (Privat) |
|
||||
| `/bfirma [Name]` | Neuen Firmen-Kontext erstellen (Firma) |
|
||||
| `/per [Name]` | Neuen Personen-Kontext erstellen; Name → Title Case, setzt `meta.fullName` |
|
||||
| `/firma [Name]` | Neuen Firmen-Kontext erstellen |
|
||||
| `/jf [Name]` | Zu passendem Jour-Fix-Kontext springen |
|
||||
| `/sidebar` | Sidebar ein-/ausblenden |
|
||||
| `/home` | Zurück zur Journal-Startseite (`/`) |
|
||||
| `/help` | Hilfeseite öffnen (`/help`) |
|
||||
|
||||
Scope-spezifische Commands erscheinen in der Bar erst ab dem zweiten Zeichen (`/p...` / `/b...`), um Duplikate mit den scope-dynamischen Commands zu vermeiden.
|
||||
|
||||
Wenn kein Text angegeben wird, erscheint ein Browser-`prompt()` zur Eingabe — `Enter` auf einem Befehl ohne Text löst also direkt eine Aktion aus.
|
||||
|
||||
Beispiel: `/note Anruf bei Steffen wegen Angebot` → sofort als Topic in `daily-log` gespeichert, ohne den aktuellen Screen zu verlassen.
|
||||
|
||||
---
|
||||
|
|
@ -134,12 +135,13 @@ In-Memory: `label.toLowerCase().includes(query)` — reicht für typische Datenm
|
|||
|
||||
## Scope
|
||||
|
||||
**In Scope:**
|
||||
**Implementiert:**
|
||||
- Navigation zu Contexts und Wiki-Seiten
|
||||
- Slash-Commands: `/note`, `/todo`, `/jf`
|
||||
- Slash-Commands: `/note`, `/pnote`, `/bnote`, `/todo`, `/ptodo`, `/btodo`, `/page`, `/ppage`, `/bpage`, `/per`, `/firma`, `/jf`, `/sidebar`, `/home`, `/help`
|
||||
- Recent-Items (sessionStorage)
|
||||
- Tastatursteuerung
|
||||
- Tastatursteuerung inkl. Enter ohne Text (Browser-Prompt)
|
||||
- Responsive (Modal auf Mobile funktioniert)
|
||||
- `/per` setzt automatisch Title Case und `meta.fullName`
|
||||
|
||||
**Out of Scope (v1):**
|
||||
- Fuzzy-Suche / Treffergewichtung
|
||||
|
|
@ -147,6 +149,7 @@ In-Memory: `label.toLowerCase().includes(query)` — reicht für typische Datenm
|
|||
- Server-seitige Volltextsuche
|
||||
- Persistente "Favourites" in der Bar
|
||||
- Konfigurierbarer Shortcut
|
||||
- Scope-Varianten für `/per` und `/firma` (`/pper`, `/bper`, ...)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
function promptIfEmpty(current: string, label: string): string {
|
||||
if (current) return current;
|
||||
return window.prompt(`${label}:`) ?? "";
|
||||
}
|
||||
|
||||
const results = $derived.by(() => {
|
||||
const q = query.trim().toLowerCase();
|
||||
|
||||
|
|
@ -114,9 +119,10 @@
|
|||
: `Neu: Notiz (${$currentScope === "private" ? "Privat" : "Firma"})`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
const t = promptIfEmpty(text, "Titel der Notiz");
|
||||
if (!t) return;
|
||||
const isPrivateScope = $currentScope === "private";
|
||||
await executeNoteCommand(text, isPrivateScope);
|
||||
await executeNoteCommand(t, isPrivateScope);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -131,8 +137,9 @@
|
|||
: "Neu: Notiz (Privat)",
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
await executeNoteCommand(text, true);
|
||||
const t = promptIfEmpty(text, "Titel der Notiz");
|
||||
if (!t) return;
|
||||
await executeNoteCommand(t, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -147,8 +154,9 @@
|
|||
: "Neu: Notiz (Firma)",
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
await executeNoteCommand(text, false);
|
||||
const t = promptIfEmpty(text, "Titel der Notiz");
|
||||
if (!t) return;
|
||||
await executeNoteCommand(t, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -164,9 +172,10 @@
|
|||
: `Neu: Todo (${$currentScope === "private" ? "Privat" : "Firma"})`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
const t = promptIfEmpty(text, "Titel des Todos");
|
||||
if (!t) return;
|
||||
const isPrivateScope = $currentScope === "private";
|
||||
await executeTodoCommand(text, isPrivateScope);
|
||||
await executeTodoCommand(t, isPrivateScope);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -181,8 +190,9 @@
|
|||
: "Neu: Todo (Privat)",
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
await executeTodoCommand(text, true);
|
||||
const t = promptIfEmpty(text, "Titel des Todos");
|
||||
if (!t) return;
|
||||
await executeTodoCommand(t, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -197,8 +207,9 @@
|
|||
: "Neu: Todo (Firma)",
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
await executeTodoCommand(text, false);
|
||||
const t = promptIfEmpty(text, "Titel des Todos");
|
||||
if (!t) return;
|
||||
await executeTodoCommand(t, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -213,13 +224,14 @@
|
|||
: `Neu: Wiki-Seite (${$currentScope === "private" ? "Privat" : "Firma"})`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
if (await pageNameExists(text)) {
|
||||
alert(`Wiki-Seite "${text}" existiert bereits.`);
|
||||
const t = promptIfEmpty(text, "Titel der Wiki-Seite");
|
||||
if (!t) return;
|
||||
if (await pageNameExists(t)) {
|
||||
alert(`Wiki-Seite "${t}" existiert bereits.`);
|
||||
return;
|
||||
}
|
||||
const isPrivateScope = $currentScope === "private";
|
||||
const page = await createPage(text, isPrivateScope);
|
||||
const page = await createPage(t, isPrivateScope);
|
||||
closeBar();
|
||||
goto(`/wiki/${page.id}`);
|
||||
},
|
||||
|
|
@ -236,12 +248,13 @@
|
|||
: `Neu: Wiki-Seite (Privat)`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
if (await pageNameExists(text)) {
|
||||
alert(`Wiki-Seite "${text}" existiert bereits.`);
|
||||
const t = promptIfEmpty(text, "Titel der Wiki-Seite");
|
||||
if (!t) return;
|
||||
if (await pageNameExists(t)) {
|
||||
alert(`Wiki-Seite "${t}" existiert bereits.`);
|
||||
return;
|
||||
}
|
||||
const page = await createPage(text, true);
|
||||
const page = await createPage(t, true);
|
||||
closeBar();
|
||||
goto(`/wiki/${page.id}`);
|
||||
},
|
||||
|
|
@ -258,12 +271,13 @@
|
|||
: `Neu: Wiki-Seite (Firma)`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
if (await pageNameExists(text)) {
|
||||
alert(`Wiki-Seite "${text}" existiert bereits.`);
|
||||
const t = promptIfEmpty(text, "Titel der Wiki-Seite");
|
||||
if (!t) return;
|
||||
if (await pageNameExists(t)) {
|
||||
alert(`Wiki-Seite "${t}" existiert bereits.`);
|
||||
return;
|
||||
}
|
||||
const page = await createPage(text, false);
|
||||
const page = await createPage(t, false);
|
||||
closeBar();
|
||||
goto(`/wiki/${page.id}`);
|
||||
},
|
||||
|
|
@ -278,14 +292,16 @@
|
|||
label: text ? `Person: "${text}"` : `Neu: Person`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
const fullName = `Person ${text}`;
|
||||
const raw = promptIfEmpty(text, "Name der Person");
|
||||
if (!raw) return;
|
||||
const displayName = raw.replace(/\b\w/g, (c) => c.toUpperCase());
|
||||
const fullName = `Person ${displayName}`;
|
||||
if (await contextNameExists(fullName, "person")) {
|
||||
alert(`Person "${text}" existiert bereits.`);
|
||||
alert(`Person "${displayName}" existiert bereits.`);
|
||||
return;
|
||||
}
|
||||
const id = newId();
|
||||
await upsertContext({ id, name: fullName, type: "person" });
|
||||
await upsertContext({ id, name: fullName, type: "person", meta: { fullName: displayName, email: "", phone: "", duSince: "", personSubType: "colleague" } });
|
||||
closeBar();
|
||||
goto(`/context/${id}`);
|
||||
},
|
||||
|
|
@ -300,10 +316,11 @@
|
|||
label: text ? `Firma: "${text}"` : `Neu: Firma`,
|
||||
badge: "BEFEHL",
|
||||
action: async () => {
|
||||
if (!text) return;
|
||||
const fullName = `Firma ${text}`;
|
||||
const t = promptIfEmpty(text, "Name der Firma");
|
||||
if (!t) return;
|
||||
const fullName = `Firma ${t}`;
|
||||
if (await contextNameExists(fullName, "company")) {
|
||||
alert(`Firma "${text}" existiert bereits.`);
|
||||
alert(`Firma "${t}" existiert bereits.`);
|
||||
return;
|
||||
}
|
||||
const id = newId();
|
||||
|
|
@ -327,6 +344,34 @@
|
|||
});
|
||||
}
|
||||
|
||||
if ("/home".startsWith(cmd)) {
|
||||
actions.push({
|
||||
id: "cmd-home",
|
||||
type: "action",
|
||||
icon: "🏠",
|
||||
label: "Journal (Startseite)",
|
||||
badge: "BEFEHL",
|
||||
action: () => {
|
||||
closeBar();
|
||||
goto("/");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if ("/help".startsWith(cmd)) {
|
||||
actions.push({
|
||||
id: "cmd-help",
|
||||
type: "action",
|
||||
icon: "❓",
|
||||
label: "Hilfe & Befehle anzeigen",
|
||||
badge: "BEFEHL",
|
||||
action: () => {
|
||||
closeBar();
|
||||
goto("/help");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if ("/jf".startsWith(cmd)) {
|
||||
actions.push({
|
||||
id: "cmd-jf",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,190 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-3xl p-6">
|
||||
<div class="mb-6 flex items-center gap-3">
|
||||
<h1 class="flex-1 text-2xl font-bold text-white">Hilfe & Befehle</h1>
|
||||
<button
|
||||
class="rounded bg-card-bg px-3 py-1.5 text-sm text-muted hover:text-white"
|
||||
onclick={() => history.back()}
|
||||
>
|
||||
← Zurück
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Command Bar -->
|
||||
<section class="mb-8">
|
||||
<h2 class="mb-3 text-lg font-semibold text-white">Command Bar</h2>
|
||||
<p class="mb-4 text-sm text-muted">
|
||||
Öffnen mit <kbd class="rounded bg-card-bg px-1.5 py-0.5 font-mono text-xs text-white">Ctrl+K</kbd>.
|
||||
Tippe einen Befehl mit <code class="text-accent">/</code> oder suche direkt nach Kontexten und Wiki-Seiten.
|
||||
</p>
|
||||
|
||||
<div class="rounded border border-border bg-card-bg overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-border text-left text-xs text-muted">
|
||||
<th class="px-4 py-2 font-medium">Befehl</th>
|
||||
<th class="px-4 py-2 font-medium">Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border">
|
||||
<!-- Neuanlage -->
|
||||
<tr class="bg-bg/30">
|
||||
<td colspan="2" class="px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted">Neuanlage</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/note [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Notiz (aktueller Scope)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/pnote [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Notiz (Privat)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/bnote [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Notiz (Firma)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/todo [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neues Todo (aktueller Scope)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/ptodo [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neues Todo (Privat)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/btodo [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neues Todo (Firma)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/page [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Wiki-Seite (aktueller Scope)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/ppage [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Wiki-Seite (Privat)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/bpage [Titel]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Wiki-Seite (Firma)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/per [Name]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Person anlegen</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/firma [Name]</td>
|
||||
<td class="px-4 py-2 text-white">Neue Firma anlegen</td>
|
||||
</tr>
|
||||
|
||||
<!-- Navigation -->
|
||||
<tr class="bg-bg/30">
|
||||
<td colspan="2" class="px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted">Navigation</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/jf [Suche]</td>
|
||||
<td class="px-4 py-2 text-white">Zu einem Jour-Fix-Meeting springen</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/home</td>
|
||||
<td class="px-4 py-2 text-white">Zurück zur Journal-Startseite</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/help</td>
|
||||
<td class="px-4 py-2 text-white">Diese Hilfeseite öffnen</td>
|
||||
</tr>
|
||||
|
||||
<!-- UI -->
|
||||
<tr class="bg-bg/30">
|
||||
<td colspan="2" class="px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted">UI</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">/sidebar</td>
|
||||
<td class="px-4 py-2 text-white">Sidebar ein-/ausblenden</td>
|
||||
</tr>
|
||||
|
||||
<!-- Suche -->
|
||||
<tr class="bg-bg/30">
|
||||
<td colspan="2" class="px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted">Suche (ohne /)</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">[Suchbegriff]</td>
|
||||
<td class="px-4 py-2 text-white">Kontexte und Wiki-Seiten durchsuchen</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">(leer)</td>
|
||||
<td class="px-4 py-2 text-white">Zuletzt besuchte Kontexte anzeigen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Keyboard Shortcuts -->
|
||||
<section class="mb-8">
|
||||
<h2 class="mb-3 text-lg font-semibold text-white">Tastenkürzel</h2>
|
||||
<div class="rounded border border-border bg-card-bg overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-border text-left text-xs text-muted">
|
||||
<th class="px-4 py-2 font-medium">Kürzel</th>
|
||||
<th class="px-4 py-2 font-medium">Funktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border">
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2"><kbd class="rounded bg-bg px-1.5 py-0.5 font-mono text-xs text-white">Ctrl+K</kbd></td>
|
||||
<td class="px-4 py-2 text-white">Command Bar öffnen/schließen</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2"><kbd class="rounded bg-bg px-1.5 py-0.5 font-mono text-xs text-white">Ctrl+B</kbd></td>
|
||||
<td class="px-4 py-2 text-white">Sidebar ein-/ausblenden</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2"><kbd class="rounded bg-bg px-1.5 py-0.5 font-mono text-xs text-white">↑ ↓</kbd></td>
|
||||
<td class="px-4 py-2 text-white">In Command Bar navigieren</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2"><kbd class="rounded bg-bg px-1.5 py-0.5 font-mono text-xs text-white">Enter</kbd></td>
|
||||
<td class="px-4 py-2 text-white">Ausgewählten Befehl ausführen</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2"><kbd class="rounded bg-bg px-1.5 py-0.5 font-mono text-xs text-white">Esc</kbd></td>
|
||||
<td class="px-4 py-2 text-white">Command Bar schließen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Inline Tags -->
|
||||
<section class="mb-8">
|
||||
<h2 class="mb-3 text-lg font-semibold text-white">Inline-Tags im Text</h2>
|
||||
<div class="rounded border border-border bg-card-bg overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-border text-left text-xs text-muted">
|
||||
<th class="px-4 py-2 font-medium">Syntax</th>
|
||||
<th class="px-4 py-2 font-medium">Bedeutung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border">
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">-> NAME</td>
|
||||
<td class="px-4 py-2 text-white">Zuweisung an Person</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">@P:PROJEKT</td>
|
||||
<td class="px-4 py-2 text-white">Projektreferenz</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-bg/40">
|
||||
<td class="px-4 py-2 font-mono text-accent">@NAME</td>
|
||||
<td class="px-4 py-2 text-white">Erwähnung einer Person</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue