added statistics-tab to settings
authorPhiTux <redacted>
Mon, 8 Sep 2025 14:26:03 +0000 (16:26 +0200)
committerPhiTux <redacted>
Mon, 8 Sep 2025 14:26:03 +0000 (16:26 +0200)
backend/handlers/additional.go
backend/main.go
frontend/src/lib/SettingsNav.svelte [new file with mode: 0644]
frontend/src/lib/settings/Admin.svelte [new file with mode: 0644]
frontend/src/lib/settings/Statistics.svelte [new file with mode: 0644]
frontend/src/routes/(authed)/+layout.svelte
frontend/src/routes/(authed)/write/+page.svelte

index 33871c4943db70db24a97f0b923339f10ee3a096..cf391b22bd970f48c93573d36f3a20543158df8d 100644 (file)
@@ -2625,159 +2625,129 @@ func renderMarkdownToHTML(text string) string {
        return string(htmlBytes)
 }
 
-/*
-// BACKUP: Old custom markdown renderer - kept for reference
-// renderMarkdownToHTML converts simple markdown to HTML
-func renderMarkdownToHTML_OLD(text string) string {
-       lines := strings.Split(text, "\n")
-       var result strings.Builder
-       var inCodeBlock bool
-       var codeBlockContent strings.Builder
-       var codeLanguage string
-
-       for _, line := range lines {
-               // Handle code blocks
-               if strings.HasPrefix(line, "```") {
-                       if !inCodeBlock {
-                               // Starting a code block
-                               inCodeBlock = true
-                               codeLanguage = strings.TrimSpace(line[3:])
-                               codeBlockContent.Reset()
-                               continue
-                       } else {
-                               // Ending a code block
-                               inCodeBlock = false
-                               codeContent := codeBlockContent.String()
-                               if codeLanguage != "" {
-                                       result.WriteString(fmt.Sprintf(`<pre><code class="language-%s">%s</code></pre>`,
-                                               htmlpkg.EscapeString(codeLanguage), htmlpkg.EscapeString(codeContent)))
-                               } else {
-                                       result.WriteString(fmt.Sprintf(`<pre><code>%s</code></pre>`,
-                                               htmlpkg.EscapeString(codeContent)))
-                               }
-                               codeLanguage = ""
-                               continue
-                       }
-               }
-
-               // If we're in a code block, accumulate the content
-               if inCodeBlock {
-                       if codeBlockContent.Len() > 0 {
-                               codeBlockContent.WriteString("\n")
-                       }
-                       codeBlockContent.WriteString(line)
-                       continue
-               }
-
-               // Normal line processing (when not in code block)
-               line = strings.TrimSpace(line)
-
-               if line == "" {
-                       result.WriteString("<br>")
-                       continue
-               }
-
-               // Handle headings
-               if strings.HasPrefix(line, "###") {
-                       content := strings.TrimSpace(line[3:])
-                       result.WriteString(fmt.Sprintf("<h3>%s</h3>", htmlpkg.EscapeString(content)))
-                       continue
-               }
-               if strings.HasPrefix(line, "##") {
-                       content := strings.TrimSpace(line[2:])
-                       result.WriteString(fmt.Sprintf("<h2>%s</h2>", htmlpkg.EscapeString(content)))
-                       continue
-               }
-               if strings.HasPrefix(line, "#") {
-                       content := strings.TrimSpace(line[1:])
-                       result.WriteString(fmt.Sprintf("<h1>%s</h1>", htmlpkg.EscapeString(content)))
-                       continue
-               }
-
-               // Handle list items
-               if strings.HasPrefix(line, "- ") || strings.HasPrefix(line, "* ") {
-                       content := strings.TrimSpace(line[2:])
-                       content = renderInlineMarkdownToHTML(content)
-                       result.WriteString(fmt.Sprintf("<ul><li>%s</li></ul>", content))
-                       continue
-               }
-
-               // Handle blockquotes
-               if strings.HasPrefix(line, "> ") {
-                       content := strings.TrimSpace(line[2:])
-                       content = renderInlineMarkdownToHTML(content)
-                       result.WriteString(fmt.Sprintf("<blockquote>%s</blockquote>", content))
-                       continue
-               }
+// Load user statistics:
+// - each logged day with amount of words for each day
+// - amount of files for each day
+// - tags for each day
+func GetStatistics(w http.ResponseWriter, r *http.Request) {
+       // Get user ID and derived key from context
+       userID, ok := r.Context().Value(utils.UserIDKey).(int)
+       if !ok {
+               http.Error(w, "Unauthorized", http.StatusUnauthorized)
+               return
+       }
+       derivedKey, ok := r.Context().Value(utils.DerivedKeyKey).(string)
+       if !ok {
+               http.Error(w, "Unauthorized", http.StatusUnauthorized)
+               return
+       }
 
-               // Regular paragraph with inline formatting
-               line = renderInlineMarkdownToHTML(line)
-               result.WriteString(fmt.Sprintf("<p>%s</p>", line))
+       // Prepare encryption key for decrypting texts and filenames
+       encKey, err := utils.GetEncryptionKey(userID, derivedKey)
+       if err != nil {
+               http.Error(w, fmt.Sprintf("Error getting encryption key: %v", err), http.StatusInternalServerError)
+               return
        }
 
-       // Handle unclosed code block
-       if inCodeBlock {
-               codeContent := codeBlockContent.String()
-               if codeLanguage != "" {
-                       result.WriteString(fmt.Sprintf(`<pre><code class="language-%s">%s</code></pre>`,
-                               htmlpkg.EscapeString(codeLanguage), htmlpkg.EscapeString(codeContent)))
-               } else {
-                       result.WriteString(fmt.Sprintf(`<pre><code>%s</code></pre>`,
-                               htmlpkg.EscapeString(codeContent)))
-               }
+       // Define response structure (per day only)
+       type DayStat struct {
+               Year         int   `json:"year"`
+               Month        int   `json:"month"`
+               Day          int   `json:"day"`
+               WordCount    int   `json:"wordCount"`
+               FileCount    int   `json:"fileCount"`
+               Tags         []int `json:"tags"`
+               IsBookmarked bool  `json:"isBookmarked"`
        }
 
-       return result.String()
-}
+       dayStats := []DayStat{}
 
-// renderInlineMarkdownToHTML processes inline markdown formatting
-func renderInlineMarkdownToHTML_OLD(text string) string {
-       // Escape HTML first
-       text = htmlpkg.EscapeString(text)
-
-       // Links with title: [text](url "title")
-       linkWithTitleRegex := regexp.MustCompile(`\[([^\]]+)\]\(([^)]+)\s+"([^"]+)"\)`)
-       text = linkWithTitleRegex.ReplaceAllStringFunc(text, func(match string) string {
-               matches := linkWithTitleRegex.FindStringSubmatch(match)
-               if len(matches) == 4 {
-                       linkText := matches[1]
-                       url := matches[2]
-                       title := matches[3]
-                       return fmt.Sprintf(`<a href="%s" title="%s" target="_blank" rel="noopener noreferrer">%s</a>`, url, title, linkText)
-               }
-               return match
-       })
+       // Get all years
+       years, err := utils.GetYears(userID)
+       if err != nil {
+               http.Error(w, fmt.Sprintf("Error retrieving years: %v", err), http.StatusInternalServerError)
+               return
+       }
 
-       // Links without title: [text](url)
-       linkRegex := regexp.MustCompile(`\[([^\]]+)\]\(([^)]+)\)`)
-       text = linkRegex.ReplaceAllStringFunc(text, func(match string) string {
-               matches := linkRegex.FindStringSubmatch(match)
-               if len(matches) == 3 {
-                       linkText := matches[1]
-                       url := matches[2]
-                       return fmt.Sprintf(`<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>`, url, linkText)
+       // Iterate years and months
+       for _, yearStr := range years {
+               yearInt, _ := strconv.Atoi(yearStr)
+               months, err := utils.GetMonths(userID, yearStr)
+               if err != nil {
+                       continue // skip problematic year
                }
-               return match
-       })
+               for _, monthStr := range months {
+                       monthInt, _ := strconv.Atoi(monthStr)
+                       content, err := utils.GetMonth(userID, yearInt, monthInt)
+                       if err != nil {
+                               continue
+                       }
+                       daysArr, ok := content["days"].([]any)
+                       if !ok {
+                               continue
+                       }
+                       for _, dayInterface := range daysArr {
+                               dayMap, ok := dayInterface.(map[string]any)
+                               if !ok {
+                                       continue
+                               }
+                               dayNumFloat, ok := dayMap["day"].(float64)
+                               if !ok {
+                                       continue
+                               }
+                               dayNum := int(dayNumFloat)
+
+                               // Word count (decrypt text if present)
+                               wordCount := 0
+                               if encText, ok := dayMap["text"].(string); ok && encText != "" {
+                                       if decrypted, err := utils.DecryptText(encText, encKey); err == nil {
+                                               // Count words using Fields (splits on any whitespace)
+                                               words := strings.Fields(decrypted)
+                                               wordCount = len(words)
+                                       }
+                               }
 
-       // Bold (**text** or __text__)
-       boldRegex := regexp.MustCompile(`\*\*(.*?)\*\*`)
-       text = boldRegex.ReplaceAllString(text, "<strong>$1</strong>")
+                               // File count (filenames stored decrypted in memory? If encrypted we try decrypt to validate)
+                               fileCount := 0
+                               if filesAny, ok := dayMap["files"].([]any); ok {
+                                       fileCount = len(filesAny)
+                               }
 
-       boldRegex2 := regexp.MustCompile(`__(.*?)__`)
-       text = boldRegex2.ReplaceAllString(text, "<strong>$1</strong>")
+                               // Tags (IDs are numeric)
+                               var tagIDs []int
+                               if tagsAny, ok := dayMap["tags"].([]any); ok {
+                                       for _, t := range tagsAny {
+                                               if tf, ok := t.(float64); ok {
+                                                       tagIDs = append(tagIDs, int(tf))
+                                               }
+                                       }
+                               }
 
-       // Italic (*text* or _text_)
-       italicRegex := regexp.MustCompile(`\*(.*?)\*`)
-       text = italicRegex.ReplaceAllString(text, "<em>$1</em>")
+                               // Bookmark flag
+                               isBookmarked := false
+                               if bmRaw, ok := dayMap["isBookmarked"]; ok {
+                                       if b, ok2 := bmRaw.(bool); ok2 {
+                                               isBookmarked = b
+                                       } else if f, ok2 := bmRaw.(float64); ok2 { // if stored as number
+                                               isBookmarked = f != 0
+                                       }
+                               }
 
-       italicRegex2 := regexp.MustCompile(`_(.*?)_`)
-       text = italicRegex2.ReplaceAllString(text, "<em>$1</em>")
+                               dayStats = append(dayStats, DayStat{
+                                       Year:         yearInt,
+                                       Month:        monthInt,
+                                       Day:          dayNum,
+                                       WordCount:    wordCount,
+                                       FileCount:    fileCount,
+                                       Tags:         tagIDs,
+                                       IsBookmarked: isBookmarked,
+                               })
+                       }
+               }
+       }
 
-       // Code (`text`)
-       codeRegex := regexp.MustCompile("`(.*?)`")
-       text = codeRegex.ReplaceAllString(text, "<code>$1</code>")
+       // Sort days by date descending (latest first) if desired; currently ascending by traversal. Keep ascending.
 
-       return text
+       w.Header().Set("Content-Type", "application/json")
+       json.NewEncoder(w).Encode(dayStats)
 }
-*/
index e430cdead3ef2b5867082370fb9f9fa6fafdbdb2..ea344c52a8964aeac4b48c36ef06405ea8014043 100644 (file)
@@ -65,6 +65,7 @@ func main() {
        mux.HandleFunc("POST /users/changePassword", middleware.RequireAuth(handlers.ChangePassword))
        mux.HandleFunc("POST /users/deleteAccount", middleware.RequireAuth(handlers.DeleteAccount))
        mux.HandleFunc("POST /users/createBackupCodes", middleware.RequireAuth(handlers.CreateBackupCodes))
+       mux.HandleFunc("GET /users/statistics", middleware.RequireAuth(handlers.GetStatistics))
 
        mux.HandleFunc("POST /logs/saveLog", middleware.RequireAuth(handlers.SaveLog))
        mux.HandleFunc("GET /logs/getLog", middleware.RequireAuth(handlers.GetLog))
diff --git a/frontend/src/lib/SettingsNav.svelte b/frontend/src/lib/SettingsNav.svelte
new file mode 100644 (file)
index 0000000..e44e5cf
--- /dev/null
@@ -0,0 +1,13 @@
+<script context="module">
+       // main navigation for the application
+       import Settings from '$lib/Settings.svelte';
+       import Statistics from '$lib/Statistics.svelte';
+       import Admin from '$lib/Admin.svelte';
+
+       // these are our 'pages' to navigate through (in order for this export to work the script tag MUST include context="module")
+       export const navOptions = [
+               { page: 'Settings', component: Settings },
+               { page: 'Statistics', component: Statistics },
+               { page: 'Admin', component: Admin }
+       ];
+</script>
diff --git a/frontend/src/lib/settings/Admin.svelte b/frontend/src/lib/settings/Admin.svelte
new file mode 100644 (file)
index 0000000..2576bf7
--- /dev/null
@@ -0,0 +1,15 @@
+<script>
+       import { getTranslate } from '@tolgee/svelte';
+       const { t } = getTranslate();
+</script>
+
+<div class="settings-admin">
+       <h2 class="h4 mb-3">{$t('settings.admin.title')}</h2>
+       <p class="text-muted">{$t('settings.admin.placeholder')}</p>
+</div>
+
+<style>
+       .settings-admin {
+               min-height: 40vh;
+       }
+</style>
diff --git a/frontend/src/lib/settings/Statistics.svelte b/frontend/src/lib/settings/Statistics.svelte
new file mode 100644 (file)
index 0000000..8a7a8b8
--- /dev/null
@@ -0,0 +1,582 @@
+<script>
+       import { API_URL } from '$lib/APIurl';
+       import { getTranslate } from '@tolgee/svelte';
+       import axios from 'axios';
+       import { onMount } from 'svelte';
+       import Tag from '$lib/Tag.svelte';
+       import { tags } from '$lib/tagStore';
+       import { get } from 'svelte/store';
+       import * as bootstrap from 'bootstrap';
+       import { mount } from 'svelte';
+       import { goto } from '$app/navigation';
+       import { selectedDate } from '$lib/calendarStore.js';
+
+       const { t } = getTranslate();
+
+       // Raw day stats from backend
+       let dayStats = [];
+
+       // Derived years list & selected year
+       let years = [];
+       let selectedYear = new Date().getFullYear();
+
+       // Heatmap data (weeks -> days)
+       let weeks = [];
+       let maxWordCountYear = 0;
+       let minWordCountYear = 0; // smallest > 0 value
+       // Filter stats for selected year
+       // Iterate all days of the year
+       let legendRanges = [];
+       // Bootstrap tooltip support
+       let heatmapEl;
+       let dayMap = new Map(); // key -> day data
+
+       const buildYearData = () => {
+               if (!years.includes(selectedYear)) return;
+
+               // Filter stats for selected year
+               const yearDays = dayStats.filter((d) => d.year === selectedYear);
+               const mapByKey = new Map();
+               let localMax = 0;
+               let localMin = Infinity;
+               for (const d of yearDays) {
+                       const key = `${d.year}-${String(d.month).padStart(2, '0')}-${String(d.day).padStart(2, '0')}`;
+                       mapByKey.set(key, d);
+                       if (d.wordCount > localMax) localMax = d.wordCount;
+                       if (d.wordCount > 0 && d.wordCount < localMin) localMin = d.wordCount;
+               }
+               maxWordCountYear = localMax;
+               minWordCountYear = localMin === Infinity ? 0 : localMin;
+
+               buildLegendRanges();
+
+               // Iterate all days of the year
+               const first = new Date(selectedYear, 0, 1);
+               const last = new Date(selectedYear, 11, 31);
+               // Build sequential weeks starting Monday (GitHub uses Sunday start; we use Monday for EU style)
+               // Pre-fill leading empty cells
+               // If week complete, push and start a new one
+               // Push trailing week if it contains any filled cells
+               const thresholds = [0.15, 0.35, 0.65]; // thresholds between intensity levels
+               // Map ratio ranges to integer word ranges
+               const weekdayIndex = (d) => (d.getDay() + 6) % 7;
+               let current = new Date(first);
+               weeks = [];
+               let currentWeek = new Array(7).fill(null);
+               // Pre-fill leading empty cells
+               for (let i = 0; i < weekdayIndex(current); i++) {
+                       currentWeek[i] = { empty: true };
+               }
+               while (current <= last) {
+                       const idx = weekdayIndex(current);
+                       const key = `${current.getFullYear()}-${String(current.getMonth() + 1).padStart(2, '0')}-${String(current.getDate()).padStart(2, '0')}`;
+                       const stat = mapByKey.get(key);
+                       const wordCount = stat ? stat.wordCount : 0;
+                       const isBookmarked = stat ? stat.isBookmarked : false;
+                       currentWeek[idx] = {
+                               date: new Date(current),
+                               wordCount,
+                               isBookmarked,
+                               tags: stat ? stat.tags : [],
+                               fileCount: stat ? stat.fileCount : 0
+                       };
+                       // If week complete, push and start new
+                       if (idx === 6) {
+                               weeks.push(currentWeek);
+                               currentWeek = new Array(7).fill(null);
+                       }
+                       // Advance to the next day
+                       current.setDate(current.getDate() + 1);
+               }
+               // Push trailing week if contains any filled cells
+               if (currentWeek.some((c) => c !== null)) weeks.push(currentWeek);
+
+               // Rebuild day map for tooltips
+               dayMap.clear();
+               for (let wi = 0; wi < weeks.length; wi++) {
+                       const w = weeks[wi];
+                       for (let di = 0; di < w.length; di++) {
+                               const d = w[di];
+                               if (d && !d.empty) dayMap.set(`${wi}-${di}`, d);
+                       }
+               }
+
+               // Initialize / refresh bootstrap tooltips after DOM update
+               setTimeout(initTooltips, 0);
+       };
+
+       const thresholds = [0.15, 0.35, 0.65]; // thresholds between levels
+       function buildLegendRanges() {
+               legendRanges = [];
+               if (maxWordCountYear === 0) {
+                       legendRanges = [
+                               { level: 0, from: 0, to: 0 },
+                               { level: 1, from: 0, to: 0 },
+                               { level: 2, from: 0, to: 0 },
+                               { level: 3, from: 0, to: 0 },
+                               { level: 4, from: 0, to: 0 }
+                       ];
+                       return;
+               }
+               // Map ratio ranges to integer word ranges
+               const segments = [
+                       { level: 0, rFrom: 0, rTo: 0 },
+                       { level: 1, rFrom: 0.0000001, rTo: thresholds[0] },
+                       { level: 2, rFrom: thresholds[0], rTo: thresholds[1] },
+                       { level: 3, rFrom: thresholds[1], rTo: thresholds[2] },
+                       { level: 4, rFrom: thresholds[2], rTo: 1 }
+               ];
+               legendRanges = segments.map((s) => {
+                       const from =
+                               s.level === 0 ? 0 : Math.max(minWordCountYear, Math.floor(s.rFrom * maxWordCountYear) || 1);
+                       let to = Math.floor(s.rTo * maxWordCountYear);
+                       if (s.level === 4) to = maxWordCountYear; // last covers top
+                       if (to < from) to = from; // ensure non-inverted
+                       return { level: s.level, from, to };
+               });
+       }
+
+       const colorLevel = (wc) => {
+               if (wc <= 0) return 0;
+               if (maxWordCountYear <= 0) return 0;
+               const r = wc / maxWordCountYear;
+               if (r < thresholds[0]) return 1;
+               if (r < thresholds[1]) return 2;
+               if (r < thresholds[2]) return 3;
+               return 4;
+       };
+
+       function selectYear(year) {
+               selectedYear = year;
+               buildYearData();
+       }
+
+       function prevYear() {
+               const idx = years.indexOf(selectedYear);
+               if (idx > 0) {
+                       selectedYear = years[idx - 1];
+                       buildYearData();
+               }
+       }
+       function nextYear() {
+               const idx = years.indexOf(selectedYear);
+               if (idx !== -1 && idx < years.length - 1) {
+                       selectedYear = years[idx + 1];
+                       buildYearData();
+               }
+       }
+
+       const fmtDate = (d) =>
+               d.toLocaleDateString(undefined, {
+                       weekday: 'long',
+                       year: 'numeric',
+                       month: '2-digit',
+                       day: '2-digit'
+               });
+
+       onMount(async () => {
+               try {
+                       const resp = await axios.get(API_URL + '/users/statistics');
+                       dayStats = resp.data;
+                       // Normalize key names to camelCase if backend sent lower-case
+                       dayStats = dayStats.map((d) => ({
+                               year: d.year ?? d.Year,
+                               month: d.month ?? d.Month,
+                               day: d.day ?? d.Day,
+                               wordCount: d.wordCount ?? d.WordCount ?? 0,
+                               fileCount: d.fileCount ?? d.FileCount ?? 0,
+                               tags: d.tags ?? d.Tags ?? [],
+                               isBookmarked: d.isBookmarked ?? d.IsBookmarked ?? false
+                       }));
+                       // Collect years
+                       years = Array.from(new Set(dayStats.map((d) => d.year))).sort((a, b) => a - b);
+                       if (!years.includes(selectedYear) && years.length) selectedYear = years[years.length - 1];
+                       buildYearData();
+               } catch (e) {
+                       console.error('Failed loading statistics', e);
+               }
+       });
+
+       // Build HTML skeleton for popover (tags get injected after show)
+       function tooltipHTML(day) {
+               const html = `
+                       <div class="popover-day-content">
+                               <div class="tt-head"><b>${fmtDate(day.date)}</b></div>
+                               <div class="tt-line">${$t('settings.statistics.wordCount', { wordCount: day.wordCount })}</div>
+                               ${day.fileCount ? `<div class='tt-line'>${$t('settings.statistics.fileCount', { fileCount: day.fileCount })}</div>` : ''}
+                               ${day.isBookmarked ? `<div class='tt-line'>★ ${$t('settings.statistics.bookmarked')}</div>` : ''}
+                               <div class="tt-tags"></div>
+                               <div class="tt-footer">
+                                       <button type="button" class="tt-open-btn" data-year="${day.date.getFullYear()}" data-month="${day.date.getMonth() + 1}" data-day="${day.date.getDate()}">
+                                               📝 ${$t('settings.statistics.open')}
+                                       </button>
+                               </div>
+                       </div>`;
+               console.log('Generated popover HTML:', html);
+               return html;
+       }
+
+       // Function to open a specific date in /write
+       function openDate(year, month, day) {
+               console.log('Open date', year, month, day);
+
+               // Set the selected date
+               $selectedDate = {
+                       year: parseInt(year),
+                       month: parseInt(month),
+                       day: parseInt(day)
+               };
+
+               // Close the settings modal (assuming it's a Bootstrap modal)
+               const settingsModal = document.querySelector('#settingsModal');
+               if (settingsModal) {
+                       const modalInstance = bootstrap.Modal.getInstance(settingsModal);
+                       if (modalInstance) {
+                               modalInstance.hide();
+                       }
+               }
+
+               // Navigate to write page
+               goto('/write');
+       }
+
+       function initTooltips() {
+               // Dispose previous instances for day cells
+               document.querySelectorAll('.day-cell[data-bs-toggle="popover"]').forEach((el) => {
+                       const inst = bootstrap.Popover.getInstance(el);
+                       if (inst) inst.dispose();
+               });
+
+               // Dispose previous instances for legend cells (keep as tooltips)
+               document.querySelectorAll('.legend-cell[data-bs-toggle="tooltip"]').forEach((el) => {
+                       const inst = bootstrap.Tooltip.getInstance(el);
+                       if (inst) inst.dispose();
+               });
+
+               // Initialize day cell popovers
+               const cells = heatmapEl?.querySelectorAll('.day-cell[data-day-key]') || [];
+               console.log('Initializing popovers for', cells.length, 'cells');
+               cells.forEach((el, index) => {
+                       const key = el.getAttribute('data-day-key');
+                       const day = dayMap.get(key);
+                       if (!day) return;
+                       
+                       const htmlContent = tooltipHTML(day);
+                       el.setAttribute('data-bs-content', htmlContent);
+                       el.setAttribute('data-bs-toggle', 'popover');
+                       
+                       console.log(`Initializing popover ${index} with content:`, htmlContent);
+                       
+                       const popover = new bootstrap.Popover(el, {
+                               html: true,
+                               placement: 'top',
+                               trigger: 'click',
+                               animation: false,
+                               container: 'body',
+                               sanitize: false // Disable sanitization to allow our HTML
+                       });
+
+                       // Test if popover is created
+                       console.log('Popover instance created:', popover);
+
+                       // Close other popovers when this one is shown
+                       el.addEventListener('show.bs.popover', () => {
+                               console.log('Popover showing for key:', key);
+                               // Close all other popovers
+                               document.querySelectorAll('.day-cell[data-bs-toggle="popover"]').forEach((otherEl) => {
+                                       if (otherEl !== el) {
+                                               const otherInst = bootstrap.Popover.getInstance(otherEl);
+                                               if (otherInst) otherInst.hide();
+                                       }
+                               });
+                       });
+
+                       // After popover is shown, mount Tag components and setup button handlers
+                       const populate = () => {
+                               console.log('Popover populate called for key:', key);
+                               const inst = bootstrap.Popover.getInstance(el);
+                               if (!inst) {
+                                       console.log('No popover instance found');
+                                       return;
+                               }
+                               const popoverEl = typeof inst.getTipElement === 'function' ? inst.getTipElement() : inst.tip;
+                               console.log('Popover element:', popoverEl);
+                               
+                               const tagContainer = popoverEl?.querySelector('.tt-tags');
+                               const openBtn = popoverEl?.querySelector('.tt-open-btn');
+                               console.log('Found elements - tags:', tagContainer, 'button:', openBtn);
+                               
+                               if (!tagContainer || tagContainer.dataset.populated === '1') return;
+                               // Mark to avoid double work
+                               tagContainer.dataset.populated = '1';
+                               const allTagsNow = get(tags) || [];
+                               (day.tags || []).forEach((tid) => {
+                                       const tagObj = allTagsNow.find((t) => t.id == tid);
+                                       if (tagObj) {
+                                               mount(Tag, { target: tagContainer, props: { tag: tagObj } });
+                                       }
+                               });
+
+                               // Setup button handler
+                               if (openBtn && !openBtn.dataset.handlerAdded) {
+                                       console.log('Adding click handler to button');
+                                       openBtn.dataset.handlerAdded = '1';
+                                       openBtn.addEventListener('click', (e) => {
+                                               console.log('Open date click', e.target, e.currentTarget);
+                                               e.preventDefault();
+                                               e.stopPropagation();
+                                               
+                                               // Get attributes from the clicked element or fallback to currentTarget
+                                               const target = e.target.closest('.tt-open-btn') || e.currentTarget;
+                                               const year = target.getAttribute('data-year');
+                                               const month = target.getAttribute('data-month');
+                                               const day = target.getAttribute('data-day');
+                                               
+                                               console.log('Extracted date:', { year, month, day });
+                                               
+                                               if (year && month && day) {
+                                                       // Hide popover first
+                                                       const inst = bootstrap.Popover.getInstance(el);
+                                                       if (inst) inst.hide();
+                                                       
+                                                       openDate(year, month, day);
+                                               }
+                                       });
+                               }
+                       };
+                       
+                       // Listen for popover events
+                       el.addEventListener('inserted.bs.popover', populate);
+                       el.addEventListener('shown.bs.popover', populate);
+               });
+
+               // Initialize legend cell tooltips (keep as simple tooltips)
+               const legendCells = document.querySelectorAll('.legend-cell[data-bs-toggle="tooltip"]');
+               legendCells.forEach((el) => {
+                       new bootstrap.Tooltip(el, {
+                               placement: 'top',
+                               trigger: 'hover focus'
+                       });
+               });
+
+               // Close popovers when clicking outside
+               document.addEventListener('click', (e) => {
+                       // Check if click is outside any day-cell and outside any popover
+                       if (!e.target.closest('.day-cell[data-bs-toggle="popover"]') && !e.target.closest('.popover')) {
+                               document.querySelectorAll('.day-cell[data-bs-toggle="popover"]').forEach((el) => {
+                                       const inst = bootstrap.Popover.getInstance(el);
+                                       if (inst) inst.hide();
+                               });
+                       }
+               }, { capture: true }); // Use capture to ensure this runs before other handlers
+       }
+</script>
+
+<div class="settings-stats">
+       <h2 class="h4 mb-3">{$t('settings.statistics.title')}</h2>
+
+       {#if years.length === 0}
+               <div class="spinner-border" role="status">
+                       <span class="visually-hidden">Loading...</span>
+               </div>
+       {:else}
+               <div class="year-selector d-flex align-items-center gap-2 mb-3 flex-wrap">
+                       <button
+                               class="btn btn-sm btn-outline-secondary"
+                               on:click={prevYear}
+                               disabled={years.indexOf(selectedYear) === 0}
+                               aria-label="previous year">«</button
+                       >
+                       <select
+                               class="form-select form-select-sm year-dropdown"
+                               bind:value={selectedYear}
+                               on:change={(e) => selectYear(+e.target.value)}
+                       >
+                               {#each years as y}
+                                       <option value={y}>{y}</option>
+                               {/each}
+                       </select>
+                       <button
+                               class="btn btn-sm btn-outline-secondary"
+                               on:click={nextYear}
+                               disabled={years.indexOf(selectedYear) === years.length - 1}
+                               aria-label="next year">»</button
+                       >
+                       <div class="legend ms-auto d-flex align-items-center gap-1">
+                               <span class="legend-label small">{$t('settings.statistics.legend')}</span>
+                               <div class="legend-colors d-flex align-items-center gap-1">
+                                       {#each legendRanges as seg}
+                                               <span
+                                                       class="legend-cell level-{seg.level}"
+                                                       data-bs-toggle="tooltip"
+                                                       data-bs-title={`${seg.from} – ${seg.to} ${$t('settings.statistics.words')}`}
+                                               ></span>
+                                       {/each}
+                               </div>
+                       </div>
+               </div>
+
+               <div class="heatmap" aria-label="Year-Heatmap" bind:this={heatmapEl}>
+                       <div class="weeks d-flex">
+                               {#each weeks as week, wi}
+                                       <div class="week-column d-flex flex-column">
+                                               {#each week as day, di}
+                                                       {#if day === null || day.empty}
+                                                               <div class="day-cell empty" aria-hidden="true"></div>
+                                                       {:else}
+                                                               <div
+                                                                       class="day-cell level-{colorLevel(day.wordCount)}"
+                                                                       role="button"
+                                                                       tabindex="0"
+                                                                       data-bs-toggle="popover"
+                                                                       data-day-key={`${wi}-${di}`}
+                                                               >
+                                                                       {#if day.isBookmarked}
+                                                                               <span class="bookmark" aria-label="Bookmarked">★</span>
+                                                                       {/if}
+                                                               </div>
+                                                       {/if}
+                                               {/each}
+                                       </div>
+                               {/each}
+                       </div>
+               </div>
+       {/if}
+</div>
+
+<style>
+       .settings-stats {
+               min-height: 40vh;
+       }
+       .year-selector .year-dropdown {
+               width: auto;
+       }
+       .heatmap {
+               overflow-x: auto;
+               position: relative; /* ensure tooltip absolute coords are relative to heatmap */
+               border: 1px solid var(--bs-border-color, #ddd);
+               padding: 0.5rem;
+               border-radius: 0.5rem;
+               background: var(--bs-body-bg, #fff);
+       }
+       .week-column {
+               gap: 3px;
+       }
+       .weeks {
+               gap: 3px;
+       }
+       .day-cell {
+               width: 14px;
+               height: 14px;
+               border-radius: 3px;
+               position: relative;
+               display: flex;
+               align-items: center;
+               justify-content: center;
+       }
+       .day-cell.empty {
+               background: transparent;
+       }
+       /* Color scale (adjust to theme) */
+       .level-0 {
+               background: var(--heatmap-empty, #ebedf0);
+       }
+       .level-1 {
+               background: #c6e48b;
+       }
+       .level-2 {
+               background: #7bc96f;
+       }
+       .level-3 {
+               background: #239a3b;
+       }
+       .level-4 {
+               background: #196127;
+       }
+       .day-cell:hover {
+               outline: 1px solid #333;
+               z-index: 2;
+       }
+       .legend-cell {
+               width: 14px;
+               height: 14px;
+               border-radius: 3px;
+               display: inline-block;
+       }
+       .legend-cell.level-0 {
+               background: var(--heatmap-empty, #ebedf0);
+       }
+       .legend-cell.level-1 {
+               background: #c6e48b;
+       }
+       .legend-cell.level-2 {
+               background: #7bc96f;
+       }
+       .legend-cell.level-3 {
+               background: #239a3b;
+       }
+       .legend-cell.level-4 {
+               background: #196127;
+       }
+       .bookmark {
+               font-size: 9px;
+               line-height: 1;
+               color: #fff;
+               text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
+       }
+       .day-cell.level-0 .bookmark {
+               color: #555;
+               text-shadow: none;
+       }
+       /* Popover styling (applies inside Bootstrap popover) */
+       :global(.popover-day-content) {
+               min-width: 200px;
+       }
+       :global(.popover-day-content .tt-head) {
+               margin-bottom: 4px;
+               font-size: 14px;
+       }
+       :global(.popover-day-content .tt-tags) {
+               display: flex;
+               flex-wrap: wrap;
+               gap: 4px;
+       }
+       :global(.popover-day-content .tt-tags .badge) {
+               font-size: 12px;
+               margin-right: 4px;
+       }
+       :global(.popover-day-content .tt-footer) {
+               text-align: center;
+               padding-top: 8px;
+       }
+       :global(.popover-day-content .tt-open-btn) {
+               font-size: 12px !important;
+               padding: 6px 12px !important;
+               background: #007bff;
+               color: white;
+               border-radius: 4px;
+               cursor: pointer;
+               border: none;
+               transition: background-color 0.2s;
+       }
+       :global(.popover-day-content .tt-open-btn:hover) {
+               background: #0056b3;
+               color: white;
+       }
+       
+       /* Old tooltip styling (now removed as we use popovers) */
+
+       /* Desktop: Add pointer cursor for day cells */
+       @media (pointer: fine) {
+               .day-cell[data-day-key] {
+                       cursor: pointer;
+               }
+       }
+       @media (max-width: 600px) {
+               .day-cell,
+               .legend-cell {
+                       width: 11px;
+                       height: 11px;
+               }
+       }
+</style>
index ee35fb5d6a12db3196a029fbb4095417507d696d..0fd2b7b14470bc7a4553e17f70264c4aafbdf583 100644 (file)
@@ -31,6 +31,8 @@
        import axios from 'axios';
        import { page } from '$app/state';
        import { blur, slide, fade } from 'svelte/transition';
+       import Statistics from '$lib/settings/Statistics.svelte';
+       import Admin from '$lib/settings/Admin.svelte';
        import { T, getTranslate, getTolgee } from '@tolgee/svelte';
 
        const { t } = getTranslate();
@@ -40,6 +42,9 @@
        let inDuration = 150;
        let outDuration = 150;
 
+       // Active sub-view of settings modal: 'settings' | 'stats' | 'admin'
+       let activeSettingsView = $state('settings');
+
        $effect(() => {
                if ($readingMode === true && page.url.pathname !== '/read') {
                        goto('/read');
        }
 
        function openSettingsModal() {
+               activeSettingsView = 'settings';
                $tempSettings = JSON.parse(JSON.stringify($settings));
                aLookBackYears = $settings.aLookBackYears.toString();
 
        >
                <!--  -->
                <div class="modal-content shadow-lg glass">
-                       <div class="modal-header">
-                               <h1>{$t('settings.title')}</h1>
-                               <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                       <div class="modal-header flex-wrap gap-2">
+                               <div class="btn-group w-100" role="group" aria-label="Settings views">
+                                       <button
+                                               type="button"
+                                               class="btn btn-outline-primary {activeSettingsView === 'settings' ? 'active' : ''}"
+                                               onclick={() => (activeSettingsView = 'settings')}
+                                       >
+                                               {$t('settings.title')}
+                                       </button>
+                                       <button
+                                               type="button"
+                                               class="btn btn-outline-primary {activeSettingsView === 'stats' ? 'active' : ''}"
+                                               onclick={() => (activeSettingsView = 'stats')}
+                                       >
+                                               {$t('settings.statistics.title')}
+                                       </button>
+                                       <button
+                                               type="button"
+                                               class="btn btn-outline-primary {activeSettingsView === 'admin' ? 'active' : ''}"
+                                               onclick={() => (activeSettingsView = 'admin')}
+                                       >
+                                               {$t('settings.admin.title')}
+                                       </button>
+                                       <button type="button" class="btn-close ms-auto" data-bs-dismiss="modal" aria-label="Close"
+                                       ></button>
+                               </div>
                        </div>
                        <div class="modal-body" id="modal-body">
                                <div class="row">
-                                       <div class="col-4 overflow-y-auto d-none d-md-block">
-                                               <nav class="flex-column align-items-stretch" id="settings-nav">
-                                                       <nav class="nav nav-pills flex-column custom-scrollspy-nav">
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'appearance' ? 'active' : ''}"
-                                                                       href="#appearance">{$t('settings.appearance')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'functions' ? 'active' : ''}"
-                                                                       href="#functions">{$t('settings.functions')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'tags' ? 'active' : ''}"
-                                                                       href="#tags">{$t('settings.tags')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'templates' ? 'active' : ''}"
-                                                                       href="#templates">{$t('settings.templates')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'data' ? 'active' : ''}"
-                                                                       href="#data">{$t('settings.data')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'security' ? 'active' : ''}"
-                                                                       href="#security">{$t('settings.security')}</a
-                                                               >
-                                                               <a
-                                                                       class="nav-link mb-1 {activeSettingsSection === 'about' ? 'active' : ''}"
-                                                                       href="#about">{$t('settings.about')}</a
-                                                               >
+                                       {#if activeSettingsView === 'settings'}
+                                               <div class="col-4 overflow-y-auto d-none d-md-block">
+                                                       <nav class="flex-column align-items-stretch" id="settings-nav">
+                                                               <nav class="nav nav-pills flex-column custom-scrollspy-nav">
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'appearance' ? 'active' : ''}"
+                                                                               href="#appearance">{$t('settings.appearance')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'functions' ? 'active' : ''}"
+                                                                               href="#functions">{$t('settings.functions')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'tags' ? 'active' : ''}"
+                                                                               href="#tags">{$t('settings.tags')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'templates' ? 'active' : ''}"
+                                                                               href="#templates">{$t('settings.templates')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'data' ? 'active' : ''}"
+                                                                               href="#data">{$t('settings.data')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'security' ? 'active' : ''}"
+                                                                               href="#security">{$t('settings.security')}</a
+                                                                       >
+                                                                       <a
+                                                                               class="nav-link mb-1 {activeSettingsSection === 'about' ? 'active' : ''}"
+                                                                               href="#about">{$t('settings.about')}</a
+                                                                       >
+                                                               </nav>
                                                        </nav>
-                                               </nav>
-                                       </div>
-                                       <div class="col-12 col-md-8">
-                                               <div
-                                                       class="settings-content overflow-y-auto"
-                                                       data-bs-spy="scroll"
-                                                       data-bs-target="#settings-nav"
-                                                       data-bs-smooth-scroll="true"
-                                                       id="settings-content"
-                                               >
-                                                       <!-- Mobile dropdown (visible on < md) -->
-                                                       <div class="d-md-none position-sticky top-0 p-1 mobile-settings-dropdown">
-                                                               <select
-                                                                       id="settingsSectionSelect"
-                                                                       class="form-select form-select-sm"
-                                                                       bind:value={activeSettingsSection}
-                                                                       onchange={() => scrollToSection(activeSettingsSection)}
-                                                               >
-                                                                       {#each settingsSectionsMeta as sec}
-                                                                               <option value={sec.id}>{$t(sec.labelKey)}</option>
-                                                                       {/each}
-                                                               </select>
-                                                       </div>
-                                                       <div id="appearance">
-                                                               <h3 class="text-primary">🎨 {$t('settings.appearance')}</h3>
-                                                               <div id="lightdark">
-                                                                       {#if $tempSettings.darkModeAutoDetect !== $settings.darkModeAutoDetect || $tempSettings.useDarkMode !== $settings.useDarkMode}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-                                                                       <h5>{$t('settings.light_dark_mode')}</h5>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="darkMode"
-                                                                                       id="darkModeAutoTrue"
-                                                                                       value={true}
-                                                                                       bind:group={$tempSettings.darkModeAutoDetect}
-                                                                               />
-                                                                               <label class="form-check-label" for="darkModeAutoTrue">
-                                                                                       {$t('settings.light_dark_auto_detect')}
-                                                                                       {#if window.matchMedia('(prefers-color-scheme: dark)').matches}
-                                                                                               <b><u>{$t('settings.dark_mode')} <Fa icon={faMoon} /></u></b>
-                                                                                       {:else}
-                                                                                               <b><u>{$t('settings.light_mode')} <Fa icon={faSun} /></u></b>
+                                               </div>
+                                               <div class="col-12 col-md-8">
+                                                       <div
+                                                               class="settings-content overflow-y-auto"
+                                                               data-bs-spy="scroll"
+                                                               data-bs-target="#settings-nav"
+                                                               data-bs-smooth-scroll="true"
+                                                               id="settings-content"
+                                                       >
+                                                               <!-- Mobile dropdown (visible on < md) -->
+                                                               <div class="d-md-none position-sticky top-0 p-1 mobile-settings-dropdown">
+                                                                       <select
+                                                                               id="settingsSectionSelect"
+                                                                               class="form-select form-select-sm"
+                                                                               bind:value={activeSettingsSection}
+                                                                               onchange={() => scrollToSection(activeSettingsSection)}
+                                                                       >
+                                                                               {#each settingsSectionsMeta as sec}
+                                                                                       <option value={sec.id}>{$t(sec.labelKey)}</option>
+                                                                               {/each}
+                                                                       </select>
+                                                               </div>
+                                                               <div id="appearance">
+                                                                       <h3 class="text-primary">🎨 {$t('settings.appearance')}</h3>
+                                                                       <div id="lightdark">
+                                                                               {#if $tempSettings.darkModeAutoDetect !== $settings.darkModeAutoDetect || $tempSettings.useDarkMode !== $settings.useDarkMode}
+                                                                                       {@render unsavedChanges()}
+                                                                               {/if}
+                                                                               <h5>{$t('settings.light_dark_mode')}</h5>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="darkMode"
+                                                                                               id="darkModeAutoTrue"
+                                                                                               value={true}
+                                                                                               bind:group={$tempSettings.darkModeAutoDetect}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="darkModeAutoTrue">
+                                                                                               {$t('settings.light_dark_auto_detect')}
+                                                                                               {#if window.matchMedia('(prefers-color-scheme: dark)').matches}
+                                                                                                       <b><u>{$t('settings.dark_mode')} <Fa icon={faMoon} /></u></b>
+                                                                                               {:else}
+                                                                                                       <b><u>{$t('settings.light_mode')} <Fa icon={faSun} /></u></b>
+                                                                                               {/if}
+                                                                                       </label>
+                                                                               </div>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="darkMode"
+                                                                                               id="darkModeAutoFalse"
+                                                                                               value={false}
+                                                                                               bind:group={$tempSettings.darkModeAutoDetect}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="darkModeAutoFalse">
+                                                                                               {$t('settings.light_dark_manual')}
+                                                                                       </label>
+                                                                                       {#if $tempSettings.darkModeAutoDetect === false}
+                                                                                               <div class="form-check form-switch d-flex flex-row ps-0" transition:slide>
+                                                                                                       <label class="form-check-label me-5" for="darkModeSwitch">
+                                                                                                               <Fa icon={faSun} />
+                                                                                                       </label>
+                                                                                                       <input
+                                                                                                               class="form-check-input"
+                                                                                                               bind:checked={$tempSettings.useDarkMode}
+                                                                                                               type="checkbox"
+                                                                                                               role="switch"
+                                                                                                               id="darkModeSwitch"
+                                                                                                       />
+                                                                                                       <label class="form-check-label ms-2" for="darkModeSwitch">
+                                                                                                               <Fa icon={faMoon} />
+                                                                                                       </label>
+                                                                                               </div>
                                                                                        {/if}
-                                                                               </label>
+                                                                               </div>
                                                                        </div>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="darkMode"
-                                                                                       id="darkModeAutoFalse"
-                                                                                       value={false}
-                                                                                       bind:group={$tempSettings.darkModeAutoDetect}
-                                                                               />
-                                                                               <label class="form-check-label" for="darkModeAutoFalse">
-                                                                                       {$t('settings.light_dark_manual')}
-                                                                               </label>
-                                                                               {#if $tempSettings.darkModeAutoDetect === false}
-                                                                                       <div class="form-check form-switch d-flex flex-row ps-0" transition:slide>
-                                                                                               <label class="form-check-label me-5" for="darkModeSwitch">
-                                                                                                       <Fa icon={faSun} />
-                                                                                               </label>
-                                                                                               <input
-                                                                                                       class="form-check-input"
-                                                                                                       bind:checked={$tempSettings.useDarkMode}
-                                                                                                       type="checkbox"
-                                                                                                       role="switch"
-                                                                                                       id="darkModeSwitch"
-                                                                                               />
-                                                                                               <label class="form-check-label ms-2" for="darkModeSwitch">
-                                                                                                       <Fa icon={faMoon} />
-                                                                                               </label>
-                                                                                       </div>
+                                                                       <div id="background">
+                                                                               {#if $tempSettings.background !== $settings.background || $tempSettings.monochromeBackgroundColor !== $settings.monochromeBackgroundColor}
+                                                                                       {@render unsavedChanges()}
                                                                                {/if}
-                                                                       </div>
-                                                               </div>
-                                                               <div id="background">
-                                                                       {#if $tempSettings.background !== $settings.background || $tempSettings.monochromeBackgroundColor !== $settings.monochromeBackgroundColor}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-
-                                                                       <h5>{$t('settings.background')}</h5>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="background"
-                                                                                       id="background_gradient"
-                                                                                       value={'gradient'}
-                                                                                       bind:group={$tempSettings.background}
-                                                                               />
-                                                                               <label class="form-check-label" for="background_gradient">
-                                                                                       {$t('settings.background_gradient')}
-                                                                               </label>
-                                                                       </div>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="background"
-                                                                                       id="background_monochrome"
-                                                                                       value={'monochrome'}
-                                                                                       bind:group={$tempSettings.background}
-                                                                               />
-                                                                               <label class="form-check-label" for="background_monochrome">
-                                                                                       {$t('settings.background_monochrome')}
-                                                                               </label>
-                                                                               {#if $tempSettings.background === 'monochrome'}
+
+                                                                               <h5>{$t('settings.background')}</h5>
+                                                                               <div class="form-check mt-2">
                                                                                        <input
-                                                                                               transition:slide
-                                                                                               class="form-control form-control-color"
-                                                                                               bind:value={$tempSettings.monochromeBackgroundColor}
-                                                                                               type="color"
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="background"
+                                                                                               id="background_gradient"
+                                                                                               value={'gradient'}
+                                                                                               bind:group={$tempSettings.background}
                                                                                        />
-                                                                               {/if}
+                                                                                       <label class="form-check-label" for="background_gradient">
+                                                                                               {$t('settings.background_gradient')}
+                                                                                       </label>
+                                                                               </div>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="background"
+                                                                                               id="background_monochrome"
+                                                                                               value={'monochrome'}
+                                                                                               bind:group={$tempSettings.background}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="background_monochrome">
+                                                                                               {$t('settings.background_monochrome')}
+                                                                                       </label>
+                                                                                       {#if $tempSettings.background === 'monochrome'}
+                                                                                               <input
+                                                                                                       transition:slide
+                                                                                                       class="form-control form-control-color"
+                                                                                                       bind:value={$tempSettings.monochromeBackgroundColor}
+                                                                                                       type="color"
+                                                                                               />
+                                                                                       {/if}
+                                                                               </div>
                                                                        </div>
                                                                </div>
-                                                       </div>
 
-                                                       <div id="functions">
-                                                               <h3 class="text-primary">🛠️ {$t('settings.functions')}</h3>
-
-                                                               <div id="autoLoadImages">
-                                                                       {#if $tempSettings.setAutoloadImagesPerDevice !== $settings.setAutoloadImagesPerDevice || $tempSettings.autoloadImagesByDefault !== $settings.autoloadImagesByDefault}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-
-                                                                       <h5>{$t('settings.images_title')}</h5>
-                                                                       {@html $t('settings.images_description')}
-
-                                                                       <div class="form-check form-switch">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       bind:checked={$tempSettings.setAutoloadImagesPerDevice}
-                                                                                       type="checkbox"
-                                                                                       role="switch"
-                                                                                       id="setImageLoadingPerDeviceSwitch"
-                                                                               />
-                                                                               <label class="form-check-label" for="setImageLoadingPerDeviceSwitch">
-                                                                                       {$t('settings.images_loading_per_device')}
-                                                                               </label>
-                                                                       </div>
+                                                               <div id="functions">
+                                                                       <h3 class="text-primary">🛠️ {$t('settings.functions')}</h3>
 
-                                                                       <div class="form-check form-switch ms-3">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       bind:checked={$autoLoadImagesThisDevice}
-                                                                                       type="checkbox"
-                                                                                       role="switch"
-                                                                                       id="loadImagesThisDeviceSwitch"
-                                                                                       disabled={!$tempSettings.setAutoloadImagesPerDevice}
-                                                                               />
-                                                                               <label class="form-check-label" for="loadImagesThisDeviceSwitch">
-                                                                                       {@html $t('settings.images_loading_this_device')}
-                                                                               </label>
-                                                                       </div>
+                                                                       <div id="autoLoadImages">
+                                                                               {#if $tempSettings.setAutoloadImagesPerDevice !== $settings.setAutoloadImagesPerDevice || $tempSettings.autoloadImagesByDefault !== $settings.autoloadImagesByDefault}
+                                                                                       {@render unsavedChanges()}
+                                                                               {/if}
 
-                                                                       <div class="form-check form-switch mt-3">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       bind:checked={$tempSettings.autoloadImagesByDefault}
-                                                                                       type="checkbox"
-                                                                                       role="switch"
-                                                                                       id="autoLoadImagesSwitch"
-                                                                                       disabled={$tempSettings.setAutoloadImagesPerDevice}
-                                                                               />
-                                                                               <label class="form-check-label" for="autoLoadImagesSwitch">
-                                                                                       {$t('settings.images_loading_default')}
-                                                                               </label>
+                                                                               <h5>{$t('settings.images_title')}</h5>
+                                                                               {@html $t('settings.images_description')}
+
+                                                                               <div class="form-check form-switch">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               bind:checked={$tempSettings.setAutoloadImagesPerDevice}
+                                                                                               type="checkbox"
+                                                                                               role="switch"
+                                                                                               id="setImageLoadingPerDeviceSwitch"
+                                                                                       />
+                                                                                       <label class="form-check-label" for="setImageLoadingPerDeviceSwitch">
+                                                                                               {$t('settings.images_loading_per_device')}
+                                                                                       </label>
+                                                                               </div>
+
+                                                                               <div class="form-check form-switch ms-3">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               bind:checked={$autoLoadImagesThisDevice}
+                                                                                               type="checkbox"
+                                                                                               role="switch"
+                                                                                               id="loadImagesThisDeviceSwitch"
+                                                                                               disabled={!$tempSettings.setAutoloadImagesPerDevice}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="loadImagesThisDeviceSwitch">
+                                                                                               {@html $t('settings.images_loading_this_device')}
+                                                                                       </label>
+                                                                               </div>
+
+                                                                               <div class="form-check form-switch mt-3">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               bind:checked={$tempSettings.autoloadImagesByDefault}
+                                                                                               type="checkbox"
+                                                                                               role="switch"
+                                                                                               id="autoLoadImagesSwitch"
+                                                                                               disabled={$tempSettings.setAutoloadImagesPerDevice}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="autoLoadImagesSwitch">
+                                                                                               {$t('settings.images_loading_default')}
+                                                                                       </label>
+                                                                               </div>
                                                                        </div>
-                                                               </div>
 
-                                                               <div id="language">
-                                                                       {#if $tempSettings.useBrowserLanguage !== $settings.useBrowserLanguage || $tempSettings.language !== $settings.language}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-                                                                       <h5>🌐 {$t('settings.language')}</h5>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="language"
-                                                                                       id="language_auto"
-                                                                                       value={true}
-                                                                                       bind:group={$tempSettings.useBrowserLanguage}
-                                                                               />
-                                                                               <label class="form-check-label" for="language_auto">
-                                                                                       {$t('settings.language_auto_detect')}
-                                                                                       <code>{window.navigator.language}</code>
-                                                                                       {#if tolgeesMatchForBrowserLanguage() !== '' && tolgeesMatchForBrowserLanguage() !== window.navigator.language}
-                                                                                               ➔ <code>{tolgeesMatchForBrowserLanguage()}</code>
-                                                                                               {$t('settings.language_X_used')}
-                                                                                       {/if}
-                                                                               </label>
-                                                                               {#if $tempSettings.useBrowserLanguage && tolgeesMatchForBrowserLanguage() === ''}
-                                                                                       <div
-                                                                                               transition:slide
-                                                                                               disabled={!$settings.useBrowserLanguage}
-                                                                                               class="alert alert-danger"
-                                                                                               role="alert"
-                                                                                       >
-                                                                                               {@html $t('settings.language_not_available', {
-                                                                                                       browserLanguage: window.navigator.language,
-                                                                                                       defaultLanguage: $tolgee.getInitialOptions().defaultLanguage
-                                                                                               })}
-                                                                                       </div>
+                                                                       <div id="language">
+                                                                               {#if $tempSettings.useBrowserLanguage !== $settings.useBrowserLanguage || $tempSettings.language !== $settings.language}
+                                                                                       {@render unsavedChanges()}
                                                                                {/if}
-                                                                       </div>
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="language"
-                                                                                       id="language_manual"
-                                                                                       value={false}
-                                                                                       bind:group={$tempSettings.useBrowserLanguage}
-                                                                               />
-                                                                               <label class="form-check-label" for="language_manual">
-                                                                                       {$t('settings.set_language_manually')}
-                                                                                       {#if !$tempSettings.useBrowserLanguage}
-                                                                                               <select
+                                                                               <h5>🌐 {$t('settings.language')}</h5>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="language"
+                                                                                               id="language_auto"
+                                                                                               value={true}
+                                                                                               bind:group={$tempSettings.useBrowserLanguage}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="language_auto">
+                                                                                               {$t('settings.language_auto_detect')}
+                                                                                               <code>{window.navigator.language}</code>
+                                                                                               {#if tolgeesMatchForBrowserLanguage() !== '' && tolgeesMatchForBrowserLanguage() !== window.navigator.language}
+                                                                                                       ➔ <code>{tolgeesMatchForBrowserLanguage()}</code>
+                                                                                                       {$t('settings.language_X_used')}
+                                                                                               {/if}
+                                                                                       </label>
+                                                                                       {#if $tempSettings.useBrowserLanguage && tolgeesMatchForBrowserLanguage() === ''}
+                                                                                               <div
                                                                                                        transition:slide
-                                                                                                       class="form-select"
-                                                                                                       bind:value={$tempSettings.language}
-                                                                                                       disabled={$tempSettings.useBrowserLanguage}
+                                                                                                       disabled={!$settings.useBrowserLanguage}
+                                                                                                       class="alert alert-danger"
+                                                                                                       role="alert"
                                                                                                >
-                                                                                                       {#each $tolgee.getInitialOptions().availableLanguages as lang}
-                                                                                                               <option value={lang}>{loadFlagEmoji(lang)} {lang}</option>
-                                                                                                       {/each}
-                                                                                               </select>
+                                                                                                       {@html $t('settings.language_not_available', {
+                                                                                                               browserLanguage: window.navigator.language,
+                                                                                                               defaultLanguage: $tolgee.getInitialOptions().defaultLanguage
+                                                                                                       })}
+                                                                                               </div>
                                                                                        {/if}
-                                                                               </label>
-                                                                       </div>
-                                                                       <div class="form-text">
-                                                                               {$t('settings.language.reload_info')}
-                                                                       </div>
-                                                               </div>
-                                                               <div id="timezone">
-                                                                       {#if $tempSettings.useBrowserTimezone !== $settings.useBrowserTimezone || ($tempSettings.timezone !== undefined && $tempSettings.timezone?.value !== $settings.timezone?.value)}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-                                                                       <h5>{$t('settings.timezone')}</h5>
-                                                                       {$t('settings.timezone.description', { written_on: $t('log.written_on') })}
-
-                                                                       <div class="form-check mt-2">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="timezone"
-                                                                                       id="timezone1"
-                                                                                       value={true}
-                                                                                       bind:group={$tempSettings.useBrowserTimezone}
-                                                                               />
-                                                                               <label class="form-check-label" for="timezone1">
-                                                                                       {@html $t('settings.timezone.auto_detect')}
-                                                                                       <code>{new Intl.DateTimeFormat().resolvedOptions().timeZone}</code>
-                                                                               </label>
+                                                                               </div>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="language"
+                                                                                               id="language_manual"
+                                                                                               value={false}
+                                                                                               bind:group={$tempSettings.useBrowserLanguage}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="language_manual">
+                                                                                               {$t('settings.set_language_manually')}
+                                                                                               {#if !$tempSettings.useBrowserLanguage}
+                                                                                                       <select
+                                                                                                               transition:slide
+                                                                                                               class="form-select"
+                                                                                                               bind:value={$tempSettings.language}
+                                                                                                               disabled={$tempSettings.useBrowserLanguage}
+                                                                                                       >
+                                                                                                               {#each $tolgee.getInitialOptions().availableLanguages as lang}
+                                                                                                                       <option value={lang}>{loadFlagEmoji(lang)} {lang}</option>
+                                                                                                               {/each}
+                                                                                                       </select>
+                                                                                               {/if}
+                                                                                       </label>
+                                                                               </div>
+                                                                               <div class="form-text">
+                                                                                       {$t('settings.language.reload_info')}
+                                                                               </div>
                                                                        </div>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="timezone"
-                                                                                       id="timezone2"
-                                                                                       value={false}
-                                                                                       bind:group={$tempSettings.useBrowserTimezone}
-                                                                               />
-                                                                               <label class="form-check-label" for="timezone2">
-                                                                                       {$t('settings.timezone.manual')}
-                                                                               </label>
-                                                                               <br />
-                                                                               <SelectTimezone />
-                                                                               {#if !$tempSettings.useBrowserTimezone}
-                                                                                       <span transition:fade>
-                                                                                               {$t('settings.timezone.selected')} <code>{$tempSettings.timezone}</code>
-                                                                                       </span>
+                                                                       <div id="timezone">
+                                                                               {#if $tempSettings.useBrowserTimezone !== $settings.useBrowserTimezone || ($tempSettings.timezone !== undefined && $tempSettings.timezone?.value !== $settings.timezone?.value)}
+                                                                                       {@render unsavedChanges()}
                                                                                {/if}
-                                                                       </div>
-
-                                                                       <div class="form-text mt-3">
-                                                                               {@html $t('settings.timezone.help_text')}
-                                                                       </div>
-                                                               </div>
+                                                                               <h5>{$t('settings.timezone')}</h5>
+                                                                               {$t('settings.timezone.description', { written_on: $t('log.written_on') })}
 
-                                                               <div id="aLookBack">
-                                                                       {#if $tempSettings.useALookBack !== $settings.useALookBack || JSON.stringify(aLookBackYears
-                                                                                               .trim()
-                                                                                               .split(',')
-                                                                                               .map( (year) => parseInt(year.trim()) )) !== JSON.stringify($settings.aLookBackYears)}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-
-                                                                       <h5>{$t('settings.aLookBack')}</h5>
-                                                                       <ul>
-                                                                               {@html $t('settings.aLookBack.description')}
-                                                                       </ul>
-                                                                       <div class="form-check form-switch">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       bind:checked={$tempSettings.useALookBack}
-                                                                                       type="checkbox"
-                                                                                       role="switch"
-                                                                                       id="useALookBackSwitch"
-                                                                               />
-                                                                               <label class="form-check-label" for="useALookBackSwitch">
-                                                                                       {$t('settings.ALookBack.useIt')}
-                                                                               </label>
-                                                                       </div>
+                                                                               <div class="form-check mt-2">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="timezone"
+                                                                                               id="timezone1"
+                                                                                               value={true}
+                                                                                               bind:group={$tempSettings.useBrowserTimezone}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="timezone1">
+                                                                                               {@html $t('settings.timezone.auto_detect')}
+                                                                                               <code>{new Intl.DateTimeFormat().resolvedOptions().timeZone}</code>
+                                                                                       </label>
+                                                                               </div>
+                                                                               <div class="form-check">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="timezone"
+                                                                                               id="timezone2"
+                                                                                               value={false}
+                                                                                               bind:group={$tempSettings.useBrowserTimezone}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="timezone2">
+                                                                                               {$t('settings.timezone.manual')}
+                                                                                       </label>
+                                                                                       <br />
+                                                                                       <SelectTimezone />
+                                                                                       {#if !$tempSettings.useBrowserTimezone}
+                                                                                               <span transition:fade>
+                                                                                                       {$t('settings.timezone.selected')} <code>{$tempSettings.timezone}</code>
+                                                                                               </span>
+                                                                                       {/if}
+                                                                               </div>
 
-                                                                       <div>
-                                                                               <input
-                                                                                       type="text"
-                                                                                       id="useALookBackYears"
-                                                                                       class="form-control {aLookBackYearsInvalid ? 'is-invalid' : ''}"
-                                                                                       aria-describedby="useALookBackHelpBlock"
-                                                                                       disabled={!$tempSettings.useALookBack}
-                                                                                       placeholder={$t('settings.ALookBack.input_placeholder')}
-                                                                                       bind:value={aLookBackYears}
-                                                                                       invalid
-                                                                               />
-                                                                               {#if aLookBackYearsInvalid}
-                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                               {$t('settings.ALookBack.invalid_input')}
-                                                                                       </div>
-                                                                               {/if}
-                                                                               <div id="useALookBackHelpBlock" class="form-text">
-                                                                                       {@html $t('settings.ALookBack.help_text')}
+                                                                               <div class="form-text mt-3">
+                                                                                       {@html $t('settings.timezone.help_text')}
                                                                                </div>
                                                                        </div>
-                                                               </div>
-                                                               <div id="loginonreload">
-                                                                       <h5>Login bei Reload</h5>
-                                                                       Bla<br />
-                                                                       blub <br />
-                                                                       bla <br />
-                                                                       blub <br />
-                                                               </div>
-                                                       </div>
 
-                                                       <div id="tags">
-                                                               <h3 class="text-primary">#️⃣ {$t('settings.tags')}</h3>
-                                                               <div>
-                                                                       {$t('settings.tags.description')}
+                                                                       <div id="aLookBack">
+                                                                               {#if $tempSettings.useALookBack !== $settings.useALookBack || JSON.stringify(aLookBackYears
+                                                                                                       .trim()
+                                                                                                       .split(',')
+                                                                                                       .map( (year) => parseInt(year.trim()) )) !== JSON.stringify($settings.aLookBackYears)}
+                                                                                       {@render unsavedChanges()}
+                                                                               {/if}
 
-                                                                       {#if $tags.length === 0}
-                                                                               <div class="alert alert-info my-2" role="alert">
-                                                                                       {$t('settings.tags.no_tags')}
+                                                                               <h5>{$t('settings.aLookBack')}</h5>
+                                                                               <ul>
+                                                                                       {@html $t('settings.aLookBack.description')}
+                                                                               </ul>
+                                                                               <div class="form-check form-switch">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               bind:checked={$tempSettings.useALookBack}
+                                                                                               type="checkbox"
+                                                                                               role="switch"
+                                                                                               id="useALookBackSwitch"
+                                                                                       />
+                                                                                       <label class="form-check-label" for="useALookBackSwitch">
+                                                                                               {$t('settings.ALookBack.useIt')}
+                                                                                       </label>
                                                                                </div>
-                                                                       {/if}
-                                                                       <div class="d-flex flex-column tagColumn mt-1">
-                                                                               {#each $tags as tag}
-                                                                                       <Tag
-                                                                                               {tag}
-                                                                                               isEditable
-                                                                                               editTag={openTagModal}
-                                                                                               isDeletable
-                                                                                               deleteTag={askDeleteTag}
+
+                                                                               <div>
+                                                                                       <input
+                                                                                               type="text"
+                                                                                               id="useALookBackYears"
+                                                                                               class="form-control {aLookBackYearsInvalid ? 'is-invalid' : ''}"
+                                                                                               aria-describedby="useALookBackHelpBlock"
+                                                                                               disabled={!$tempSettings.useALookBack}
+                                                                                               placeholder={$t('settings.ALookBack.input_placeholder')}
+                                                                                               bind:value={aLookBackYears}
+                                                                                               invalid
                                                                                        />
-                                                                                       {#if deleteTagId === tag.id}
-                                                                                               <div
-                                                                                                       class="alert alert-danger align-items-center"
-                                                                                                       role="alert"
-                                                                                                       transition:slide
-                                                                                               >
-                                                                                                       <div>
-                                                                                                               <Fa icon={faTriangleExclamation} fw />
-                                                                                                               {@html $t('settings.tags.delete_confirmation')}
-                                                                                                       </div>
-                                                                                                       <!-- svelte-ignore a11y_consider_explicit_label -->
-                                                                                                       <div class="d-flex flex-row mt-2">
-                                                                                                               <button class="btn btn-secondary" onclick={() => (deleteTagId = null)}
-                                                                                                                       >{$t('settings.abort')}
-                                                                                                               </button>
-                                                                                                               <button
-                                                                                                                       disabled={isDeletingTag}
-                                                                                                                       class="btn btn-danger ms-3"
-                                                                                                                       onclick={() => deleteTag(tag.id)}
-                                                                                                                       >{$t('settings.delete')}
-                                                                                                                       {#if isDeletingTag}
-                                                                                                                               <span
-                                                                                                                                       class="spinner-border spinner-border-sm ms-2"
-                                                                                                                                       role="status"
-                                                                                                                                       aria-hidden="true"
-                                                                                                                               ></span>
-                                                                                                                       {/if}
-                                                                                                               </button>
-                                                                                                       </div>
+                                                                                       {#if aLookBackYearsInvalid}
+                                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                                       {$t('settings.ALookBack.invalid_input')}
                                                                                                </div>
                                                                                        {/if}
-                                                                               {/each}
+                                                                                       <div id="useALookBackHelpBlock" class="form-text">
+                                                                                               {@html $t('settings.ALookBack.help_text')}
+                                                                                       </div>
+                                                                               </div>
+                                                                       </div>
+                                                                       <div id="loginonreload">
+                                                                               <h5>Login bei Reload</h5>
+                                                                               Bla<br />
+                                                                               blub <br />
+                                                                               bla <br />
+                                                                               blub <br />
                                                                        </div>
                                                                </div>
-                                                       </div>
 
-                                                       <div id="templates">
-                                                               <h3 class="text-primary">📝 {$t('settings.templates')}</h3>
-                                                               <div>
-                                                                       {#if oldTemplateName !== templateName || oldTemplateText !== templateText}
-                                                                               {@render unsavedChanges()}
-                                                                       {/if}
-
-                                                                       <div class="d-flex flex-column">
-                                                                               <select
-                                                                                       bind:value={selectedTemplate}
-                                                                                       class="form-select"
-                                                                                       aria-label="Select template"
-                                                                                       onchange={updateSelectedTemplate}
-                                                                               >
-                                                                                       <option value="-1" selected={selectedTemplate === '-1'}>
-                                                                                               {$t('settings.templates.create_new')}
-                                                                                       </option>
-                                                                                       {#each $templates as template, index}
-                                                                                               <option value={index} selected={index === selectedTemplate}>
-                                                                                                       {template.name}
-                                                                                               </option>
+                                                               <div id="tags">
+                                                                       <h3 class="text-primary">#️⃣ {$t('settings.tags')}</h3>
+                                                                       <div>
+                                                                               {$t('settings.tags.description')}
+
+                                                                               {#if $tags.length === 0}
+                                                                                       <div class="alert alert-info my-2" role="alert">
+                                                                                               {$t('settings.tags.no_tags')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                               <div class="d-flex flex-column tagColumn mt-1">
+                                                                                       {#each $tags as tag}
+                                                                                               <Tag
+                                                                                                       {tag}
+                                                                                                       isEditable
+                                                                                                       editTag={openTagModal}
+                                                                                                       isDeletable
+                                                                                                       deleteTag={askDeleteTag}
+                                                                                               />
+                                                                                               {#if deleteTagId === tag.id}
+                                                                                                       <div
+                                                                                                               class="alert alert-danger align-items-center"
+                                                                                                               role="alert"
+                                                                                                               transition:slide
+                                                                                                       >
+                                                                                                               <div>
+                                                                                                                       <Fa icon={faTriangleExclamation} fw />
+                                                                                                                       {@html $t('settings.tags.delete_confirmation')}
+                                                                                                               </div>
+                                                                                                               <!-- svelte-ignore a11y_consider_explicit_label -->
+                                                                                                               <div class="d-flex flex-row mt-2">
+                                                                                                                       <button class="btn btn-secondary" onclick={() => (deleteTagId = null)}
+                                                                                                                               >{$t('settings.abort')}
+                                                                                                                       </button>
+                                                                                                                       <button
+                                                                                                                               disabled={isDeletingTag}
+                                                                                                                               class="btn btn-danger ms-3"
+                                                                                                                               onclick={() => deleteTag(tag.id)}
+                                                                                                                               >{$t('settings.delete')}
+                                                                                                                               {#if isDeletingTag}
+                                                                                                                                       <span
+                                                                                                                                               class="spinner-border spinner-border-sm ms-2"
+                                                                                                                                               role="status"
+                                                                                                                                               aria-hidden="true"
+                                                                                                                                       ></span>
+                                                                                                                               {/if}
+                                                                                                                       </button>
+                                                                                                               </div>
+                                                                                                       </div>
+                                                                                               {/if}
                                                                                        {/each}
-                                                                               </select>
+                                                                               </div>
                                                                        </div>
+                                                               </div>
+
+                                                               <div id="templates">
+                                                                       <h3 class="text-primary">📝 {$t('settings.templates')}</h3>
+                                                                       <div>
+                                                                               {#if oldTemplateName !== templateName || oldTemplateText !== templateText}
+                                                                                       {@render unsavedChanges()}
+                                                                               {/if}
+
+                                                                               <div class="d-flex flex-column">
+                                                                                       <select
+                                                                                               bind:value={selectedTemplate}
+                                                                                               class="form-select"
+                                                                                               aria-label="Select template"
+                                                                                               onchange={updateSelectedTemplate}
+                                                                                       >
+                                                                                               <option value="-1" selected={selectedTemplate === '-1'}>
+                                                                                                       {$t('settings.templates.create_new')}
+                                                                                               </option>
+                                                                                               {#each $templates as template, index}
+                                                                                                       <option value={index} selected={index === selectedTemplate}>
+                                                                                                               {template.name}
+                                                                                                       </option>
+                                                                                               {/each}
+                                                                                       </select>
+                                                                               </div>
 
-                                                                       <hr />
+                                                                               <hr />
 
-                                                                       {#if confirmDeleteTemplate}
-                                                                               <div transition:slide class="d-flex flex-row align-items-center mb-2">
-                                                                                       <span>
-                                                                                               {@html $t('settings.templates.delete_confirmation', {
-                                                                                                       template: $templates[selectedTemplate]?.name
-                                                                                               })}
-                                                                                       </span>
+                                                                               {#if confirmDeleteTemplate}
+                                                                                       <div transition:slide class="d-flex flex-row align-items-center mb-2">
+                                                                                               <span>
+                                                                                                       {@html $t('settings.templates.delete_confirmation', {
+                                                                                                               template: $templates[selectedTemplate]?.name
+                                                                                                       })}
+                                                                                               </span>
+                                                                                               <button
+                                                                                                       type="button"
+                                                                                                       class="btn btn-secondary ms-2"
+                                                                                                       onclick={() => (confirmDeleteTemplate = false)}
+                                                                                                       >{$t('settings.abort')}</button
+                                                                                               >
+                                                                                               <button
+                                                                                                       type="button"
+                                                                                                       class="btn btn-danger ms-2"
+                                                                                                       onclick={() => {
+                                                                                                               deleteTemplate();
+                                                                                                       }}
+                                                                                                       disabled={isDeletingTemplate}
+                                                                                                       >{$t('settings.delete')}
+                                                                                                       {#if isDeletingTemplate}
+                                                                                                               <span
+                                                                                                                       class="spinner-border spinner-border-sm ms-2"
+                                                                                                                       role="status"
+                                                                                                                       aria-hidden="true"
+                                                                                                               ></span>
+                                                                                                       {/if}
+                                                                                               </button>
+                                                                                       </div>
+                                                                               {/if}
+                                                                               <div class="d-flex flex-row">
+                                                                                       <input
+                                                                                               disabled={selectedTemplate === null}
+                                                                                               type="text"
+                                                                                               bind:value={templateName}
+                                                                                               class="form-control"
+                                                                                               placeholder={$t('settings.template.name_of_template')}
+                                                                                       />
                                                                                        <button
+                                                                                               disabled={selectedTemplate === '-1' || selectedTemplate === null}
                                                                                                type="button"
-                                                                                               class="btn btn-secondary ms-2"
-                                                                                               onclick={() => (confirmDeleteTemplate = false)}
-                                                                                               >{$t('settings.abort')}</button
+                                                                                               class="btn btn-outline-danger ms-5"
+                                                                                               onclick={() => {
+                                                                                                       confirmDeleteTemplate = !confirmDeleteTemplate;
+                                                                                               }}><Fa fw icon={faTrash} /></button
                                                                                        >
+                                                                               </div>
+                                                                               <textarea
+                                                                                       disabled={selectedTemplate === null}
+                                                                                       bind:value={templateText}
+                                                                                       class="form-control mt-2"
+                                                                                       rows="10"
+                                                                                       placeholder={$t('settings.template.content_of_template')}
+                                                                               >
+                                                                               </textarea>
+                                                                               <div class="d-flex justify-content-end">
                                                                                        <button
+                                                                                               disabled={(oldTemplateName === templateName &&
+                                                                                                       oldTemplateText === templateText) ||
+                                                                                                       isSavingTemplate}
                                                                                                type="button"
-                                                                                               class="btn btn-danger ms-2"
-                                                                                               onclick={() => {
-                                                                                                       deleteTemplate();
-                                                                                               }}
-                                                                                               disabled={isDeletingTemplate}
-                                                                                               >{$t('settings.delete')}
-                                                                                               {#if isDeletingTemplate}
+                                                                                               class="btn btn-primary mt-2"
+                                                                                               onclick={saveTemplate}
+                                                                                       >
+                                                                                               {$t('settings.template.save_template')}
+                                                                                               {#if isSavingTemplate}
                                                                                                        <span
                                                                                                                class="spinner-border spinner-border-sm ms-2"
                                                                                                                role="status"
                                                                                                {/if}
                                                                                        </button>
                                                                                </div>
-                                                                       {/if}
-                                                                       <div class="d-flex flex-row">
-                                                                               <input
-                                                                                       disabled={selectedTemplate === null}
-                                                                                       type="text"
-                                                                                       bind:value={templateName}
-                                                                                       class="form-control"
-                                                                                       placeholder={$t('settings.template.name_of_template')}
-                                                                               />
-                                                                               <button
-                                                                                       disabled={selectedTemplate === '-1' || selectedTemplate === null}
-                                                                                       type="button"
-                                                                                       class="btn btn-outline-danger ms-5"
-                                                                                       onclick={() => {
-                                                                                               confirmDeleteTemplate = !confirmDeleteTemplate;
-                                                                                       }}><Fa fw icon={faTrash} /></button
-                                                                               >
-                                                                       </div>
-                                                                       <textarea
-                                                                               disabled={selectedTemplate === null}
-                                                                               bind:value={templateText}
-                                                                               class="form-control mt-2"
-                                                                               rows="10"
-                                                                               placeholder={$t('settings.template.content_of_template')}
-                                                                       >
-                                                                       </textarea>
-                                                                       <div class="d-flex justify-content-end">
-                                                                               <button
-                                                                                       disabled={(oldTemplateName === templateName &&
-                                                                                               oldTemplateText === templateText) ||
-                                                                                               isSavingTemplate}
-                                                                                       type="button"
-                                                                                       class="btn btn-primary mt-2"
-                                                                                       onclick={saveTemplate}
-                                                                               >
-                                                                                       {$t('settings.template.save_template')}
-                                                                                       {#if isSavingTemplate}
-                                                                                               <span
-                                                                                                       class="spinner-border spinner-border-sm ms-2"
-                                                                                                       role="status"
-                                                                                                       aria-hidden="true"
-                                                                                               ></span>
-                                                                                       {/if}
-                                                                               </button>
                                                                        </div>
                                                                </div>
-                                                       </div>
-
-                                                       <div id="data">
-                                                               <h3 class="text-primary">📁 {$t('settings.data')}</h3>
-                                                               <div>
-                                                                       <h5>{$t('settings.export')}</h5>
-                                                                       {$t('settings.export.description')}
-
-                                                                       <h6>{$t('settings.export.period')}</h6>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="period"
-                                                                                       value="periodAll"
-                                                                                       id="periodAll"
-                                                                                       bind:group={exportPeriod}
-                                                                               />
-                                                                               <label class="form-check-label" for="periodAll"
-                                                                                       >{$t('settings.export.period_all')}</label
-                                                                               >
-                                                                       </div>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="period"
-                                                                                       value="periodVariable"
-                                                                                       id="periodVariable"
-                                                                                       bind:group={exportPeriod}
-                                                                               />
-                                                                               <label class="form-check-label" for="periodVariable">
-                                                                                       {$t('settings.export.period_variable')}</label
-                                                                               >
-                                                                               {#if exportPeriod === 'periodVariable'}
-                                                                                       <div class="d-flex flex-row" transition:slide>
-                                                                                               <div class="me-2">
-                                                                                                       <label for="exportStartDate">{$t('settings.export.start_date')}</label>
-                                                                                                       <input
-                                                                                                               type="date"
-                                                                                                               class="form-control me-2"
-                                                                                                               id="exportStartDate"
-                                                                                                               bind:value={exportStartDate}
-                                                                                                       />
-                                                                                               </div>
-                                                                                               <div>
-                                                                                                       <label for="exportEndDate">{$t('settings.export.end_date')}</label>
-                                                                                                       <input
-                                                                                                               type="date"
-                                                                                                               class="form-control"
-                                                                                                               id="exportEndDate"
-                                                                                                               bind:value={exportEndDate}
-                                                                                                       />
-                                                                                               </div>
-                                                                                       </div>
-                                                                                       {#if exportStartDate !== '' && exportEndDate !== '' && exportStartDate > exportEndDate}
-                                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                                       {$t('settings.export.period_invalid')}
-                                                                                               </div>
-                                                                                       {/if}
-                                                                               {/if}
-                                                                       </div>
-
-                                                                       <h6>{$t('settings.export.split')}</h6>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="split"
-                                                                                       value="aio"
-                                                                                       id="splitAIO"
-                                                                                       bind:group={exportSplit}
-                                                                               />
-                                                                               <label class="form-check-label" for="splitAIO"
-                                                                                       >{$t('settings.export.split_aio')}
-                                                                               </label>
-                                                                       </div>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="split"
-                                                                                       value="year"
-                                                                                       id="splitYear"
-                                                                                       bind:group={exportSplit}
-                                                                               />
-                                                                               <label class="form-check-label" for="splitYear"
-                                                                                       >{$t('settings.export.split_year')}
-                                                                               </label>
-                                                                       </div>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="radio"
-                                                                                       name="split"
-                                                                                       value="month"
-                                                                                       id="splitMonth"
-                                                                                       bind:group={exportSplit}
-                                                                               />
-                                                                               <label class="form-check-label" for="splitMonth"
-                                                                                       >{$t('settings.export.split_month')}
-                                                                               </label>
-                                                                       </div>
 
-                                                                       <h6>{$t('settings.export.show_images')}</h6>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="checkbox"
-                                                                                       name="images"
-                                                                                       id="exportImagesInHTML"
-                                                                                       bind:checked={exportImagesInHTML}
-                                                                               />
-                                                                               <label class="form-check-label" for="exportImagesInHTML">
-                                                                                       {@html $t('settings.export.show_images_description')}
-                                                                               </label>
-                                                                       </div>
-
-                                                                       <h6>{$t('settings.export.show_tags')}</h6>
-                                                                       <div class="form-check">
-                                                                               <input
-                                                                                       class="form-check-input"
-                                                                                       type="checkbox"
-                                                                                       id="exportTagsInHTML"
-                                                                                       bind:checked={exportTagsInHTML}
-                                                                               />
-                                                                               <label class="form-check-label" for="exportTagsInHTML">
-                                                                                       {$t('settings.export.show_tags_description')}
-                                                                               </label>
-                                                                       </div>
-
-                                                                       <div class="form-text">
-                                                                               {@html $t('settings.export.help_text')}
-                                                                       </div>
-                                                                       <button
-                                                                               class="btn btn-primary mt-3"
-                                                                               onclick={exportData}
-                                                                               data-sveltekit-noscroll
-                                                                               disabled={isExporting ||
-                                                                                       (exportPeriod === 'periodVariable' &&
-                                                                                               (exportStartDate === '' || exportEndDate === ''))}
-                                                                       >
-                                                                               {$t('settings.export.export_button')}
-                                                                               {#if isExporting}
-                                                                                       <div class="spinner-border spinner-border-sm ms-2" role="status">
-                                                                                               <span class="visually-hidden">Loading...</span>
-                                                                                       </div>
-                                                                               {/if}
-                                                                       </button>
-                                                               </div>
-                                                               <div><h5>Import</h5></div>
-                                                       </div>
+                                                               <div id="data">
+                                                                       <h3 class="text-primary">📁 {$t('settings.data')}</h3>
+                                                                       <div>
+                                                                               <h5>{$t('settings.export')}</h5>
+                                                                               {$t('settings.export.description')}
 
-                                                       <div id="security">
-                                                               <h3 class="text-primary">🔒 {$t('settings.security')}</h3>
-                                                               <div>
-                                                                       <h5>{$t('settings.security.change_password')}</h5>
-                                                                       <form onsubmit={changePassword}>
-                                                                               <div class="form-floating mb-3">
+                                                                               <h6>{$t('settings.export.period')}</h6>
+                                                                               <div class="form-check">
                                                                                        <input
-                                                                                               type="password"
-                                                                                               class="form-control"
-                                                                                               id="currentPassword"
-                                                                                               placeholder={$t('settings.password.current_password')}
-                                                                                               bind:value={currentPassword}
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="period"
+                                                                                               value="periodAll"
+                                                                                               id="periodAll"
+                                                                                               bind:group={exportPeriod}
                                                                                        />
-                                                                                       <label for="currentPassword">{$t('settings.password.current_password')}</label
+                                                                                       <label class="form-check-label" for="periodAll"
+                                                                                               >{$t('settings.export.period_all')}</label
                                                                                        >
                                                                                </div>
-                                                                               <div class="form-floating mb-3">
-                                                                                       <input
-                                                                                               type="password"
-                                                                                               class="form-control"
-                                                                                               id="newPassword"
-                                                                                               placeholder={$t('settings.password.new_password')}
-                                                                                               bind:value={newPassword}
-                                                                                       />
-                                                                                       <label for="newPassword">{$t('settings.password.new_password')}</label>
-                                                                               </div>
-                                                                               <div class="form-floating mb-3">
+                                                                               <div class="form-check">
                                                                                        <input
-                                                                                               type="password"
-                                                                                               class="form-control"
-                                                                                               id="confirmNewPassword"
-                                                                                               placeholder={$t('settings.password.confirm_new_password')}
-                                                                                               bind:value={confirmNewPassword}
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="period"
+                                                                                               value="periodVariable"
+                                                                                               id="periodVariable"
+                                                                                               bind:group={exportPeriod}
                                                                                        />
-                                                                                       <label for="confirmNewPassword"
-                                                                                               >{$t('settings.password.confirm_new_password')}</label
+                                                                                       <label class="form-check-label" for="periodVariable">
+                                                                                               {$t('settings.export.period_variable')}</label
                                                                                        >
-                                                                               </div>
-                                                                               <button class="btn btn-primary" onclick={changePassword}>
-                                                                                       {#if isChangingPassword}
-                                                                                               <!-- svelte-ignore a11y_no_static_element_interactions -->
-                                                                                               <div class="spinner-border" role="status">
-                                                                                                       <span class="visually-hidden">Loading...</span>
+                                                                                       {#if exportPeriod === 'periodVariable'}
+                                                                                               <div class="d-flex flex-row" transition:slide>
+                                                                                                       <div class="me-2">
+                                                                                                               <label for="exportStartDate">{$t('settings.export.start_date')}</label>
+                                                                                                               <input
+                                                                                                                       type="date"
+                                                                                                                       class="form-control me-2"
+                                                                                                                       id="exportStartDate"
+                                                                                                                       bind:value={exportStartDate}
+                                                                                                               />
+                                                                                                       </div>
+                                                                                                       <div>
+                                                                                                               <label for="exportEndDate">{$t('settings.export.end_date')}</label>
+                                                                                                               <input
+                                                                                                                       type="date"
+                                                                                                                       class="form-control"
+                                                                                                                       id="exportEndDate"
+                                                                                                                       bind:value={exportEndDate}
+                                                                                                               />
+                                                                                                       </div>
                                                                                                </div>
+                                                                                               {#if exportStartDate !== '' && exportEndDate !== '' && exportStartDate > exportEndDate}
+                                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                                               {$t('settings.export.period_invalid')}
+                                                                                                       </div>
+                                                                                               {/if}
                                                                                        {/if}
-                                                                                       {$t('settings.password.change_password_button')}
-                                                                               </button>
-                                                                       </form>
-                                                                       {#if changePasswordNotEqual}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.password.passwords_dont_match')}
                                                                                </div>
-                                                                       {/if}
-                                                                       {#if changingPasswordSuccess}
-                                                                               <div class="alert alert-success mt-2" role="alert" transition:slide>
-                                                                                       {@html $t('settings.password.success')}
-                                                                               </div>
-                                                                       {/if}
-                                                                       {#if changingPasswordIncorrect}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.password.current_password_incorrect')}
-                                                                               </div>
-                                                                       {:else if changingPasswordError}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.password.change_error')}
+
+                                                                               <h6>{$t('settings.export.split')}</h6>
+                                                                               <div class="form-check">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="split"
+                                                                                               value="aio"
+                                                                                               id="splitAIO"
+                                                                                               bind:group={exportSplit}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="splitAIO"
+                                                                                               >{$t('settings.export.split_aio')}
+                                                                                       </label>
                                                                                </div>
-                                                                       {/if}
-                                                               </div>
-                                                               <div>
-                                                                       <h5>{$t('settings.backup_codes')}</h5>
-                                                                       <ul>
-                                                                               {@html $t('settings.backup_codes.description')}
-                                                                       </ul>
-
-                                                                       <form onsubmit={createBackupCodes}>
-                                                                               <div class="form-floating mb-3">
+                                                                               <div class="form-check">
                                                                                        <input
-                                                                                               type="password"
-                                                                                               class="form-control"
-                                                                                               id="currentPassword"
-                                                                                               placeholder={$t('settings.password.current_password')}
-                                                                                               bind:value={backupCodesPassword}
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="split"
+                                                                                               value="year"
+                                                                                               id="splitYear"
+                                                                                               bind:group={exportSplit}
                                                                                        />
-                                                                                       <label for="currentPassword">{$t('settings.password.confirm_password')}</label
-                                                                                       >
+                                                                                       <label class="form-check-label" for="splitYear"
+                                                                                               >{$t('settings.export.split_year')}
+                                                                                       </label>
                                                                                </div>
-                                                                               <button
-                                                                                       class="btn btn-primary"
-                                                                                       onclick={createBackupCodes}
-                                                                                       data-sveltekit-noscroll
-                                                                               >
-                                                                                       {$t('settings.backup_codes.generate_button')}
-                                                                                       {#if isGeneratingBackupCodes}
-                                                                                               <div class="spinner-border spinner-border-sm" role="status">
-                                                                                                       <span class="visually-hidden">Loading...</span>
-                                                                                               </div>
-                                                                                       {/if}
-                                                                               </button>
-                                                                       </form>
-                                                                       {#if backupCodes.length > 0}
-                                                                               <div class="alert alert-success alert-dismissible mt-3" transition:slide>
-                                                                                       {@html $t('settings.backup_codes.success')}
-
-                                                                                       <button class="btn btn-secondary my-2" onclick={copyBackupCodes}>
-                                                                                               <Fa icon={codesCopiedSuccess ? faCheck : faCopy} />
-                                                                                               {$t('settings.backup_codes.copy_button')}
-                                                                                       </button>
-                                                                                       <ul class="list-group">
-                                                                                               {#each backupCodes as code}
-                                                                                                       <li class="list-group-item backupCode">
-                                                                                                               <code>{code}</code>
-                                                                                                       </li>
-                                                                                               {/each}
-                                                                                       </ul>
+                                                                               <div class="form-check">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="radio"
+                                                                                               name="split"
+                                                                                               value="month"
+                                                                                               id="splitMonth"
+                                                                                               bind:group={exportSplit}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="splitMonth"
+                                                                                               >{$t('settings.export.split_month')}
+                                                                                       </label>
                                                                                </div>
-                                                                       {/if}
-                                                                       {#if showBackupCodesError}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.backup_codes.error')}
+
+                                                                               <h6>{$t('settings.export.show_images')}</h6>
+                                                                               <div class="form-check">
+                                                                                       <input
+                                                                                               class="form-check-input"
+                                                                                               type="checkbox"
+                                                                                               name="images"
+                                                                                               id="exportImagesInHTML"
+                                                                                               bind:checked={exportImagesInHTML}
+                                                                                       />
+                                                                                       <label class="form-check-label" for="exportImagesInHTML">
+                                                                                               {@html $t('settings.export.show_images_description')}
+                                                                                       </label>
                                                                                </div>
-                                                                       {/if}
-                                                               </div>
-                                                               <div><h5>Username ändern</h5></div>
-                                                               <div>
-                                                                       <h5>{$t('settings.delete_account')}</h5>
-                                                                       <p>
-                                                                               {$t('settings.delete_account.description')}
-                                                                       </p>
-                                                                       <form
-                                                                               onsubmit={() => {
-                                                                                       showConfirmDeleteAccount = true;
-                                                                               }}
-                                                                       >
-                                                                               <div class="form-floating mb-3">
+
+                                                                               <h6>{$t('settings.export.show_tags')}</h6>
+                                                                               <div class="form-check">
                                                                                        <input
-                                                                                               type="password"
-                                                                                               class="form-control"
-                                                                                               id="currentPassword"
-                                                                                               placeholder={$t('settings.password.current_password')}
-                                                                                               bind:value={deleteAccountPassword}
+                                                                                               class="form-check-input"
+                                                                                               type="checkbox"
+                                                                                               id="exportTagsInHTML"
+                                                                                               bind:checked={exportTagsInHTML}
                                                                                        />
-                                                                                       <label for="currentPassword">{$t('settings.password.confirm_password')}</label
-                                                                                       >
+                                                                                       <label class="form-check-label" for="exportTagsInHTML">
+                                                                                               {$t('settings.export.show_tags_description')}
+                                                                                       </label>
+                                                                               </div>
+
+                                                                               <div class="form-text">
+                                                                                       {@html $t('settings.export.help_text')}
                                                                                </div>
                                                                                <button
-                                                                                       class="btn btn-danger"
-                                                                                       onclick={() => {
-                                                                                               showConfirmDeleteAccount = true;
-                                                                                       }}
+                                                                                       class="btn btn-primary mt-3"
+                                                                                       onclick={exportData}
                                                                                        data-sveltekit-noscroll
+                                                                                       disabled={isExporting ||
+                                                                                               (exportPeriod === 'periodVariable' &&
+                                                                                                       (exportStartDate === '' || exportEndDate === ''))}
                                                                                >
-                                                                                       {$t('settings.delete_account.delete_button')}
-                                                                                       {#if isDeletingAccount}
-                                                                                               <!-- svelte-ignore a11y_no_static_element_interactions -->
-                                                                                               <div class="spinner-border" role="status">
+                                                                                       {$t('settings.export.export_button')}
+                                                                                       {#if isExporting}
+                                                                                               <div class="spinner-border spinner-border-sm ms-2" role="status">
                                                                                                        <span class="visually-hidden">Loading...</span>
                                                                                                </div>
                                                                                        {/if}
                                                                                </button>
-                                                                       </form>
-                                                                       {#if showDeleteAccountSuccess}
-                                                                               <div class="alert alert-success mt-2" role="alert" transition:slide>
-                                                                                       {@html $t('settings.delete_account.success')}
-                                                                               </div>
-                                                                       {/if}
-                                                                       {#if deleteAccountPasswordIncorrect}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.delete_account.password_incorrect')}
-                                                                               </div>
-                                                                       {/if}
-                                                                       {#if showConfirmDeleteAccount}
-                                                                               <div class="alert alert-danger mt-2" role="alert" transition:slide>
-                                                                                       {$t('settings.delete_account.confirm')}
+                                                                       </div>
+                                                                       <div><h5>Import</h5></div>
+                                                               </div>
 
-                                                                                       <div class="d-flex flex-row mt-2">
-                                                                                               <button
-                                                                                                       class="btn btn-secondary"
-                                                                                                       onclick={() => {
-                                                                                                               showConfirmDeleteAccount = false;
-                                                                                                               deleteAccountPassword = '';
-                                                                                                       }}>{$t('settings.abort')}</button
+                                                               <div id="security">
+                                                                       <h3 class="text-primary">🔒 {$t('settings.security')}</h3>
+                                                                       <div>
+                                                                               <h5>{$t('settings.security.change_password')}</h5>
+                                                                               <form onsubmit={changePassword}>
+                                                                                       <div class="form-floating mb-3">
+                                                                                               <input
+                                                                                                       type="password"
+                                                                                                       class="form-control"
+                                                                                                       id="currentPassword"
+                                                                                                       placeholder={$t('settings.password.current_password')}
+                                                                                                       bind:value={currentPassword}
+                                                                                               />
+                                                                                               <label for="currentPassword"
+                                                                                                       >{$t('settings.password.current_password')}</label
                                                                                                >
-                                                                                               <button
-                                                                                                       class="btn btn-danger ms-3"
-                                                                                                       onclick={deleteAccount}
-                                                                                                       disabled={isDeletingAccount}
-                                                                                                       >{$t('settings.delete_account.confirm_button')}
-                                                                                                       {#if isDeletingAccount}
-                                                                                                               <span
-                                                                                                                       class="spinner-border spinner-border-sm ms-2"
-                                                                                                                       role="status"
-                                                                                                                       aria-hidden="true"
-                                                                                                               ></span>
-                                                                                                       {/if}
+                                                                                       </div>
+                                                                                       <div class="form-floating mb-3">
+                                                                                               <input
+                                                                                                       type="password"
+                                                                                                       class="form-control"
+                                                                                                       id="newPassword"
+                                                                                                       placeholder={$t('settings.password.new_password')}
+                                                                                                       bind:value={newPassword}
+                                                                                               />
+                                                                                               <label for="newPassword">{$t('settings.password.new_password')}</label>
+                                                                                       </div>
+                                                                                       <div class="form-floating mb-3">
+                                                                                               <input
+                                                                                                       type="password"
+                                                                                                       class="form-control"
+                                                                                                       id="confirmNewPassword"
+                                                                                                       placeholder={$t('settings.password.confirm_new_password')}
+                                                                                                       bind:value={confirmNewPassword}
+                                                                                               />
+                                                                                               <label for="confirmNewPassword"
+                                                                                                       >{$t('settings.password.confirm_new_password')}</label
+                                                                                               >
+                                                                                       </div>
+                                                                                       <button class="btn btn-primary" onclick={changePassword}>
+                                                                                               {#if isChangingPassword}
+                                                                                                       <!-- svelte-ignore a11y_no_static_element_interactions -->
+                                                                                                       <div class="spinner-border" role="status">
+                                                                                                               <span class="visually-hidden">Loading...</span>
+                                                                                                       </div>
+                                                                                               {/if}
+                                                                                               {$t('settings.password.change_password_button')}
+                                                                                       </button>
+                                                                               </form>
+                                                                               {#if changePasswordNotEqual}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.password.passwords_dont_match')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                               {#if changingPasswordSuccess}
+                                                                                       <div class="alert alert-success mt-2" role="alert" transition:slide>
+                                                                                               {@html $t('settings.password.success')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                               {#if changingPasswordIncorrect}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.password.current_password_incorrect')}
+                                                                                       </div>
+                                                                               {:else if changingPasswordError}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.password.change_error')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                       </div>
+                                                                       <div>
+                                                                               <h5>{$t('settings.backup_codes')}</h5>
+                                                                               <ul>
+                                                                                       {@html $t('settings.backup_codes.description')}
+                                                                               </ul>
+
+                                                                               <form onsubmit={createBackupCodes}>
+                                                                                       <div class="form-floating mb-3">
+                                                                                               <input
+                                                                                                       type="password"
+                                                                                                       class="form-control"
+                                                                                                       id="currentPassword"
+                                                                                                       placeholder={$t('settings.password.current_password')}
+                                                                                                       bind:value={backupCodesPassword}
+                                                                                               />
+                                                                                               <label for="currentPassword"
+                                                                                                       >{$t('settings.password.confirm_password')}</label
+                                                                                               >
+                                                                                       </div>
+                                                                                       <button
+                                                                                               class="btn btn-primary"
+                                                                                               onclick={createBackupCodes}
+                                                                                               data-sveltekit-noscroll
+                                                                                       >
+                                                                                               {$t('settings.backup_codes.generate_button')}
+                                                                                               {#if isGeneratingBackupCodes}
+                                                                                                       <div class="spinner-border spinner-border-sm" role="status">
+                                                                                                               <span class="visually-hidden">Loading...</span>
+                                                                                                       </div>
+                                                                                               {/if}
+                                                                                       </button>
+                                                                               </form>
+                                                                               {#if backupCodes.length > 0}
+                                                                                       <div class="alert alert-success alert-dismissible mt-3" transition:slide>
+                                                                                               {@html $t('settings.backup_codes.success')}
+
+                                                                                               <button class="btn btn-secondary my-2" onclick={copyBackupCodes}>
+                                                                                                       <Fa icon={codesCopiedSuccess ? faCheck : faCopy} />
+                                                                                                       {$t('settings.backup_codes.copy_button')}
                                                                                                </button>
+                                                                                               <ul class="list-group">
+                                                                                                       {#each backupCodes as code}
+                                                                                                               <li class="list-group-item backupCode">
+                                                                                                                       <code>{code}</code>
+                                                                                                               </li>
+                                                                                                       {/each}
+                                                                                               </ul>
                                                                                        </div>
-                                                                               </div>
-                                                                       {/if}
+                                                                               {/if}
+                                                                               {#if showBackupCodesError}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.backup_codes.error')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                       </div>
+                                                                       <div><h5>Username ändern</h5></div>
+                                                                       <div>
+                                                                               <h5>{$t('settings.delete_account')}</h5>
+                                                                               <p>
+                                                                                       {$t('settings.delete_account.description')}
+                                                                               </p>
+                                                                               <form
+                                                                                       onsubmit={() => {
+                                                                                               showConfirmDeleteAccount = true;
+                                                                                       }}
+                                                                               >
+                                                                                       <div class="form-floating mb-3">
+                                                                                               <input
+                                                                                                       type="password"
+                                                                                                       class="form-control"
+                                                                                                       id="currentPassword"
+                                                                                                       placeholder={$t('settings.password.current_password')}
+                                                                                                       bind:value={deleteAccountPassword}
+                                                                                               />
+                                                                                               <label for="currentPassword"
+                                                                                                       >{$t('settings.password.confirm_password')}</label
+                                                                                               >
+                                                                                       </div>
+                                                                                       <button
+                                                                                               class="btn btn-danger"
+                                                                                               onclick={() => {
+                                                                                                       showConfirmDeleteAccount = true;
+                                                                                               }}
+                                                                                               data-sveltekit-noscroll
+                                                                                       >
+                                                                                               {$t('settings.delete_account.delete_button')}
+                                                                                               {#if isDeletingAccount}
+                                                                                                       <!-- svelte-ignore a11y_no_static_element_interactions -->
+                                                                                                       <div class="spinner-border" role="status">
+                                                                                                               <span class="visually-hidden">Loading...</span>
+                                                                                                       </div>
+                                                                                               {/if}
+                                                                                       </button>
+                                                                               </form>
+                                                                               {#if showDeleteAccountSuccess}
+                                                                                       <div class="alert alert-success mt-2" role="alert" transition:slide>
+                                                                                               {@html $t('settings.delete_account.success')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                               {#if deleteAccountPasswordIncorrect}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.delete_account.password_incorrect')}
+                                                                                       </div>
+                                                                               {/if}
+                                                                               {#if showConfirmDeleteAccount}
+                                                                                       <div class="alert alert-danger mt-2" role="alert" transition:slide>
+                                                                                               {$t('settings.delete_account.confirm')}
+
+                                                                                               <div class="d-flex flex-row mt-2">
+                                                                                                       <button
+                                                                                                               class="btn btn-secondary"
+                                                                                                               onclick={() => {
+                                                                                                                       showConfirmDeleteAccount = false;
+                                                                                                                       deleteAccountPassword = '';
+                                                                                                               }}>{$t('settings.abort')}</button
+                                                                                                       >
+                                                                                                       <button
+                                                                                                               class="btn btn-danger ms-3"
+                                                                                                               onclick={deleteAccount}
+                                                                                                               disabled={isDeletingAccount}
+                                                                                                               >{$t('settings.delete_account.confirm_button')}
+                                                                                                               {#if isDeletingAccount}
+                                                                                                                       <span
+                                                                                                                               class="spinner-border spinner-border-sm ms-2"
+                                                                                                                               role="status"
+                                                                                                                               aria-hidden="true"
+                                                                                                                       ></span>
+                                                                                                               {/if}
+                                                                                                       </button>
+                                                                                               </div>
+                                                                                       </div>
+                                                                               {/if}
+                                                                       </div>
                                                                </div>
-                                                       </div>
 
-                                                       <div id="about">
-                                                               <h3 class="text-primary">💡 {$t('settings.about')}</h3>
-                                                               Version:<br />
-                                                               Changelog: <br />
-                                                               Link zu github
+                                                               <div id="about">
+                                                                       <h3 class="text-primary">💡 {$t('settings.about')}</h3>
+                                                                       Version:<br />
+                                                                       Changelog: <br />
+                                                                       Link zu github
+                                                               </div>
                                                        </div>
                                                </div>
-                                       </div>
+                                       {/if}
+                                       {#if activeSettingsView === 'stats'}
+                                               <div class="col-12">
+                                                       <Statistics />
+                                               </div>
+                                       {/if}
+                                       {#if activeSettingsView === 'admin'}
+                                               <div class="col-12">
+                                                       <Admin />
+                                               </div>
+                                       {/if}
                                </div>
                        </div>
                        <div class="modal-footer">
-                               {#if settingsHaveChanged}
-                                       <div class="footer-unsaved-changes" transition:fade={{ duration: 100 }}>
-                                               {$t('settings.unsaved_changes')}
-                                       </div>
-                               {/if}
-                               <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"
-                                       >{$t('settings.abort')}</button
-                               >
-                               <button
-                                       type="button"
-                                       class="btn btn-primary"
-                                       onclick={saveUserSettings}
-                                       disabled={isSaving || !settingsHaveChanged}
-                                       >{$t('settings.save')}
-                                       {#if isSaving}
-                                               <span class="spinner-border spinner-border-sm ms-2" role="status" aria-hidden="true"
-                                               ></span>
+                               {#if activeSettingsView === 'settings'}
+                                       {#if settingsHaveChanged}
+                                               <div class="footer-unsaved-changes" transition:fade={{ duration: 100 }}>
+                                                       {$t('settings.unsaved_changes')}
+                                               </div>
                                        {/if}
-                               </button>
+                                       <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"
+                                               >{$t('settings.abort')}</button
+                                       >
+                                       <button
+                                               type="button"
+                                               class="btn btn-primary"
+                                               onclick={saveUserSettings}
+                                               disabled={isSaving || !settingsHaveChanged}
+                                               >{$t('settings.save')}
+                                               {#if isSaving}
+                                                       <span class="spinner-border spinner-border-sm ms-2" role="status" aria-hidden="true"
+                                                       ></span>
+                                               {/if}
+                                       </button>
+                               {:else}
+                                       <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
+                                               {$t('settings.close') || 'Close'}
+                                       </button>
+                               {/if}
                        </div>
                </div>
        </div>
index 1ffa6bc804b40a69beb693d12e7c884352b1c1fc..1a93b34aed55d7c6b48acf6256da66063fc1f39f 100644 (file)
                background-color: rgba(219, 219, 219, 0.45);
        }
 
-       .filenameWeight {
-               font-weight: 550;
-       }
-
        .files {
                /* margin-right: 2rem; */
                margin-bottom: 1rem;
git clone https://git.99rst.org/PROJECT