feat(editor): Knopf, der einen Stand von Hand sichert
Zehn Minuten sind der falsche Takt für den einen Moment, in dem man einen Stand wirklich will: unmittelbar vor einer größeren Änderung. Dann ist der letzte selbsttätige Stand im Zweifel neun Minuten alt. - Kamera statt Plus: Ein `+` neben dem Dokument-Namen läse sich als „neues Dokument“, ein Lesezeichen als „Favorit“. Gegen Uhr (Verlauf) und Caret (Dokumentwahl) ist die Kamera eindeutig. - Die Rückmeldung kommt IMMER, auch wenn nichts angelegt wurde: Der Knopf verspricht „dein Stand ist gesichert“, nicht „ein Eintrag wurde erzeugt“. Bei unverändertem Text steht er schon oben in der Liste — einen doppelten Eintrag zu erzwingen kostete nur einen der 20 Plätze. - Gezeigt per vorhandenem Haus-Idiom (`flashBtn`, 1,5 s Haken); dafür nur `.copybtn.done .ic-copy` um `.ic-main` erweitert. - Pad-Fall folgt von selbst: beide Knöpfe in EINER Zuweisung versteckt. - i18n `snapAddTooltip` in 9 Sprachen; der Leer-Text des Menüs nennt jetzt beide Wege. Nachgemessen: 0 -> Klick -> 1 (Haken sichtbar, nach 1,7 s wieder Kamera); zweiter Klick ohne Änderung -> weiterhin 1, Rückmeldung trotzdem; nach einer Änderung -> 2. Im schmalen Layout kostet der Knopf nichts (Kopfhöhe 44 px und Zeilenzahl mit und ohne ihn identisch). D54-Nachtrag; Plan: #ed.snaps.manual [x] (158 Knoten, 0 Warnungen). 243 Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7abdd3bc45
commit
f7d963809a
@@ -3690,3 +3690,51 @@ schließt das Menü, das Diagramm zeichnet neu (30 Knoten) — und ein `undo` ho
|
||||
den vorherigen Stand zeichengenau zurück. Der **Pad-Fall** ist durch die
|
||||
`readOnly`-Wächter im Code abgedeckt, aber nicht live durchgespielt (er
|
||||
bräuchte ein echtes Pad).
|
||||
|
||||
**Nachtrag — ein Knopf, der von Hand sichert.** Zehn Minuten sind der falsche
|
||||
Takt für den einen Moment, in dem man einen Stand wirklich will: unmittelbar
|
||||
**vor** einer größeren Änderung. Genau dann ist der letzte selbsttätige Stand
|
||||
im Zweifel neun Minuten alt und enthält die Arbeit nicht, die man gleich
|
||||
aufs Spiel setzt. Der Knopf steht rechts neben dem Verlaufs-Knopf, in
|
||||
derselben Gruppe wie der Dokument-Wähler.
|
||||
|
||||
**Kamera, nicht Plus.** Ein `+` unmittelbar neben dem Dokument-Namen liest
|
||||
sich als „neues Dokument" — das gibt es schon, im Menü daneben. Ein
|
||||
Lesezeichen läse sich als „Favorit". Die Kamera ist gegen beide Nachbarn
|
||||
eindeutig (Uhr mit Pfeil = Verlauf, Caret = Dokumentwahl) und trifft die
|
||||
Vorstellung, die der Nutzer selbst benannt hat („einen Snapshot manuell
|
||||
anfertigen"). Die UI-Texte bleiben bei „Stand", weil das Menü daneben so
|
||||
heißt.
|
||||
|
||||
**Die Rückmeldung kommt immer — auch wenn nichts angelegt wurde.** Ein Knopf,
|
||||
der bei unverändertem Text stumm bleibt, wirkt kaputt; genau das passiert,
|
||||
denn `snapshotNow()` legt keinen doppelten Eintrag an. Der Ausweg ist keine
|
||||
zweite Meldung, sondern eine genauere Zusage: Der Knopf verspricht **„dein
|
||||
aktueller Stand ist gesichert"**, nicht „ein Eintrag wurde erzeugt". Bei
|
||||
unverändertem Text steht er bereits oben in der Liste — die Zusage stimmt
|
||||
also in beiden Fällen, und es braucht weder eine Fallunterscheidung noch
|
||||
einen zehnten i18n-Text. Einen Eintrag zu erzwingen wäre die schlechtere
|
||||
Wahl: Er kostete einen der zwanzig Plätze für Text, der schon da ist.
|
||||
|
||||
Gezeigt wird das mit dem **vorhandenen** Haus-Idiom: `flashBtn()` setzt für
|
||||
1,5 s die Klasse `done`, die Petrol färbt und das Icon gegen einen Haken
|
||||
tauscht — dieselbe Rückmeldung wie bei „kopieren" und „herunterladen". Dafür
|
||||
musste nur die CSS-Regel `.copybtn.done .ic-copy` um `.ic-main` erweitert
|
||||
werden: die neutrale Form desselben Platzes für Knöpfe, die nichts kopieren.
|
||||
|
||||
Ein **offenes Menü bleibt offen** und zeichnet neu — dort sieht man den
|
||||
Eintrag entstehen. Der Pad-Fall folgt von selbst: Beide Knöpfe werden in
|
||||
**einer** Zuweisung versteckt (`snapBtn.hidden = snapAddBtn.hidden =
|
||||
src.readOnly`), sie können also nicht auseinanderlaufen.
|
||||
|
||||
Der Leer-Text des Menüs nennt jetzt beide Wege („auf Knopfdruck und alle 10
|
||||
Minuten") — er ist die Stelle, an der jemand fragt, wie man überhaupt zu
|
||||
einem Stand kommt.
|
||||
|
||||
**Nachgemessen** (Werkbaum-Plan, Stände zuvor leer): 0 → Klick → **1**,
|
||||
Haken sichtbar (`ic-done` block, `ic-main` none), nach 1,7 s wieder das
|
||||
Kamera-Icon. Zweiter Klick **ohne** Änderung → weiterhin 1, Rückmeldung
|
||||
trotzdem. Text geändert, Klick → **2**; Menü zeigt beide, neueste zuoberst,
|
||||
und liegt vollständig im Panel. Im schmalen Layout kostet der Knopf nichts:
|
||||
Kopfhöhe 44 px und Zeilenzahl sind mit und ohne ihn identisch, die Breite des
|
||||
Dokument-Namens bleibt bei 54 px.
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
- [^] #ed.fold.write: Folding writes the mark back into the text (S) %% one undo step
|
||||
- [^] #ed.fold.preset: One switch folds everything from size M downward (S) %% see D44
|
||||
- [^] #ed.snaps: Earlier states of a document, every ten minutes (S) %% only when something changed
|
||||
- [x] #ed.snaps.manual: Save a state by hand, before a larger change (XS) %% ten minutes is the wrong beat for that moment
|
||||
- [ ] #ed.files: Open and save .werkbaum files (S)
|
||||
+ [^] #ed.fresh: Show what is new since your last visit (S)
|
||||
+ [?] #ed.percolor: A pastel colour per person (S)
|
||||
@@ -521,6 +522,12 @@
|
||||
beside the document picker. Loading one is a single undo step, so a wrong
|
||||
pick costs nothing.
|
||||
|
||||
#ed.snaps.manual
|
||||
Ten minutes is the wrong beat for the one moment a state is really wanted:
|
||||
right before a larger change. The button promises that the current state is
|
||||
kept, not that an entry was added, so it confirms even when the text is
|
||||
unchanged and already at the top of the list.
|
||||
|
||||
#ed.files
|
||||
Open a .werkbaum file and save one. Today the leading data format is the one
|
||||
thing that cannot leave the browser as a file, while the diagram can.
|
||||
|
||||
@@ -74,6 +74,13 @@
|
||||
</button>
|
||||
<div class="snapmenu" id="snapMenu" role="menu" data-i18n-aria="snapMenuAria" aria-label="Frühere Stände" hidden></div>
|
||||
</span>
|
||||
<!-- Von Hand sichern, z. B. vor einer größeren Änderung. Kamera statt
|
||||
Plus: ein Plus neben dem Dokument-Namen läse sich als „neues
|
||||
Dokument“ (D54-Nachtrag). -->
|
||||
<button type="button" class="copybtn snapaddbtn" id="snapAddBtn" data-i18n-title="snapAddTooltip" data-i18n-aria="snapAddTooltip" title="Aktuellen Stand jetzt sichern" aria-label="Aktuellen Stand jetzt sichern">
|
||||
<svg class="ic-main" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 9a2 2 0 0 1 2-2h2.2l1.3-2h6.9l1.3 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/><circle cx="12" cy="13" r="3.1"/></svg>
|
||||
<svg class="ic-done" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
||||
</button>
|
||||
</span>
|
||||
<button type="button" class="copybtn padview" id="padViewBtn" data-view="text" hidden>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect class="frame" x="2.5" y="5" width="19" height="14" rx="2"/><line class="ic-both" x1="12" y1="5" x2="12" y2="19"/><rect class="ic-pad" x="3.5" y="6" width="8" height="12" rx="1" fill="currentColor" stroke="none"/><rect class="ic-text" x="12.5" y="6" width="8" height="12" rx="1" fill="currentColor" stroke="none"/></svg>
|
||||
|
||||
+35
-10
@@ -1761,7 +1761,8 @@ const I18N = {
|
||||
docSwitchTooltip:"Dokument wählen oder verwalten", docMenuAria:"Dokumente",
|
||||
/* Frühere Stände (D54) — alle 10 Minuten, nur bei Änderung. */
|
||||
snapTooltip:"Frühere Stände dieses Dokuments", snapMenuAria:"Frühere Stände",
|
||||
snapNone:"Noch keine früheren Stände – gesichert wird alle 10 Minuten, sobald sich etwas geändert hat.",
|
||||
snapNone:"Noch keine früheren Stände – gesichert wird auf Knopfdruck und alle 10 Minuten, sobald sich etwas geändert hat.",
|
||||
snapAddTooltip:"Aktuellen Stand jetzt sichern",
|
||||
snapLines:"{n} Zeilen",
|
||||
docNew:"Neues Dokument", docRename:"Umbenennen", docDelete:"Löschen",
|
||||
docNewName:"Unbenannt",
|
||||
@@ -1849,7 +1850,8 @@ const I18N = {
|
||||
editorTitle:"Structure (text)", diagramTitle:"Diagram",
|
||||
docSwitchTooltip:"Choose or manage document", docMenuAria:"Documents",
|
||||
snapTooltip:"Earlier states of this document", snapMenuAria:"Earlier states",
|
||||
snapNone:"No earlier states yet – one is kept every 10 minutes, once something has changed.",
|
||||
snapNone:"No earlier states yet – one is kept on demand and every 10 minutes, once something has changed.",
|
||||
snapAddTooltip:"Save the current state now",
|
||||
snapLines:"{n} lines",
|
||||
docNew:"New document", docRename:"Rename", docDelete:"Delete",
|
||||
docNewName:"Untitled",
|
||||
@@ -1937,7 +1939,8 @@ const I18N = {
|
||||
editorTitle:"Estructura (texto)", diagramTitle:"Diagrama",
|
||||
docSwitchTooltip:"Elegir o gestionar documento", docMenuAria:"Documentos",
|
||||
snapTooltip:"Estados anteriores de este documento", snapMenuAria:"Estados anteriores",
|
||||
snapNone:"Aún no hay estados anteriores: se guarda uno cada 10 minutos, cuando algo ha cambiado.",
|
||||
snapNone:"Aún no hay estados anteriores: se guarda uno al pulsar el botón y cada 10 minutos, cuando algo ha cambiado.",
|
||||
snapAddTooltip:"Guardar ahora el estado actual",
|
||||
snapLines:"{n} líneas",
|
||||
docNew:"Nuevo documento", docRename:"Renombrar", docDelete:"Eliminar",
|
||||
docNewName:"Sin título",
|
||||
@@ -2025,7 +2028,8 @@ const I18N = {
|
||||
editorTitle:"Structure (texte)", diagramTitle:"Diagramme",
|
||||
docSwitchTooltip:"Choisir ou gérer le document", docMenuAria:"Documents",
|
||||
snapTooltip:"États antérieurs de ce document", snapMenuAria:"États antérieurs",
|
||||
snapNone:"Pas encore d’état antérieur : un état est conservé toutes les 10 minutes, dès que quelque chose a changé.",
|
||||
snapNone:"Pas encore d’état antérieur : un état est conservé sur demande et toutes les 10 minutes, dès que quelque chose a changé.",
|
||||
snapAddTooltip:"Enregistrer l’état actuel maintenant",
|
||||
snapLines:"{n} lignes",
|
||||
docNew:"Nouveau document", docRename:"Renommer", docDelete:"Supprimer",
|
||||
docNewName:"Sans titre",
|
||||
@@ -2113,7 +2117,8 @@ const I18N = {
|
||||
editorTitle:"Struktura (tekst)", diagramTitle:"Diagram",
|
||||
docSwitchTooltip:"Wybierz lub zarządzaj dokumentem", docMenuAria:"Dokumenty",
|
||||
snapTooltip:"Wcześniejsze stany tego dokumentu", snapMenuAria:"Wcześniejsze stany",
|
||||
snapNone:"Brak wcześniejszych stanów – zapisywany jest co 10 minut, gdy coś się zmieni.",
|
||||
snapNone:"Brak wcześniejszych stanów – zapisywany jest na żądanie i co 10 minut, gdy coś się zmieni.",
|
||||
snapAddTooltip:"Zapisz bieżący stan teraz",
|
||||
snapLines:"wierszy: {n}",
|
||||
docNew:"Nowy dokument", docRename:"Zmień nazwę", docDelete:"Usuń",
|
||||
docNewName:"Bez nazwy",
|
||||
@@ -2201,7 +2206,8 @@ const I18N = {
|
||||
editorTitle:"Структура (текст)", diagramTitle:"Диаграмма",
|
||||
docSwitchTooltip:"Выбрать документ или управлять им", docMenuAria:"Документы",
|
||||
snapTooltip:"Прежние состояния этого документа", snapMenuAria:"Прежние состояния",
|
||||
snapNone:"Прежних состояний пока нет — они сохраняются каждые 10 минут, если что-то изменилось.",
|
||||
snapNone:"Прежних состояний пока нет — они сохраняются по нажатию кнопки и каждые 10 минут, если что-то изменилось.",
|
||||
snapAddTooltip:"Сохранить текущее состояние сейчас",
|
||||
snapLines:"строк: {n}",
|
||||
docNew:"Новый документ", docRename:"Переименовать", docDelete:"Удалить",
|
||||
docNewName:"Без названия",
|
||||
@@ -2289,7 +2295,8 @@ const I18N = {
|
||||
editorTitle:"संरचना (टेक्स्ट)", diagramTitle:"आरेख",
|
||||
docSwitchTooltip:"दस्तावेज़ चुनें या प्रबंधित करें", docMenuAria:"दस्तावेज़",
|
||||
snapTooltip:"इस दस्तावेज़ की पिछली स्थितियाँ", snapMenuAria:"पिछली स्थितियाँ",
|
||||
snapNone:"अभी कोई पिछली स्थिति नहीं — कुछ बदलने पर हर 10 मिनट में एक सहेजी जाती है।",
|
||||
snapNone:"अभी कोई पिछली स्थिति नहीं — बटन दबाने पर और कुछ बदलने पर हर 10 मिनट में एक सहेजी जाती है।",
|
||||
snapAddTooltip:"मौजूदा स्थिति अभी सहेजें",
|
||||
snapLines:"{n} पंक्तियाँ",
|
||||
docNew:"नया दस्तावेज़", docRename:"नाम बदलें", docDelete:"हटाएँ",
|
||||
docNewName:"बिना शीर्षक",
|
||||
@@ -2377,7 +2384,8 @@ const I18N = {
|
||||
editorTitle:"结构(文本)", diagramTitle:"图表",
|
||||
docSwitchTooltip:"选择或管理文档", docMenuAria:"文档",
|
||||
snapTooltip:"此文档的早期状态", snapMenuAria:"早期状态",
|
||||
snapNone:"暂无早期状态——内容有变动时,每 10 分钟保存一次。",
|
||||
snapNone:"暂无早期状态——可随时手动保存;内容有变动时,也会每 10 分钟保存一次。",
|
||||
snapAddTooltip:"立即保存当前状态",
|
||||
snapLines:"{n} 行",
|
||||
docNew:"新建文档", docRename:"重命名", docDelete:"删除",
|
||||
docNewName:"未命名",
|
||||
@@ -2465,7 +2473,8 @@ const I18N = {
|
||||
editorTitle:"構造(テキスト)", diagramTitle:"ダイアグラム",
|
||||
docSwitchTooltip:"ドキュメントを選択・管理", docMenuAria:"ドキュメント",
|
||||
snapTooltip:"このドキュメントの以前の状態", snapMenuAria:"以前の状態",
|
||||
snapNone:"以前の状態はまだありません — 変更があれば 10 分ごとに保存されます。",
|
||||
snapNone:"以前の状態はまだありません — ボタンを押したとき、および変更があれば 10 分ごとに保存されます。",
|
||||
snapAddTooltip:"現在の状態を今すぐ保存",
|
||||
snapLines:"{n} 行",
|
||||
docNew:"新規ドキュメント", docRename:"名前を変更", docDelete:"削除",
|
||||
docNewName:"無題",
|
||||
@@ -2972,6 +2981,7 @@ function snapshotNow(){
|
||||
setInterval(snapshotNow, SNAP_EVERY);
|
||||
|
||||
const snapBtn = document.getElementById('snapBtn');
|
||||
const snapAddBtn = document.getElementById('snapAddBtn');
|
||||
const snapMenu = document.getElementById('snapMenu');
|
||||
|
||||
function snapLabel(ms){
|
||||
@@ -3027,11 +3037,26 @@ function closeSnapMenu(){
|
||||
snapMenu.hidden = true;
|
||||
snapBtn.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
function updateSnapBtn(){ snapBtn.hidden = src.readOnly; if(src.readOnly) closeSnapMenu(); }
|
||||
function updateSnapBtn(){
|
||||
snapBtn.hidden = snapAddBtn.hidden = src.readOnly;
|
||||
if(src.readOnly) closeSnapMenu();
|
||||
}
|
||||
snapBtn.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
snapMenu.hidden ? openSnapMenu() : closeSnapMenu();
|
||||
});
|
||||
/* Von Hand sichern — der Fall „gleich ändere ich viel“, für den zehn Minuten
|
||||
zu lang sind. Die Rückmeldung kommt **immer**, auch wenn `snapshotNow()`
|
||||
nichts angelegt hat: Der Knopf verspricht „dein Stand ist gesichert“, nicht
|
||||
„ein Eintrag wurde erzeugt“ — bei unverändertem Text steht er schon oben in
|
||||
der Liste. Einen doppelten Eintrag zu erzwingen kostete nur einen der 20
|
||||
Plätze (D54-Nachtrag). Ein offenes Menü bleibt offen und zeichnet neu, dort
|
||||
sieht man den neuen Eintrag entstehen. */
|
||||
snapAddBtn.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
snapshotNow();
|
||||
flashBtn(snapAddBtn);
|
||||
});
|
||||
document.addEventListener('click', e => {
|
||||
if(!snapMenu.hidden && !snapMenu.contains(e.target) && !snapBtn.contains(e.target)) closeSnapMenu();
|
||||
});
|
||||
|
||||
@@ -362,7 +362,9 @@
|
||||
.copybtn:hover,.copybtn.done{border-color:var(--or);color:var(--or)}
|
||||
.copybtn svg{display:block;width:15px;height:15px}
|
||||
.copybtn .ic-done{display:none}
|
||||
.copybtn.done .ic-copy{display:none}
|
||||
/* `.ic-main` ist die neutrale Form von `.ic-copy` für Knöpfe, die nichts
|
||||
kopieren, aber dieselbe Erfolgs-Rückmeldung geben (Stand sichern, D54). */
|
||||
.copybtn.done .ic-copy,.copybtn.done .ic-main{display:none}
|
||||
.copybtn.done .ic-done{display:block}
|
||||
/* „im Pad bearbeiten" (D31) — nur bei einem ?etherpad=-Dokument sichtbar.
|
||||
Das [hidden] braucht die eigene Regel, weil .copybtn ein display setzt. */
|
||||
|
||||
Reference in New Issue
Block a user