Commit 1a4fe178 authored by jan.koester's avatar jan.koester
Browse files

test

parent 19049e94
Loading
Loading
Loading
Loading
+129 −0
Original line number Diff line number Diff line
@@ -472,6 +472,135 @@ dialog label {
    color: var(--bg-primary);
}

/* Settings Dialog */
.settings-dialog {
    width: 700px;
    max-width: 90vw;
    max-height: 80vh;
    padding: 0;
}

.settings-dialog .dialog-actions {
    padding: 0.8rem 1.2rem;
    border-top: 1px solid var(--border);
}

.set-modal {
    display: flex;
    min-height: 350px;
}

.set-sidebar {
    width: 180px;
    min-width: 180px;
    background: var(--bg-primary);
    border-right: 1px solid var(--border);
    padding: 1rem 0;
}

.set-sidebar h3 {
    padding: 0 1rem 0.8rem;
    font-size: 0.95rem;
    color: var(--accent);
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.5rem;
}

.set-nav {
    list-style: none;
    padding: 0;
    margin: 0;
}

.set-nav-item {
    padding: 0.5rem 1rem;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 0.85rem;
    transition: background 0.15s, color 0.15s;
}

.set-nav-item:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.set-nav-item.active {
    background: var(--bg-secondary);
    color: var(--accent);
    border-left: 3px solid var(--accent);
}

.set-content {
    flex: 1;
    padding: 1.2rem;
    overflow-y: auto;
}

.set-section h4 {
    margin-bottom: 1rem;
    color: var(--text-primary);
    font-size: 1rem;
}

.set-field {
    margin-bottom: 1rem;
    display: flex;
    align-items: center;
    gap: 0.8rem;
}

.set-field label {
    min-width: 120px;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.set-field select,
.set-field input {
    flex: 1;
    padding: 0.45rem 0.6rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    font-size: 0.9rem;
    outline: none;
}

.set-field select:focus,
.set-field input:focus {
    border-color: var(--accent);
}

.set-save-btn {
    padding: 0.4rem 1rem;
    background: var(--accent);
    color: var(--bg-primary);
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.85rem;
}

.set-save-btn:hover {
    background: var(--accent-hover);
}

.set-status {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.set-status.success {
    color: var(--success, #a6e3a1);
}

.set-status.error {
    color: var(--danger);
}

/* Scrollbar */
::-webkit-scrollbar {
    width: 8px;
+32 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
            <span id="doc-name" class="doc-name">Untitled</span>
        </div>
        <div class="toolbar-group" style="margin-left:auto">
            <button id="btn-settings" data-i18n-title="Settings">&#x2699; <span data-i18n="Settings">Einstellungen</span></button>
            <button id="btn-logout" data-i18n-title="Logout">&#x1F6AA; <span data-i18n="Logout">Abmelden</span></button>
        </div>
    </header>
@@ -109,6 +110,37 @@
        </div>
    </dialog>

    <dialog id="settings-dialog" class="settings-dialog">
        <div class="set-modal">
            <div class="set-sidebar">
                <h3 data-i18n="Settings">Einstellungen</h3>
                <ul class="set-nav">
                    <li class="set-nav-item active" data-section="language" data-i18n="Language">Sprache</li>
                </ul>
            </div>
            <div class="set-content" id="settings-content">
                <!-- Language section (default) -->
                <div id="settings-language" class="set-section">
                    <h4 data-i18n="Language">Sprache</h4>
                    <div class="set-field">
                        <label data-i18n="Language">Language / Sprache</label>
                        <select id="settings-lang-select">
                            <option value="de">Deutsch</option>
                            <option value="en">English</option>
                        </select>
                    </div>
                    <div class="set-field">
                        <button id="btn-settings-lang-save" class="set-save-btn" data-i18n="save">Speichern</button>
                        <span id="settings-lang-status" class="set-status"></span>
                    </div>
                </div>
            </div>
        </div>
        <div class="dialog-actions">
            <button id="btn-settings-close" data-i18n="Close">Schließen</button>
        </div>
    </dialog>

    <script src="js/i18n.js"></script>
    <script src="js/api.js"></script>
    <script src="js/tree.js"></script>
+10 −0
Original line number Diff line number Diff line
@@ -153,6 +153,16 @@ var EditorApi = (function() {
                documentId: documentId,
                revisionId: revisionId
            });
        },

        getSettingsLanguage: function() {
            return request('GET', '/api/settings/language');
        },

        setSettingsLanguage: function(language) {
            return request('POST', '/api/settings/language', {
                language: language
            });
        }
    };
})();
+64 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
            bindToolbar();
            bindTreeActions();
            bindDialogs();
            bindSettingsDialog();
            Preview.clear();

            DocumentTree.setOnSelect(function(uuid) {
@@ -139,6 +140,10 @@
                window.location.href = '/login.html';
            });
        });

        document.getElementById('btn-settings').addEventListener('click', function() {
            openSettings();
        });
    }

    // --- Tree action bindings ---
