settings overhaul v1

This commit is contained in:
2026-08-19 21:06:08 +02:00
parent 39646aa8c5
commit 619a6f9557

View File

@@ -2,24 +2,24 @@
<div class="pagewrapper"> <div class="pagewrapper">
<div id="main"> <div id="main">
<div class="settings"> <div class="settings">
<h1>{{ t('settings.title') }}</h1> <h1><i class="fa-solid fa-sliders"></i> {{ t('settings.title') }}</h1>
<!-- Quick navigation --> <!-- Quick navigation -->
<nav id="settings-quicknav" aria-label="Settings sections"> <nav id="settings-quicknav" aria-label="Settings sections">
<a href="#profile">{{ t('settings.profile') }}</a> <a href="#profile"><i class="fa-solid fa-user-pen"></i> {{ t('settings.profile') }}</a>
<a href="#preferences">{{ t('settings.preferences') }}</a> <a href="#preferences"><i class="fa-solid fa-sliders"></i> {{ t('settings.preferences') }}</a>
@if(enable_data_export) @if(enable_data_export)
<a href="#export">{{ t('settings.export_data_title') }}</a> <a href="#export"><i class="fa-solid fa-file-export"></i> {{ t('settings.export_data_title') }}</a>
@endif @endif
<a href="#account">{{ t('settings.account') }}</a> <a href="#account"><i class="fa-solid fa-shield-halved"></i> {{ t('settings.account') }}</a>
@if(matrix_enabled || telegram_enabled) @if(matrix_enabled || telegram_enabled)
<a href="#linked">{{ t('settings.linked_accounts') }}</a> <a href="#linked"><i class="fa-solid fa-link"></i> {{ t('settings.linked_accounts') }}</a>
@endif @endif
@if(enable_user_api_keys) @if(enable_user_api_keys)
<a href="#apikey">API Key</a> <a href="#apikey"><i class="fa-solid fa-key"></i> API Key</a>
@endif @endif
@if(enable_user_invites) @if(enable_user_invites)
<a href="#invites">{{ t('invites.section_title') }}</a> <a href="#invites"><i class="fa-solid fa-ticket"></i> {{ t('invites.section_title') }}</a>
@endif @endif
</nav> </nav>
<style> <style>
@@ -75,9 +75,59 @@
<!-- ═══════════════════════════════ PROFILE ═══════════════════════════════ --> <!-- ═══════════════════════════════ PROFILE ═══════════════════════════════ -->
<h2 id="profile">{{ t('settings.profile') }}</h2> <h2 id="profile"><i class="fa-solid fa-user-pen"></i> {{ t('settings.profile') }}</h2>
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.avatar') }}</legend> <!-- Identity & Display Settings -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-signature"></i> {{ t('settings.display_name') }}</legend>
<div class="setting-item">
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<input type="text" id="display_name_input" class="input"
placeholder="{{ t('settings.display_name_placeholder') }}" value="{!! session.display_name || '' !!}"
maxlength="32" style="max-width: 240px; height: 32px; font-size: 0.9em;">
<button type="button" id="btn-update-display-name" class="button"
style="padding: 5px 14px; font-size: 0.85em;">{{ t('settings.save') }}</button>
</div>
<div id="display-name-status" class="avatar-status"></div>
</div>
</fieldset>
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-palette"></i> {{ t('settings.username_color') }}</legend>
<div class="setting-item">
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<input type="color" id="username_color_picker" value="{{ session.username_color || '#ffffff' }}"
style="width: 50px; height: 32px; padding: 0; border: 1px solid var(--nav-border-color); cursor: pointer; background: none; border-radius: 4px;">
<input type="text" id="username_color_hex" value="{{ session.username_color || '#ffffff' }}" maxlength="7"
placeholder="#ffffff" class="input"
style="width: 95px; font-family: monospace; font-size: 0.9em; padding: 4px 8px; height: 32px;">
<button type="button" id="btn-save-username-color" class="button"
style="padding: 5px 14px; font-size: 0.85em;">{{ t('settings.save_color') }}</button>
<button type="button" id="btn-reset-username-color" class="button button-secondary"
style="padding: 5px 14px; font-size: 0.85em;">{{ t('settings.reset') }}</button>
</div>
<small class="text-muted" style="display: block; margin-top: 6px;">{{ t('settings.username_color_hint') }}</small>
</div>
</fieldset>
@if(enable_profile_description)
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-align-left"></i> {{ t('settings.custom_description') }}</legend>
<div class="setting-item">
<textarea id="profile_description" class="input" placeholder="{{ t('settings.description_placeholder') }}"
maxlength="2000" style="min-height: 80px;">{!! session.description || '' !!}</textarea>
<div class="profile-settings-actions" style="margin-top: 10px;">
<button type="button" id="btn-save-description" class="button">{{ t('settings.save_description') }}</button>
<button type="button" id="btn-clear-description" class="button button-danger">{{ t('settings.clear') }}</button>
</div>
<div id="description-status" class="avatar-status"></div>
</div>
</fieldset>
@endif
<!-- Avatar & Media Uploads -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-user-gear"></i> {{ t('settings.avatar') }}</legend>
<div class="avatar-settings-wrapper"> <div class="avatar-settings-wrapper">
<div class="avatar-preview-container"> <div class="avatar-preview-container">
<div class="avatar-preview-label">{{ t('settings.current_avatar') }}</div> <div class="avatar-preview-label">{{ t('settings.current_avatar') }}</div>
@@ -121,24 +171,9 @@
</div> </div>
</fieldset> </fieldset>
@if(enable_profile_description)
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.custom_description') }}</legend>
<div class="setting-item">
<textarea id="profile_description" class="input" placeholder="{{ t('settings.description_placeholder') }}"
maxlength="2000">{!! session.description || '' !!}</textarea>
<div class="profile-settings-actions">
<button type="button" id="btn-save-description" class="button">{{ t('settings.save_description') }}</button>
<button type="button" id="btn-clear-description" class="button button-danger">{{ t('settings.clear') }}</button>
</div>
<div id="description-status" class="avatar-status"></div>
</div>
</fieldset>
@endif
@if(user_banner_enabled) @if(user_banner_enabled)
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;"> <fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">Profile Banner</legend> <legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-image"></i> Profile Banner</legend>
<div class="avatar-settings-wrapper"> <div class="avatar-settings-wrapper">
<div class="avatar-preview-container" style="width: 360px; max-width: 100%;"> <div class="avatar-preview-container" style="width: 360px; max-width: 100%;">
<div class="avatar-preview-label">{{ t('settings.current_banner') }}</div> <div class="avatar-preview-label">{{ t('settings.current_banner') }}</div>
@@ -179,40 +214,9 @@
</fieldset> </fieldset>
@endif @endif
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;"> <!-- Live Profile Preview -->
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.username_color') }}</legend> <fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 25px; background: rgba(0,0,0,0.06);">
<div class="setting-item"> <legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-eye"></i> Live Profile Preview</legend>
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<input type="color" id="username_color_picker" value="{{ session.username_color || '#ffffff' }}"
style="width: 50px; height: 30px; padding: 0; border: 1px solid var(--nav-border-color); cursor: pointer; background: none;">
<input type="text" id="username_color_hex" value="{{ session.username_color || '#ffffff' }}" maxlength="7"
placeholder="#ffffff" class="input"
style="width: 90px; font-family: monospace; font-size: 0.9em; padding: 4px 8px; height: 30px;">
<button type="button" id="btn-save-username-color" class="button"
style="padding: 5px 10px; font-size: 0.85em;">{{ t('settings.save_color') }}</button>
<button type="button" id="btn-reset-username-color" class="button button-secondary"
style="padding: 5px 10px; font-size: 0.85em;">{{ t('settings.reset') }}</button>
</div>
<small class="text-muted">{{ t('settings.username_color_hint') }}</small>
</div>
</fieldset>
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.display_name') }}</legend>
<div class="setting-item">
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<input type="text" id="display_name_input" class="input"
placeholder="{{ t('settings.display_name_placeholder') }}" value="{!! session.display_name || '' !!}"
maxlength="32" style="max-width: 200px; height: 30px; font-size: 0.9em;">
<button type="button" id="btn-update-display-name" class="button"
style="padding: 5px 10px; font-size: 0.85em;">{{ t('settings.save') }}</button>
</div>
<div id="display-name-status" class="avatar-status"></div>
</div>
</fieldset>
<fieldset style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">Live Profile Preview</legend>
<div class="setting-item" style="max-width: 750px;"> <div class="setting-item" style="max-width: 750px;">
<div class="user-infobox-block" id="live-profile-preview-box" style="--author-accent: {{ session.username_color || 'var(--accent)' }}; --author-border: {{ session.username_color || 'var(--accent)' }}; @if(banner_file && user_banner_enabled) --author-banner: url('/a/{{ banner_file }}?t={{ Date.now() }}'); --author-banner-position: {{ banner_position === 'center' ? 'center top' : (banner_position || 'center top') }}; --author-banner-size: {{ banner_size || 'cover' }}; @endif"> <div class="user-infobox-block" id="live-profile-preview-box" style="--author-accent: {{ session.username_color || 'var(--accent)' }}; --author-border: {{ session.username_color || 'var(--accent)' }}; @if(banner_file && user_banner_enabled) --author-banner: url('/a/{{ banner_file }}?t={{ Date.now() }}'); --author-banner-position: {{ banner_position === 'center' ? 'center top' : (banner_position || 'center top') }}; --author-banner-size: {{ banner_size || 'cover' }}; @endif">
<div class="user-infobox-avatar"> <div class="user-infobox-avatar">
@@ -245,247 +249,25 @@
</fieldset> </fieldset>
<!-- ═══════════════════════════════ PREFERENCES ═══════════════════════════════ --> <!-- ═══════════════════════════════ PREFERENCES ═══════════════════════════════ -->
<h2 id="preferences">{{ t('settings.preferences') }}</h2> <h2 id="preferences"><i class="fa-solid fa-sliders"></i> {{ t('settings.preferences') }}</h2>
<div class="preferences-settings-wrapper"> <div class="preferences-settings-wrapper">
<fieldset
style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.ui_section') }}</legend>
<div class="setting-item" style="margin-bottom: 15px;">
<label for="show_motd_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="show_motd_toggle" @if(session.show_motd !==false) checked @endif>
<span>{{ t('settings.show_motd') }}</span>
</label>
</div>
<div class="setting-item">
<label for="use_new_layout_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="use_new_layout_toggle" @if(session.use_new_layout===true) checked @endif>
<span>{{ t('settings.modern_layout') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.modern_layout_hint') }}</small>
</div>
@if(!session.use_new_layout)
<div class="setting-item" style="margin-top: 15px;">
<label for="alternative_infobox_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="alternative_infobox_toggle" @if(session.use_alternative_infobox===true) checked @endif>
<span>{{ t('settings.alternative_infobox') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.alternative_infobox_hint') }}</small>
</div>
@endif
@if(!session.use_new_layout)
<div class="setting-item" style="margin-top: 15px;">
<label for="alternative_steuerung_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="alternative_steuerung_toggle" @if(session.use_alternative_steuerung===true) checked @endif>
<span>{{ t('settings.alternative_steuerung') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.alternative_steuerung_hint') }}</small>
</div>
@endif
<div class="setting-item" style="margin-bottom: 15px;"> <!-- 1. Appearance & Theme -->
<label for="wheel_nav_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;"> <fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<input type="checkbox" id="wheel_nav_toggle"> <legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-palette"></i> {{ t('settings.appearance_section') }}</legend>
<span>{{ t('settings.scroll_nav') }}</span>
</label> <div class="setting-item" style="margin-top: 10px;">
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.scroll_nav_hint') }}</small> <label for="website_theme_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.theme') }}</label>
</div> <div style="display: flex; align-items: center; gap: 10px;">
<div class="setting-item" style="margin-bottom: 15px;"> <select id="website_theme_select" class="input" style="flex: 1; max-width: 300px;">
<label for="image_expand_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;"> @each(themes as t)
<input type="checkbox" id="image_expand_toggle"> <option value="{{ t }}" @if(theme===t) selected @endif>{{ t }}</option>
<span>{{ t('settings.image_expand_on_click') || 'Expand images inline on click' }}</span> @endeach
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.image_expand_on_click_hint') || 'Instead of opening the scroll zoom modal, clicking an image will expand it to full size within the page.' }}</small>
</div>
<div class="setting-item" style="margin-bottom: 15px;">
<label for="f_for_fullscreen_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="f_for_fullscreen_toggle">
<span>{{ t('settings.f_for_fullscreen') || 'F is for Fullscreen' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.f_for_fullscreen_hint') || 'Pressing F will toggle fullscreen in the video player instead of favoriting the post.' }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="disable_autoplay_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="disable_autoplay_toggle" @if(session.disable_autoplay===true) checked @endif>
<span>{{ t('settings.disable_autoplay') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.disable_autoplay_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="disable_swiping_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="disable_swiping_toggle" @if(session.disable_swiping===true) checked @endif>
<span>{{ t('settings.disable_swiping') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.disable_swiping_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="favorites_private_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="favorites_private_toggle" @if(session.favorites_private===true) checked @endif>
<span>{{ t('settings.favorites_private') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.favorites_private_hint') }}</small>
<div class="sub-setting-item" style="margin-left: 25px; margin-top: 10px;">
<label for="hide_fav_badge_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_fav_badge_toggle" @if(session.hide_fav_badge===true) checked @endif>
<span>{{ t('settings.hide_fav_badge') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_fav_badge_hint') }}</small>
</div>
</div>
@if(allow_user_upload_visibility !== false)
<div class="setting-item" style="margin-top: 15px;">
<label for="default_upload_visibility_select" style="display: block; font-weight: bold; margin-bottom: 5px;">
<span>{{ t('settings.default_upload_visibility') }}</span>
</label>
<select id="default_upload_visibility_select" class="form-control" style="width: 200px; padding: 5px; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--nav-border-color); border-radius: 4px;">
<option value="0" @if(session.default_upload_visibility === 0 || (!session.default_upload_visibility && session.default_upload_visibility !== 0)) selected @endif>{{ t('visibility.public') }}</option>
<option value="1" @if(session.default_upload_visibility === 1) selected @endif>{{ t('visibility.unlisted') }}</option>
<option value="2" @if(session.default_upload_visibility === 2) selected @endif>{{ t('visibility.private') }}</option>
</select> </select>
<small class="text-muted" style="display: block; margin-top: 5px;">{{ t('settings.default_upload_visibility_hint') }}</small>
</div> </div>
@endif
<div class="setting-item" style="margin-top: 15px;">
<label for="show_background_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="show_background_toggle" @if(session.show_background !==false) checked @endif>
<span>{{ t('settings.enable_bg_blur') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.enable_bg_blur_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="quote_emojis_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="quote_emojis_toggle" @if(session.quote_emojis !==false) checked @endif>
<span>{{ t('settings.render_emojis') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.render_emojis_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="embed_youtube_in_comments_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="embed_youtube_in_comments_toggle" @if(session.embed_youtube_in_comments !==false) checked @endif>
<span>{{ t('settings.embed_yt') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.embed_yt_hint') }}</small>
</div>
@if(show_koepfe)
<div class="setting-item" style="margin-top: 15px;">
<label for="hide_koepfe_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_koepfe_toggle" @if(session.hide_koepfe===true) checked @endif>
<span>{{ t('settings.hide_koepfe') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_koepfe_hint') }}</small>
</div>
@endif
@if(allow_language_change)
<div class="setting-item" style="margin-top: 15px;">
<label for="language_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.language') }}</label>
<select id="language_select" class="input" style="padding: 6px 10px; max-width: 220px;">
<option value="" @if(!session.language) selected @endif>{{ t('settings.language_default') }}</option>
<option value="en" @if(session.language==='en' ) selected @endif>{{ t('settings.language_en') }}</option>
<option value="de" @if(session.language==='de' ) selected @endif>{{ t('settings.language_de') }}</option>
<option value="nl" @if(session.language==='nl' ) selected @endif>{{ t('settings.language_nl') }}</option>
<option value="zange" @if(session.language==='zange' ) selected @endif>{{ t('settings.language_zange') }}
</option>
</select>
<br><small class="text-muted">{{ t('settings.language_hint') }}</small>
</div> </div>
@endif <div class="setting-item" style="margin-top: 18px;">
<div class="setting-item" style="margin-top: 15px;">
<label for="comment_display_mode_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.comment_display_mode') }}</label>
<select id="comment_display_mode_select" class="input" style="padding: 6px 10px; max-width: 220px;" @if(session.force_comment_display_mode) disabled @endif>
<option value="0" @if(session.comment_display_mode==0) selected @endif>{{ t('settings.comment_display_tree') }}</option>
<option value="1" @if(session.comment_display_mode==1) selected @endif>{{ t('settings.comment_display_linear') }}</option>
</select>
<br><small class="text-muted">
@if(session.force_comment_display_mode)
<strong>{{ t('settings.forced_mode_notice') || 'This setting is managed by an administrator.' }}</strong>
@else
{{ t('settings.comment_display_mode_hint') }}
@endif
</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="hide_item_ratings_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_item_ratings_toggle">
<span>{{ t('settings.hide_item_ratings') || 'Hide item ratings' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_item_ratings_hint') || 'Don\'t show SFW/NSFW rating indicators on main page items' }}</small>
</div>
</fieldset>
<fieldset
style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.content_preferences_section') }}</legend>
<div class="setting-item">
<label for="blur_nsfw_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_nsfw_toggle">
<span>{{ t('settings.blur_nsfw') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_nsfw_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_nsfl_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_nsfl_toggle">
<span>{{ t('settings.blur_nsfl') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_nsfl_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_sfw_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_sfw_toggle">
<span>{{ t('settings.blur_sfw') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_sfw_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_untagged_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_untagged_toggle">
<span>{{ t('settings.blur_untagged') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_untagged_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px; border-top: 1px dashed var(--nav-border-color); padding-top: 15px;">
<label for="blur_detail_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_detail_toggle">
<span>{{ t('settings.blur_detail') || 'Click to reveal item on detail page' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_detail_hint') || 'Require clicking to reveal blurred media on the post detail page instead of showing it immediately.' }}</small>
</div>
</fieldset>
<fieldset
style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.notifications_section') }}</legend>
<div class="setting-item">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-receive-system-notifications" @if(session.receive_system_notifications !==false) checked @endif>
<span>{{ t('settings.receive_system_notifications') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.receive_system_notifications_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-receive-user-notifications" @if(session.receive_user_notifications !==false) checked @endif>
<span>{{ t('settings.receive_user_notifications') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.receive_user_notifications_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-do-not-disturb" @if(session.do_not_disturb===true) checked @endif>
<span>{{ t('settings.do_not_disturb') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.do_not_disturb_hint') }}</small>
</div>
</fieldset>
<fieldset
style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;">
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.appearance_section') }}</legend>
<div class="setting-item" style="margin-top: 20px;">
<label for="website_font_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.website_font') }}</label> <label for="website_font_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.website_font') }}</label>
<div style="display: flex; align-items: center; gap: 10px;"> <div style="display: flex; align-items: center; gap: 10px;">
<select id="website_font_select" class="input" style="flex: 1; max-width: 300px;"> <select id="website_font_select" class="input" style="flex: 1; max-width: 300px;">
@@ -496,22 +278,281 @@
</select> </select>
</div> </div>
</div> </div>
<div class="setting-item" style="margin-top: 20px;">
<label for="website_theme_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.theme') }}</label> @if(allow_language_change)
<div style="display: flex; align-items: center; gap: 10px;"> <div class="setting-item" style="margin-top: 18px;">
<select id="website_theme_select" class="input" style="flex: 1; max-width: 300px;"> <label for="language_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.language') }}</label>
@each(themes as t) <select id="language_select" class="input" style="padding: 6px 10px; max-width: 300px;">
<option value="{{ t }}" @if(theme===t) selected @endif>{{ t }}</option> <option value="" @if(!session.language) selected @endif>{{ t('settings.language_default') }}</option>
@endeach <option value="en" @if(session.language==='en' ) selected @endif>{{ t('settings.language_en') }}</option>
<option value="de" @if(session.language==='de' ) selected @endif>{{ t('settings.language_de') }}</option>
<option value="nl" @if(session.language==='nl' ) selected @endif>{{ t('settings.language_nl') }}</option>
<option value="zange" @if(session.language==='zange' ) selected @endif>{{ t('settings.language_zange') }}</option>
</select> </select>
<small class="text-muted" style="display: block; margin-top: 4px;">{{ t('settings.language_hint') }}</small>
</div> </div>
@endif
<div class="setting-item" style="margin-top: 18px;">
<label for="show_background_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="show_background_toggle" @if(session.show_background !==false) checked @endif>
<span>{{ t('settings.enable_bg_blur') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.enable_bg_blur_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="show_motd_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="show_motd_toggle" @if(session.show_motd !==false) checked @endif>
<span>{{ t('settings.show_motd') }}</span>
</label>
</div> </div>
</fieldset> </fieldset>
<!-- 2. Interface & Layout -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-desktop"></i> {{ t('settings.ui_section') }}</legend>
<div class="setting-item">
<label for="use_new_layout_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="use_new_layout_toggle" @if(session.use_new_layout===true) checked @endif>
<span>{{ t('settings.modern_layout') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.modern_layout_hint') }}</small>
</div>
@if(!session.use_new_layout)
<div class="setting-item" style="margin-top: 15px;">
<label for="alternative_infobox_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="alternative_infobox_toggle" @if(session.use_alternative_infobox===true) checked @endif>
<span>{{ t('settings.alternative_infobox') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.alternative_infobox_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="alternative_steuerung_toggle"
style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="alternative_steuerung_toggle" @if(session.use_alternative_steuerung===true) checked @endif>
<span>{{ t('settings.alternative_steuerung') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.alternative_steuerung_hint') }}</small>
</div>
@endif
@if(show_koepfe)
<div class="setting-item" style="margin-top: 15px;">
<label for="hide_koepfe_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_koepfe_toggle" @if(session.hide_koepfe===true) checked @endif>
<span>{{ t('settings.hide_koepfe') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_koepfe_hint') }}</small>
</div>
@endif
</fieldset>
<!-- 3. Playback & Navigation Controls -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-play"></i> Playback & Navigation</legend>
<div class="setting-item">
<label for="disable_autoplay_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="disable_autoplay_toggle" @if(session.disable_autoplay===true) checked @endif>
<span>{{ t('settings.disable_autoplay') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.disable_autoplay_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="disable_swiping_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="disable_swiping_toggle" @if(session.disable_swiping===true) checked @endif>
<span>{{ t('settings.disable_swiping') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.disable_swiping_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="wheel_nav_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="wheel_nav_toggle">
<span>{{ t('settings.scroll_nav') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.scroll_nav_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="image_expand_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="image_expand_toggle">
<span>{{ t('settings.image_expand_on_click') || 'Expand images inline on click' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.image_expand_on_click_hint') || 'Instead of opening the scroll zoom modal, clicking an image will expand it to full size within the page.' }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="f_for_fullscreen_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="f_for_fullscreen_toggle">
<span>{{ t('settings.f_for_fullscreen') || 'F is for Fullscreen' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.f_for_fullscreen_hint') || 'Pressing F will toggle fullscreen in the video player instead of favoriting the post.' }}</small>
</div>
</fieldset>
<!-- 4. Comments & Discussion -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-comments"></i> Comments & Discussion</legend>
<div class="setting-item">
<label for="comment_display_mode_select" style="display: block; margin-bottom: 5px; font-weight: bold;">{{ t('settings.comment_display_mode') }}</label>
<select id="comment_display_mode_select" class="input" style="padding: 6px 10px; max-width: 300px;" @if(session.force_comment_display_mode) disabled @endif>
<option value="0" @if(session.comment_display_mode==0) selected @endif>{{ t('settings.comment_display_tree') }}</option>
<option value="1" @if(session.comment_display_mode==1) selected @endif>{{ t('settings.comment_display_linear') }}</option>
</select>
<small class="text-muted" style="display: block; margin-top: 4px;">
@if(session.force_comment_display_mode)
<strong>{{ t('settings.forced_mode_notice') || 'This setting is managed by an administrator.' }}</strong>
@else
{{ t('settings.comment_display_mode_hint') }}
@endif
</small>
</div>
<div class="setting-item" style="margin-top: 18px;">
<label for="quote_emojis_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="quote_emojis_toggle" @if(session.quote_emojis !==false) checked @endif>
<span>{{ t('settings.render_emojis') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.render_emojis_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="embed_youtube_in_comments_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="embed_youtube_in_comments_toggle" @if(session.embed_youtube_in_comments !==false) checked @endif>
<span>{{ t('settings.embed_yt') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.embed_yt_hint') }}</small>
</div>
</fieldset>
<!-- 5. Content Preferences & Blurring -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-eye-slash"></i> {{ t('settings.content_preferences_section') }}</legend>
<div class="setting-item">
<label for="blur_sfw_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_sfw_toggle">
<span>{{ t('settings.blur_sfw') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_sfw_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_nsfw_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_nsfw_toggle">
<span>{{ t('settings.blur_nsfw') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_nsfw_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_nsfl_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_nsfl_toggle">
<span>{{ t('settings.blur_nsfl') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_nsfl_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_untagged_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_untagged_toggle">
<span>{{ t('settings.blur_untagged') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_untagged_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="blur_detail_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="blur_detail_toggle">
<span>{{ t('settings.blur_detail') || 'Click to reveal item on detail page' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.blur_detail_hint') || 'Require clicking to reveal blurred media on the post detail page instead of showing it immediately.' }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label for="hide_item_ratings_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_item_ratings_toggle">
<span>{{ t('settings.hide_item_ratings') || 'Hide item ratings' }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_item_ratings_hint') || 'Don\'t show SFW/NSFW rating indicators on main page items' }}</small>
</div>
</fieldset>
<!-- 6. Privacy & Upload Defaults -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-user-shield"></i> Privacy & Defaults</legend>
<div class="setting-item">
<label for="favorites_private_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="favorites_private_toggle" @if(session.favorites_private===true) checked @endif>
<span>{{ t('settings.favorites_private') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.favorites_private_hint') }}</small>
<div class="sub-setting-item" style="margin-left: 25px; margin-top: 10px;">
<label for="hide_fav_badge_toggle" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="hide_fav_badge_toggle" @if(session.hide_fav_badge===true) checked @endif>
<span>{{ t('settings.hide_fav_badge') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.hide_fav_badge_hint') }}</small>
</div>
</div>
@if(allow_user_upload_visibility !== false)
<div class="setting-item" style="margin-top: 18px;">
<label for="default_upload_visibility_select" style="display: block; font-weight: bold; margin-bottom: 5px;">
<span>{{ t('settings.default_upload_visibility') }}</span>
</label>
<select id="default_upload_visibility_select" class="form-control" style="width: 220px; padding: 6px 10px; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--nav-border-color); border-radius: 4px;">
<option value="0" @if(session.default_upload_visibility === 0 || (!session.default_upload_visibility && session.default_upload_visibility !== 0)) selected @endif>{{ t('visibility.public') }}</option>
<option value="1" @if(session.default_upload_visibility === 1) selected @endif>{{ t('visibility.unlisted') }}</option>
<option value="2" @if(session.default_upload_visibility === 2) selected @endif>{{ t('visibility.private') }}</option>
</select>
<small class="text-muted" style="display: block; margin-top: 5px;">{{ t('settings.default_upload_visibility_hint') }}</small>
</div>
@endif
</fieldset>
<!-- 7. Notifications -->
<fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
<legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-bell"></i> {{ t('settings.notifications_section') }}</legend>
<div class="setting-item">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-receive-system-notifications" @if(session.receive_system_notifications !==false) checked @endif>
<span>{{ t('settings.receive_system_notifications') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.receive_system_notifications_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-receive-user-notifications" @if(session.receive_user_notifications !==false) checked @endif>
<span>{{ t('settings.receive_user_notifications') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.receive_user_notifications_hint') }}</small>
</div>
<div class="setting-item" style="margin-top: 15px;">
<label class="checkbox-container" style="cursor: pointer; display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="chk-do-not-disturb" @if(session.do_not_disturb===true) checked @endif>
<span>{{ t('settings.do_not_disturb') }}</span>
</label>
<small class="text-muted" style="margin-left: 25px;">{{ t('settings.do_not_disturb_hint') }}</small>
</div>
</fieldset>
<!-- 8. Flash / SWF Settings (if enabled) -->
@if(enable_swf) @if(enable_swf)
<fieldset <fieldset style="border: 1px solid var(--nav-border-color); padding: 12px 16px; border-radius: 6px; margin-bottom: 20px; background: rgba(0,0,0,0.06);">
style="border: 1px solid var(--nav-border-color); padding: 10px; border-radius: 4px; margin-bottom: 15px;"> <legend style="width: auto; padding: 0 8px; font-size: 1.05em; font-weight: bold;"><i class="fa-solid fa-bolt"></i> {{ t('settings.flash_section') }}</legend>
<legend style="width: auto; padding: 0 5px; font-size: 1.1em; font-weight: bold;">{{ t('settings.flash_section') }}</legend>
<div class="setting-item"> <div class="setting-item">
<label for="ruffle_background_toggle" <label for="ruffle_background_toggle"
@@ -526,10 +567,11 @@
@endif @endif
</div> </div>
@if(enable_data_export) @if(enable_data_export)
<!-- ═══════════════════════════════ EXPORT ═══════════════════════════════ --> <!-- ═══════════════════════════════ EXPORT ═══════════════════════════════ -->
<h2 id="export">{{ t('settings.export_data_title') || 'Export Data' }}</h2> <h2 id="export"><i class="fa-solid fa-file-export"></i> {{ t('settings.export_data_title') || 'Export Data' }}</h2>
<div class="export-settings-wrapper" style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 4px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;"> <div class="export-settings-wrapper" style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 6px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;">
<p>{{ t('settings.export_data_desc') || 'Download a copy of your data. This process happens entirely in your browser to protect your privacy and save server resources.' }}</p> <p>{{ t('settings.export_data_desc') || 'Download a copy of your data. This process happens entirely in your browser to protect your privacy and save server resources.' }}</p>
<div class="setting-item" style="margin-bottom: 15px;"> <div class="setting-item" style="margin-bottom: 15px;">
@@ -568,10 +610,11 @@
</button> </button>
</div> </div>
@endif @endif
<!-- ═══════════════════════════════ ACCOUNT ═══════════════════════════════ --> <!-- ═══════════════════════════════ ACCOUNT ═══════════════════════════════ -->
<h2 id="account">{{ t('settings.account') }}</h2> <h2 id="account"><i class="fa-solid fa-shield-halved"></i> {{ t('settings.account') }}</h2>
<div class="account-settings-wrapper" <div class="account-settings-wrapper"
style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 4px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;"> style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 6px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;">
<table class="table account-info-table" <table class="table account-info-table"
style="margin-bottom: 30px; border-collapse: separate; border-spacing: 0 5px;"> style="margin-bottom: 30px; border-collapse: separate; border-spacing: 0 5px;">
<tbody> <tbody>
@@ -597,7 +640,7 @@
<div class="account-actions-grid" <div class="account-actions-grid"
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px;"> style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px;">
<div class="password-change-section" style="display: flex; flex-direction: column; gap: 15px;"> <div class="password-change-section" style="display: flex; flex-direction: column; gap: 15px;">
<h4 style="margin-top: 0; color: var(--accent);">{{ t('settings.change_password') }}</h4> <h4 style="margin-top: 0; color: var(--accent);"><i class="fa-solid fa-key"></i> {{ t('settings.change_password') }}</h4>
<form id="password-change-form" style="display: flex; flex-direction: column; gap: 10px;"> <form id="password-change-form" style="display: flex; flex-direction: column; gap: 10px;">
<input type="password" id="current_password" class="input" <input type="password" id="current_password" class="input"
placeholder="{{ t('settings.current_password') }}" required autocomplete="current-password"> placeholder="{{ t('settings.current_password') }}" required autocomplete="current-password">
@@ -612,7 +655,7 @@
</div> </div>
<div class="email-update-section" style="display: flex; flex-direction: column; gap: 15px;"> <div class="email-update-section" style="display: flex; flex-direction: column; gap: 15px;">
<h4 style="margin-top: 0; color: var(--accent);">{{ t('settings.update_email') }}</h4> <h4 style="margin-top: 0; color: var(--accent);"><i class="fa-solid fa-envelope"></i> {{ t('settings.update_email') }}</h4>
<form id="email-update-form" style="display: flex; flex-direction: column; gap: 10px;"> <form id="email-update-form" style="display: flex; flex-direction: column; gap: 10px;">
<input type="email" id="email_input" class="input" placeholder="{{ t('settings.new_email') }}" <input type="email" id="email_input" class="input" placeholder="{{ t('settings.new_email') }}"
value="{{ email }}" required> value="{{ email }}" required>
@@ -627,10 +670,11 @@
</div> </div>
</div> </div>
</div> </div>
@if(matrix_enabled || telegram_enabled) @if(matrix_enabled || telegram_enabled)
<!-- ═══════════════════════════════ LINKED ACCOUNTS ═══════════════════════════════ --> <!-- ═══════════════════════════════ LINKED ACCOUNTS ═══════════════════════════════ -->
<h2 id="linked">{{ t('settings.linked_accounts') }}</h2> <h2 id="linked"><i class="fa-solid fa-link"></i> {{ t('settings.linked_accounts') }}</h2>
<div class="linked-accounts-wrapper"> <div class="linked-accounts-wrapper" style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 6px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;">
<p>{{ t('settings.matrix_link_desc') }}</p> <p>{{ t('settings.matrix_link_desc') }}</p>
<div id="linked-accounts-container" style="margin-bottom: 1rem;"> <div id="linked-accounts-container" style="margin-bottom: 1rem;">
@@ -666,9 +710,9 @@
@if(enable_user_api_keys) @if(enable_user_api_keys)
<!-- ═══════════════════════════════ API KEY ═══════════════════════════════ --> <!-- ═══════════════════════════════ API KEY ═══════════════════════════════ -->
<h2 id="apikey">Upload API Key</h2> <h2 id="apikey"><i class="fa-solid fa-key"></i> Upload API Key</h2>
<div id="api-key-section" class="account-settings-wrapper" <div id="api-key-section" class="account-settings-wrapper"
style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 4px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;"> style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 6px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;">
<p style="color: var(--text-muted); margin-bottom: 15px;"> <p style="color: var(--text-muted); margin-bottom: 15px;">
Use this key to upload files via external tools or scripts like ShareX. Use this key to upload files via external tools or scripts like ShareX.
The key grants <strong>upload access only</strong> to your account. The key grants <strong>upload access only</strong> to your account.
@@ -702,9 +746,9 @@
@if(enable_user_invites) @if(enable_user_invites)
<!-- ═══════════════════════════════ INVITES ═══════════════════════════════ --> <!-- ═══════════════════════════════ INVITES ═══════════════════════════════ -->
<h2 id="invites">{{ t('invites.section_title') }}</h2> <h2 id="invites"><i class="fa-solid fa-ticket"></i> {{ t('invites.section_title') }}</h2>
<div id="invite-section" class="account-settings-wrapper" <div id="invite-section" class="account-settings-wrapper"
style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 4px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;"> style="background: rgba(0,0,0,0.1); padding: 20px; border-radius: 6px; border: 1px solid var(--nav-border-color); margin-bottom: 30px;">
<p id="invite-section-desc" style="color: var(--text-muted); margin-bottom: 15px;">{{ t('invites.section_desc') }}</p> <p id="invite-section-desc" style="color: var(--text-muted); margin-bottom: 15px;">{{ t('invites.section_desc') }}</p>
@@ -816,8 +860,6 @@
<script> <script>
(function() { (function() {
// Read all translated strings from server-rendered data attributes.
// Attributes must be lowercase kebab-case: data-foo-bar → dataset.fooBar
const ds = document.getElementById('invite-i18n')?.dataset || {}; const ds = document.getElementById('invite-i18n')?.dataset || {};
const T = (key, vars) => { const T = (key, vars) => {
let str = ds[key] || key; let str = ds[key] || key;
@@ -852,7 +894,6 @@
} }
if (data.is_admin) { if (data.is_admin) {
// Swap description and hide criteria/slots UI for admins
const desc = document.getElementById('invite-section-desc'); const desc = document.getElementById('invite-section-desc');
if (desc) desc.textContent = T('adminDesc'); if (desc) desc.textContent = T('adminDesc');
const grid = document.getElementById('invite-criteria-grid'); const grid = document.getElementById('invite-criteria-grid');
@@ -860,7 +901,6 @@
if (grid) grid.style.display = 'none'; if (grid) grid.style.display = 'none';
if (statusLine) statusLine.style.display = 'none'; if (statusLine) statusLine.style.display = 'none';
} else { } else {
// Update criteria grid
const criteriaMap = { const criteriaMap = {
'ic-uploads': data.criteria.uploads, 'ic-uploads': data.criteria.uploads,
'ic-age': data.criteria.age_days, 'ic-age': data.criteria.age_days,
@@ -878,19 +918,15 @@
}); });
} }
// Eligibility badge
const badge = document.getElementById('invite-eligible-badge'); const badge = document.getElementById('invite-eligible-badge');
badge.textContent = data.eligible ? T('eligible') : T('notEligible'); badge.textContent = data.eligible ? T('eligible') : T('notEligible');
badge.style.color = data.eligible ? '#51cf66' : '#ff6b6b'; badge.style.color = data.eligible ? '#51cf66' : '#ff6b6b';
// Slots info
document.getElementById('invite-slots-info').textContent = document.getElementById('invite-slots-info').textContent =
T('slotsUsed', { used: data.slots_consumed, total: data.slots_total }); T('slotsUsed', { used: data.slots_consumed, total: data.slots_total });
// Generate button state
genBtn.disabled = !data.eligible || (!data.is_admin && data.slots_available <= 0); genBtn.disabled = !data.eligible || (!data.is_admin && data.slots_available <= 0);
// Token list
if (!data.tokens || data.tokens.length === 0) { if (!data.tokens || data.tokens.length === 0) {
tokenList.innerHTML = '<span class="text-muted" style="font-size:0.9em;">' + T('noInvites') + '</span>'; tokenList.innerHTML = '<span class="text-muted" style="font-size:0.9em;">' + T('noInvites') + '</span>';
} else { } else {