An app for logging board climbs
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add import export logbook in the settings

+75
+60
www/routes/settings.ts
··· 1 + import app from '../models/app.ts' 2 + 1 3 const BOARD_OPTIONS = [ 2 4 { mb_type: 0, label: '2016 40°' }, 3 5 { mb_type: 1, label: '2017 25°' }, ··· 30 32 this.gradeScale = localStorage.getItem('grade_scale') ?? 'french' 31 33 this.render() 32 34 this.bindEvents() 35 + } 36 + 37 + disconnectedCallback() { 38 + this.removeEventListener('click', this.#handleClick) 33 39 } 34 40 35 41 private render(): void { ··· 76 82 } 77 83 </div> 78 84 </section> 85 + 86 + <section> 87 + <h2>Logbook Data</h2> 88 + <p>Export your logbook to a file, or import a previously exported file.</p> 89 + <div class="settings-data-actions"> 90 + <button class="action" id="settings-export">Export logbook</button> 91 + <button class="action" id="settings-import">Import logbook</button> 92 + </div> 93 + <p id="settings-data-status" class="settings-data-status" hidden></p> 94 + </section> 79 95 ` 80 96 } 81 97 98 + #handleClick = (e: Event) => { 99 + const target = e.target as HTMLElement 100 + if (target.closest('#settings-export')) { 101 + this.#handleExport() 102 + } else if (target.closest('#settings-import')) { 103 + this.#handleImport() 104 + } 105 + } 106 + 107 + #setStatus(msg: string, isError = false): void { 108 + const el = this.querySelector<HTMLElement>('#settings-data-status') 109 + if (!el) return 110 + el.textContent = msg 111 + el.hidden = false 112 + el.className = isError 113 + ? 'settings-data-status settings-data-status--error' 114 + : 'settings-data-status' 115 + } 116 + 117 + async #handleExport(): Promise<void> { 118 + const btn = this.querySelector<HTMLButtonElement>('#settings-export') 119 + if (btn) btn.disabled = true 120 + const result = await app.exportStore() 121 + if (btn) btn.disabled = false 122 + if (result.success) { 123 + this.#setStatus('Logbook exported successfully.') 124 + } else { 125 + this.#setStatus(result.error ?? 'Export failed.', true) 126 + } 127 + } 128 + 129 + async #handleImport(): Promise<void> { 130 + const btn = this.querySelector<HTMLButtonElement>('#settings-import') 131 + if (btn) btn.disabled = true 132 + const result = await app.importStore() 133 + if (btn) btn.disabled = false 134 + if (result.success) { 135 + this.#setStatus('Logbook imported successfully.') 136 + } else { 137 + this.#setStatus(result.error ?? 'Import failed.', true) 138 + } 139 + } 140 + 82 141 private bindEvents(): void { 142 + this.addEventListener('click', this.#handleClick) 83 143 this.querySelectorAll<HTMLInputElement>('input[name="mb_type"]').forEach( 84 144 (input) => { 85 145 input.addEventListener('change', (e) => {
+15
www/static/theme.css
··· 687 687 margin-top: 2px; 688 688 } 689 689 690 + .settings-data-actions { 691 + display: flex; 692 + gap: var(--s3); 693 + } 694 + 695 + .settings-data-status { 696 + margin-top: var(--s3); 697 + font-size: var(--f6); 698 + opacity: 0.8; 699 + } 700 + 701 + .settings-data-status--error { 702 + color: var(--danger, #e05); 703 + } 704 + 690 705 /* ── Logbook session dialog ─────────────────────────────────────────────── */ 691 706 692 707 .lb-overlay {