update
This commit is contained in:
12
Makefile
12
Makefile
@@ -1,8 +1,9 @@
|
|||||||
.PHONY: install build run dev auth prod stop logs push pull
|
.PHONY: install build run dev auth prod stop logs push pull loeschen
|
||||||
|
|
||||||
PY := .venv/bin/python
|
PY := .venv/bin/python
|
||||||
COMPOSE = docker compose
|
COMPOSE = docker compose
|
||||||
SERVER ?= root@178.104.67.87
|
SERVER ?= root@178.104.67.87
|
||||||
|
URL ?= https://buchwerk.marha.de
|
||||||
REMOTE ?= /var/www/buchwerk
|
REMOTE ?= /var/www/buchwerk
|
||||||
# Themen zwischen lokal und Server abgleichen; TOPIC=<Name> beschränkt auf ein Thema.
|
# Themen zwischen lokal und Server abgleichen; TOPIC=<Name> beschränkt auf ein Thema.
|
||||||
# Ausgeschlossen: Arbeitsdateien der Agenten (arbeit/) und Logs. Ohne --delete: nichts wird entfernt.
|
# Ausgeschlossen: Arbeitsdateien der Agenten (arbeit/) und Logs. Ohne --delete: nichts wird entfernt.
|
||||||
@@ -47,3 +48,12 @@ push:
|
|||||||
pull:
|
pull:
|
||||||
rsync -az --progress --mkpath $(SYNC_AUS) "$(SERVER):$(REMOTE)/$(SYNC_QUELLE)" "$(SYNC_QUELLE)"
|
rsync -az --progress --mkpath $(SYNC_AUS) "$(SERVER):$(REMOTE)/$(SYNC_QUELLE)" "$(SYNC_QUELLE)"
|
||||||
@echo "Geholt: $(SERVER):$(REMOTE)/$(SYNC_QUELLE) → $(SYNC_QUELLE)"
|
@echo "Geholt: $(SERVER):$(REMOTE)/$(SYNC_QUELLE) → $(SYNC_QUELLE)"
|
||||||
|
|
||||||
|
# Fertige Bücher lassen sich in der Oberfläche nicht löschen. Nur hier, mit Rückfrage:
|
||||||
|
# make loeschen TOPIC="Godot 4" – entfernt das Thema auf dem Server (über die API) und lokal.
|
||||||
|
loeschen:
|
||||||
|
@[ -n "$(TOPIC)" ] || { echo "TOPIC=<Name> angeben"; exit 1; }
|
||||||
|
@printf 'Thema „%s“ samt Buch auf dem Server und lokal unwiderruflich löschen? [j/N] ' "$(TOPIC)"; read a; [ "$$a" = "j" ]
|
||||||
|
curl -fsS -X DELETE "$(URL)/api/topics/$$(python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1]))' "$(TOPIC)")" && echo
|
||||||
|
rm -rf "storage/$(TOPIC)"
|
||||||
|
@echo "Gelöscht: $(TOPIC)"
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ function tokens(n) { return n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' : n >= 1e3 ? M
|
|||||||
@click="topic = t.name; navAuf = false">
|
@click="topic = t.name; navAuf = false">
|
||||||
<span class="punkt" :class="t.laeuft ? 'laeuft' : t.status"></span>
|
<span class="punkt" :class="t.laeuft ? 'laeuft' : t.status"></span>
|
||||||
<span style="flex: 1">{{ t.titel }}</span>
|
<span style="flex: 1">{{ t.titel }}</span>
|
||||||
<button class="klein sekundaer" title="Löschen" @click.stop="loeschen(t.name)">✕</button>
|
<button v-if="t.status !== 'fertig'" class="klein sekundaer" title="Löschen" @click.stop="loeschen(t.name)">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!topics.length" style="color: var(--dim); padding: 8px">Noch kein Thema.</div>
|
<div v-if="!topics.length" style="color: var(--dim); padding: 8px">Noch kein Thema.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ import Lesemodus from './Lesemodus.vue'
|
|||||||
const props = defineProps({ topic: String, laeuft: Boolean, fortschritt: Number })
|
const props = defineProps({ topic: String, laeuft: Boolean, fortschritt: Number })
|
||||||
const daten = ref(null)
|
const daten = ref(null)
|
||||||
const lesemodus = ref(false)
|
const lesemodus = ref(false)
|
||||||
|
// Vollbild nur aus der Klickgeste heraus (Browser-Vorgabe); iOS-Safari kennt die API nicht.
|
||||||
|
function lesemodusStart() {
|
||||||
|
lesemodus.value = true
|
||||||
|
document.documentElement.requestFullscreen?.().catch(() => {})
|
||||||
|
}
|
||||||
|
function lesemodusEnde() {
|
||||||
|
lesemodus.value = false
|
||||||
|
if (document.fullscreenElement) document.exitFullscreen().catch(() => {})
|
||||||
|
}
|
||||||
const navAuf = ref(false)
|
const navAuf = ref(false)
|
||||||
// Wischgeste (nur Buchansicht, nicht im Lesemodus): nach rechts öffnet das Inhaltsverzeichnis, nach links schließt es
|
// Wischgeste (nur Buchansicht, nicht im Lesemodus): nach rechts öffnet das Inhaltsverzeichnis, nach links schließt es
|
||||||
let wisch = null
|
let wisch = null
|
||||||
@@ -100,7 +109,7 @@ onUnmounted(() => window.removeEventListener('keydown', taste))
|
|||||||
<nav class="guide-nav" :class="{ offen: navAuf }">
|
<nav class="guide-nav" :class="{ offen: navAuf }">
|
||||||
<button class="schliessen sekundaer klein" @click="navAuf = false">✕ Schließen</button>
|
<button class="schliessen sekundaer klein" @click="navAuf = false">✕ Schließen</button>
|
||||||
<div class="werkzeuge">
|
<div class="werkzeuge">
|
||||||
<button class="klein" title="Lesemodus: Abschnitt für Abschnitt" @click="lesemodus = true" :disabled="!abschnitte.length">Lesen ▶</button>
|
<button class="klein" title="Lesemodus: Abschnitt für Abschnitt" @click="lesemodusStart" :disabled="!abschnitte.length">Lesen ▶</button>
|
||||||
<a class="knopf klein sekundaer" title="Als Markdown-Datei herunterladen" :href="api.guideMdUrl(topic)" download>MD</a>
|
<a class="knopf klein sekundaer" title="Als Markdown-Datei herunterladen" :href="api.guideMdUrl(topic)" download>MD</a>
|
||||||
<a v-if="daten?.pdf" class="knopf klein sekundaer" title="Als PDF herunterladen" :href="api.pdfUrl(topic)" download>PDF</a>
|
<a v-if="daten?.pdf" class="knopf klein sekundaer" title="Als PDF herunterladen" :href="api.pdfUrl(topic)" download>PDF</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,7 +135,7 @@ onUnmounted(() => window.removeEventListener('keydown', taste))
|
|||||||
<div ref="lese" class="lese" @touchstart.passive="wischStart" @touchend.passive="wischEnde">
|
<div ref="lese" class="lese" @touchstart.passive="wischStart" @touchend.passive="wischEnde">
|
||||||
<div class="mobil-leiste">
|
<div class="mobil-leiste">
|
||||||
<button class="sekundaer klein" @click="navAuf = !navAuf">☰ Inhalt</button>
|
<button class="sekundaer klein" @click="navAuf = !navAuf">☰ Inhalt</button>
|
||||||
<button class="klein" @click="lesemodus = true" :disabled="!abschnitte.length">Lesen ▶</button>
|
<button class="klein" @click="lesemodusStart" :disabled="!abschnitte.length">Lesen ▶</button>
|
||||||
<a class="knopf klein sekundaer" :href="api.guideMdUrl(topic)" download>MD</a>
|
<a class="knopf klein sekundaer" :href="api.guideMdUrl(topic)" download>MD</a>
|
||||||
<a v-if="daten?.pdf" class="knopf klein sekundaer" :href="api.pdfUrl(topic)" download>PDF</a>
|
<a v-if="daten?.pdf" class="knopf klein sekundaer" :href="api.pdfUrl(topic)" download>PDF</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,6 +184,6 @@ onUnmounted(() => window.removeEventListener('keydown', taste))
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Lesemodus v-if="lesemodus && daten" :daten="daten" :topic="topic" @schliessen="lesemodus = false" />
|
<Lesemodus v-if="lesemodus && daten" :daten="daten" :topic="topic" @schliessen="lesemodusEnde" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function reset() { if (confirm('Lauf zurücksetzen? Alles außer dem Thema wird
|
|||||||
<div class="aktionen">
|
<div class="aktionen">
|
||||||
<button v-if="!laeuft && !fertig" @click="emit('start')">{{ begonnen ? 'Fortsetzen' : 'Buch erzeugen' }}</button>
|
<button v-if="!laeuft && !fertig" @click="emit('start')">{{ begonnen ? 'Fortsetzen' : 'Buch erzeugen' }}</button>
|
||||||
<button v-if="laeuft" class="sekundaer" @click="emit('pause')">Pause</button>
|
<button v-if="laeuft" class="sekundaer" @click="emit('pause')">Pause</button>
|
||||||
<button v-if="!laeuft && begonnen" class="sekundaer" @click="reset">Zurücksetzen</button>
|
<button v-if="!laeuft && begonnen && !fertig" class="sekundaer" @click="reset">Zurücksetzen</button>
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
<span class="badge" :class="statusFarbe[state.status]">{{ statusText[state.status] || state.status }}<template v-if="state.stufe && laeuft"> · {{ state.stufe }}</template></span>
|
<span class="badge" :class="statusFarbe[state.status]">{{ statusText[state.status] || state.status }}<template v-if="state.stufe && laeuft"> · {{ state.stufe }}</template></span>
|
||||||
<span class="badge">{{ usd(state.kosten_usd) }}</span>
|
<span class="badge">{{ usd(state.kosten_usd) }}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user