@@ -397,6 +402,65 @@
        }
    }

    // --- Settings ---

    function openSettings() {
        EditorApi.getSettingsLanguage().then(function(resp) {
            var sel = document.getElementById('settings-lang-select');
            sel.value = resp.language || 'en';
            document.getElementById('settings-lang-status').textContent = '';
            document.getElementById('settings-dialog').showModal();
        }).catch(function(err) {
            alert(I18n.t('I18N_ACTION_FAILED') + ': ' + (err.error || ''));
        });
    }

    function bindSettingsDialog() {
        document.getElementById('btn-settings-close').addEventListener('click', function() {
            document.getElementById('settings-dialog').close();
        });

        document.getElementById('btn-settings-lang-save').addEventListener('click', function() {
            var lang = document.getElementById('settings-lang-select').value;
            var status = document.getElementById('settings-lang-status');
            status.textContent = I18n.t('I18N_SAVING', 'Saving...');

            EditorApi.setSettingsLanguage(lang).then(function() {
                status.textContent = I18n.t('I18N_SAVED', 'Saved');
                status.className = 'set-status success';

                // Clear lang cookie so DB setting takes effect
                document.cookie = 'lang=;path=/;max-age=0';

                // Reload translations and re-translate page
                I18n.load(function() {
                    I18n.translatePage();
                    // Clear status after re-translate
                    setTimeout(function() {
                        status.textContent = '';
                        status.className = 'set-status';
                    }, 2000);
                });
            }).catch(function(err) {
                status.textContent = I18n.t('I18N_SAVE_FAILED', 'Save failed');
                status.className = 'set-status error';
            });
        });

        // Nav section switching
        var navItems = document.querySelectorAll('.set-nav-item');
        for (var i = 0; i < navItems.length; i++) {
            navItems[i].addEventListener('click', function() {
                for (var j = 0; j < navItems.length; j++) navItems[j].classList.remove('active');
                this.classList.add('active');
                var sections = document.querySelectorAll('.set-section');
                for (var k = 0; k < sections.length; k++) sections[k].style.display = 'none';
                var target = document.getElementById('settings-' + this.getAttribute('data-section'));
                if (target) target.style.display = 'block';
            });
        }
    }

    // --- Keyboard shortcuts ---

    document.addEventListener('keydown', function(e) {
+56 −5
Original line number Diff line number Diff line
@@ -87,10 +87,34 @@
            font-size: 0.85rem;
            display: none;
        }
        .lang-switcher {
            position: absolute;
            top: 1rem;
            right: 1rem;
        }
        .lang-switcher select {
            background: var(--bg-secondary);
            color: var(--text-primary);
            border: 1px solid var(--border);
            border-radius: 6px;
            padding: 0.4rem 0.6rem;
            font-size: 0.85rem;
            cursor: pointer;
            outline: none;
        }
        .lang-switcher select:focus {
            border-color: var(--accent);
        }
    </style>
</head>
<body>
    <div class="login-container">
        <div class="lang-switcher">
            <select id="lang-select">
                <option value="de">Deutsch</option>
                <option value="en">English</option>
            </select>
        </div>
        <div class="login-box">
            <h1>blogi editor</h1>
            <p class="subtitle" data-i18n="Login">Sign in with your authdb account</p>
@@ -113,7 +137,34 @@
    <script src="js/i18n.js"></script>
    <script>
    (function() {
        I18n.load(function() { I18n.translatePage(); });
        var langSelect = document.getElementById('lang-select');

        // Read current lang cookie
        function getLangCookie() {
            var m = document.cookie.match(/(?:^|;\s*)lang=([^;]*)/);
            return m ? m[1] : '';
        }
        function setLangCookie(val) {
            document.cookie = 'lang=' + val + ';path=/;max-age=31536000;SameSite=Strict';
        }

        // Set initial selection from cookie
        var cur = getLangCookie();
        if (cur) langSelect.value = cur;

        I18n.load(function() {
            I18n.translatePage();
            // Sync select to actual loaded language
            langSelect.value = I18n.getLang();
        });

        langSelect.addEventListener('change', function() {
            setLangCookie(this.value);
            // Reload i18n and re-translate
            I18n.load(function() {
                I18n.translatePage();
            });
        });

        var form = document.getElementById('login-form');
        var errBox = document.getElementById('login-error');
@@ -123,7 +174,7 @@
            e.preventDefault();
            errBox.style.display = 'none';
            btn.disabled = true;
            btn.textContent = 'Signing in...';
            btn.textContent = I18n.t('Loading...', 'Signing in...');

            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/api/login', true);
@@ -131,7 +182,7 @@
            xhr.onreadystatechange = function() {
                if (xhr.readyState !== 4) return;
                btn.disabled = false;
                btn.textContent = 'Sign in';
                btn.textContent = I18n.t('Submit', 'Sign in');

                if (xhr.status === 200) {
                    window.location.href = '/';
@@ -147,8 +198,8 @@
            };
            xhr.onerror = function() {
                btn.disabled = false;
                btn.textContent = 'Sign in';
                errBox.textContent = 'Network error';
                btn.textContent = I18n.t('Submit', 'Sign in');
                errBox.textContent = I18n.t('Error:', 'Network error');
                errBox.style.display = 'block';
            };
            xhr.send(JSON.stringify({
Loading