diff --git a/assets/css/forum-style.css b/assets/css/forum-style.css index 93328bf..a8f5e9f 100644 --- a/assets/css/forum-style.css +++ b/assets/css/forum-style.css @@ -416,14 +416,57 @@ a.wbf-btn--primary:hover { align-items: center; text-align: center; } + +/* Banner */ +.wbf-profile-banner { + position: relative; + width: 100%; + height: 120px; + overflow: hidden; + background: linear-gradient(135deg, #0a1628 0%, #162040 50%, #0d1a30 100%); +} +.wbf-profile-banner__img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.wbf-profile-banner__placeholder { + width: 100%; + height: 100%; + background: linear-gradient(135deg, #0a1628 0%, #162040 50%, #0d1a30 100%); +} +.wbf-banner-upload-btn { + position: absolute; + bottom: 8px; + right: 8px; + width: 32px; + height: 32px; + border-radius: 50%; + background: rgba(0,0,0,.55); + backdrop-filter: blur(6px); + color: #fff; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background .2s, transform .15s; + font-size: .8rem; + border: 1px solid rgba(255,255,255,.15); +} +.wbf-banner-upload-btn:hover { + background: rgba(0,180,216,.5); + transform: scale(1.1); +} + .wbf-profile-sidebar__avatar-wrap { position: relative; - padding: 2rem 0 1.25rem; + padding: 0 0 1.25rem; + margin-top: -45px; width: 100%; display: flex; justify-content: center; - background: linear-gradient(160deg, #0d1117, #161d2e); - border-bottom: 1px solid rgba(0,180,216,.12); + z-index: 2; } .wbf-profile-sidebar__avatar { width: 100px; height: 100px; @@ -557,6 +600,235 @@ a.wbf-btn--primary:hover { padding-top: 1rem; border-top: 1px solid var(--c-border); } +/* ── Verbindungen / Connection Cards ────────────────────────────────────── */ +.wbf-connection-card { + display: grid; + grid-template-columns: 56px 1fr; + grid-template-rows: auto auto; + gap: 0 1.1rem; + padding: 1.4rem 1.25rem; + border-bottom: 1px solid var(--c-border); + transition: background .15s; +} +.wbf-connection-card:last-child { border-bottom: none; } +.wbf-connection-card:hover { background: rgba(255,255,255,.025); } + +.wbf-connection-card__icon { + grid-column: 1; + grid-row: 1 / 3; + width: 48px; + height: 48px; + border-radius: 12px; + border: 1px solid transparent; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.35rem; + align-self: center; +} + +/* Titelzeile — rechts oben */ +.wbf-connection-card__head { + grid-column: 2; + grid-row: 1; + display: flex; + align-items: center; + gap: .6rem; + margin-bottom: .5rem; +} + +.wbf-connection-card__body { + flex: 1; + min-width: 0; +} + +.wbf-connection-card__title { + font-weight: 700; + font-size: .92rem; + color: var(--c-text); + line-height: 1; +} + +.wbf-connection-card__desc { + font-size: .82rem; + color: var(--c-muted); + line-height: 1.55; + margin-bottom: .85rem; +} + +/* Content-Bereich — grid row 2, rechte Spalte */ +.wbf-connection-card__content { + grid-column: 2; + grid-row: 2; +} + +/* Plugin-Output normalisieren */ +.wbf-connection-card__content p { + font-size: .8rem; + color: var(--c-muted); + line-height: 1.5; + margin: 0 0 .7rem; + font-weight: 400 !important; +} +.wbf-connection-card__content label { + display: block; + font-size: .75rem; + font-weight: 600; + color: var(--c-text-dim); + text-transform: uppercase; + letter-spacing: .04em; + margin-bottom: .35rem; +} +.wbf-connection-card__content .wbf-mc-row, +.wbf-connection-card__content > form, +.wbf-connection-card__content > div { + display: flex; + align-items: center; + gap: .55rem; + flex-wrap: wrap; +} + +/* Input + Button auf einer Linie halten */ +.wbf-connect-row { + display: flex !important; + align-items: center !important; + gap: .55rem !important; + flex-wrap: nowrap !important; +} +.wbf-connect-row input[type="text"] { + flex: 1 1 0; + min-width: 0; + max-width: none !important; +} +.wbf-connect-row button, +.wbf-connect-row .wbf-btn { + flex-shrink: 0; + white-space: nowrap; +} + +/* Alle Verknüpfen-Buttons in Connection-Cards vereinheitlichen */ +.wbf-connection-card__content .wbf-btn, +.wbf-connection-card__content button:not(.wbf-bb-spoiler__btn) { + padding: .5rem 1rem !important; + font-size: .83rem !important; + font-weight: 600 !important; + height: 2.25rem !important; + line-height: 1 !important; + display: inline-flex !important; + align-items: center !important; + gap: .4rem !important; + border-radius: var(--radius-sm) !important; + border: 1.5px solid transparent !important; + cursor: pointer !important; + font-family: inherit !important; + transition: var(--transition) !important; + white-space: nowrap !important; +} +/* Primär (Verknüpfen / Code senden) */ +.wbf-connection-card__content .wbf-btn--primary, +.wbf-connection-card__content button.wbf-btn--primary { + background: var(--c-primary) !important; + color: #fff !important; + border-color: var(--c-primary) !important; + box-shadow: 0 0 10px rgba(0,180,216,.25) !important; +} +.wbf-connection-card__content .wbf-btn--primary:hover { + background: var(--c-primary-d) !important; + border-color: var(--c-primary-d) !important; +} +/* Ghost (Zurück / Trennen) */ +.wbf-connection-card__content .wbf-btn--ghost, +.wbf-connection-card__content button.wbf-btn--ghost { + background: transparent !important; + color: var(--c-text-dim) !important; + border-color: var(--c-border-d) !important; +} +.wbf-connection-card__content .wbf-btn--ghost:hover { + border-color: var(--c-primary) !important; + color: var(--c-primary) !important; +} +/* MC-Plugin: dessen Button via content selector normalisieren */ +.wbf-connection-card__content input[type="submit"], +.wbf-connection-card__content .mc-connect-btn { + padding: .5rem 1rem !important; + height: 2.25rem !important; + font-size: .83rem !important; + font-weight: 600 !important; + background: var(--c-primary) !important; + color: #fff !important; + border: 1.5px solid var(--c-primary) !important; + border-radius: var(--radius-sm) !important; + cursor: pointer !important; + font-family: inherit !important; + white-space: nowrap !important; + display: inline-flex !important; + align-items: center !important; +} +.wbf-connection-card__content input[type="text"] { + flex: 1; + min-width: 160px; + max-width: 280px; + padding: .45rem .75rem; + border: 1px solid var(--c-border); + border-radius: var(--radius-sm, 6px); + background: var(--c-bg); + color: var(--c-text); + font-size: .88rem; +} +.wbf-connection-card__content input[type="text"]:focus { + outline: none; + border-color: var(--c-primary); + box-shadow: 0 0 0 3px rgba(0,180,216,.15); +} +.wbf-connection-card__content button, +.wbf-connection-card__content .wbf-btn { + white-space: nowrap; +} + +/* Status-Badge in der Card (verbunden / nicht verbunden) */ +.wbf-connection-badge { + display: inline-flex; + align-items: center; + gap: .35rem; + font-size: .78rem; + font-weight: 600; + padding: .25rem .65rem; + border-radius: 20px; +} +.wbf-connection-badge--connected { + color: #16a34a; + background: rgba(22,163,74,.12); + border: 1px solid rgba(22,163,74,.25); +} +.wbf-connection-badge--disconnected { + color: var(--c-muted); + background: rgba(148,163,184,.08); + border: 1px solid var(--c-border); +} + +/* Discord-spezifische Farben */ +.wbf-connection-card--discord .wbf-connection-card__icon { + background: rgba(88,101,242,.15); + border-color: rgba(88,101,242,.3); +} +.wbf-connection-card--discord .wbf-connection-card__icon i { + color: #5865f2; +} + +/* Verbunden-Info */ +.wbf-discord-linked-name { + display: inline-flex; + align-items: center; + gap: .4rem; + font-weight: 700; + font-size: .92rem; + color: var(--c-text); + padding: .35rem .75rem; + background: rgba(88,101,242,.1); + border: 1px solid rgba(88,101,242,.25); + border-radius: 20px; +} + .wbf-profile-edit-grid { display: grid; grid-template-columns: 1fr 1fr; @@ -1816,10 +2088,15 @@ select.wbf-cf-input option { background: var(--c-surface2); color: var(--c-text) text-align: left; } .wbf-profile-sidebar__avatar-wrap { - padding: 1.25rem; + padding: 0 0 1rem; + margin-top: -45px; width: auto; border-bottom: none; - border-right: 1px solid var(--c-border); + border-right: none; + } + .wbf-profile-banner { + height: 100px; + width: 100%; } .wbf-profile-sidebar__identity { align-items: flex-start; diff --git a/assets/js/forum-script.js b/assets/js/forum-script.js index da4fdb0..f9ebd0a 100644 --- a/assets/js/forum-script.js +++ b/assets/js/forum-script.js @@ -3,6 +3,10 @@ /* ── Utilities ──────────────────────────────────────────────── */ function wbfPost(action, data, cb, errCb) { + if (typeof WBF === 'undefined' || !WBF.ajax_url || !WBF.nonce) { + if (errCb) errCb({message: 'Forum-Fehler: AJAX-Setup fehlt. Bitte Seite neu laden.'}); + return; + } data.action = action; data.nonce = WBF.nonce; $.post(WBF.ajax_url, data, function (res) { @@ -52,12 +56,18 @@ /* ── Registrieren ───────────────────────────────────────────── */ $(document).on('click', '.wbf-reg-submit-btn', function () { var $btn = $(this).prop('disabled', true).html(''); + var $invite = $(this).closest('.wbf-auth-box').find('.wbf-field-invite-code'); + var inviteVal = ''; + if ($invite.length > 0) { + var raw = $invite.val(); + if (typeof raw === 'string') inviteVal = raw.toUpperCase().trim(); + } wbfPost('wbf_register', { username: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-user').val(), display_name: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-name').val(), email: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-email').val(), password: $(this).closest('.wbf-auth-box').find('.wbf-field-reg-pass').val(), - invite_code: $(this).closest('.wbf-auth-box').find('.wbf-field-invite-code').val().toUpperCase().trim(), + invite_code: inviteVal, rules_accepted: $(this).closest('.wbf-auth-box').find('.wbf-field-rules-accept').is(':checked') ? '1' : '' }, function () { location.reload(); @@ -609,6 +619,48 @@ }); }); + // ── Banner-Upload ───────────────────────────────────────────────────────── + $(document).on('change', '#wbfBannerFile', function () { + var file = this.files[0]; + if (!file) return; + + // Sofort-Vorschau + var objectUrl = URL.createObjectURL(file); + var $wrap = $('#wbfProfileBannerWrap'); + var $existing = $wrap.find('.wbf-profile-banner__img'); + + // Falls noch kein Banner-Bild existiert, eins einfügen + if ($existing.length === 0) { + $wrap.prepend(''); + } else { + $existing.attr('src', objectUrl).css('opacity', '.4'); + } + + var fd = new FormData(); + fd.append('action', 'wbf_upload_banner'); + fd.append('nonce', WBF.nonce); + fd.append('banner', file); + + $.ajax({ + url: WBF.ajax_url, + type: 'POST', + data: fd, + processData: false, + contentType: false, + success: function (res) { + var $img = $wrap.find('.wbf-profile-banner__img'); + if (res.success) { + URL.revokeObjectURL(objectUrl); + $img.attr('src', res.data.banner_url + '?v=' + Date.now()); + } + $img.css('opacity', ''); + }, + error: function () { + $wrap.find('.wbf-profile-banner__img').css('opacity', ''); + } + }); + }); + /* ══════════════════════════════════════════════════════════ FEATURE: Ungelesene Beiträge ══════════════════════════════════════════════════════════ */ @@ -2163,4 +2215,132 @@ $bar.hide(); }); -}(jQuery)); \ No newline at end of file + + + // ── Discord-Integration (3-Schritt Verifikation) ───────────────────────── + + var wbfDcStep = 1; // aktueller Schritt + + function wbfDcMsg(text, color) { + var $m = $('#wbf-discord-msg'); + $m.css('color', color || 'var(--c-muted)').html(text); + } + + function wbfDcSetBadge(connected) { + var $badge = $('.wbf-connection-card--discord .wbf-connection-badge'); + if (connected) { + $badge.removeClass('wbf-connection-badge--disconnected') + .addClass('wbf-connection-badge--connected') + .html(' Verbunden'); + } else { + $badge.removeClass('wbf-connection-badge--connected') + .addClass('wbf-connection-badge--disconnected') + .html(' Nicht verbunden'); + } + } + + // Schritt 1 → Code senden + $(document).on('click', '#wbf-discord-send-code', function () { + var username = $('#wbf-discord-input').val().trim(); + if (!username) { wbfDcMsg(' Bitte Benutzername eingeben.', '#f97316'); return; } + var $btn = $(this).prop('disabled', true).html(' Sende…'); + wbfDcMsg(''); + $.post(WBF.ajax_url, { + action: 'wbf_discord_send_code', + nonce: WBF.nonce, + discord_username: username, + }, function (res) { + $btn.prop('disabled', false).html(' Code senden'); + if (res.success) { + wbfDcMsg(' ' + (res.data.message || 'Code gesendet!'), '#16a34a'); + $('#wbf-dc-step1').slideUp(200, function () { $('#wbf-dc-step2').slideDown(200); }); + $('#wbf-discord-code-input').val('').focus(); + wbfDcStep = 2; + } else { + wbfDcMsg(' ' + ((res.data && res.data.message) || 'Fehler.'), '#dc2626'); + } + }).fail(function () { + $btn.prop('disabled', false).html(' Code senden'); + wbfDcMsg(' Netzwerkfehler.', '#dc2626'); + }); + }); + + // Schritt 2 → Code bestätigen + $(document).on('click', '#wbf-discord-verify', function () { + var code = $('#wbf-discord-code-input').val().trim().toUpperCase(); + if (code.length < 4) { wbfDcMsg(' Bitte Code eingeben.', '#f97316'); return; } + var $btn = $(this).prop('disabled', true).html(' Prüfe…'); + $.post(WBF.ajax_url, { + action: 'wbf_discord_verify_code', + nonce: WBF.nonce, + verify_code: code, + }, function (res) { + $btn.prop('disabled', false).html(' Bestätigen'); + if (res.success) { + wbfDcMsg(' ' + (res.data.message || 'Verbunden!'), '#16a34a'); + wbfDcSetBadge(true); + // UI auf "Verbunden"-Ansicht umschalten + var name = res.data.display_name || ''; + $('#wbf-discord-form').slideUp(200); + // Verbunden-Info einfügen/aktualisieren + var $info = $('.wbf-discord-connected-info'); + if ($info.length) { + $info.find('.wbf-discord-linked-name').html(' ' + $('').text(name).html()); + } else { + // Frisch laden damit die PHP-Struktur stimmt + setTimeout(function(){ location.reload(); }, 1200); + } + } else { + wbfDcMsg(' ' + ((res.data && res.data.message) || 'Fehler.'), '#dc2626'); + } + }).fail(function () { + $btn.prop('disabled', false).html(' Bestätigen'); + wbfDcMsg(' Netzwerkfehler.', '#dc2626'); + }); + }); + + // Enter-Taste auf Code-Feld + $(document).on('keydown', '#wbf-discord-code-input', function (e) { + if (e.key === 'Enter') { e.preventDefault(); $('#wbf-discord-verify').trigger('click'); } + }); + + // Enter-Taste auf Username-Feld + $(document).on('keydown', '#wbf-discord-input', function (e) { + if (e.key === 'Enter') { e.preventDefault(); $('#wbf-discord-send-code').trigger('click'); } + }); + + // „Zurück" in Schritt 2 + $(document).on('click', '#wbf-discord-code-back', function () { + $('#wbf-dc-step2').slideUp(200, function () { $('#wbf-dc-step1').slideDown(200); }); + wbfDcMsg(''); + wbfDcStep = 1; + }); + + // „Neu verknüpfen" bei bereits verbundenem Account + $(document).on('click', '#wbf-discord-relink', function () { + $('#wbf-discord-form').slideDown(200); + $('#wbf-discord-input').val('').focus(); + }); + + // Verbindung trennen + $(document).on('click', '#wbf-discord-disconnect', function () { + if (!confirm('Discord-Verbindung wirklich trennen?')) return; + var $btn = $(this).prop('disabled', true); + $.post(WBF.ajax_url, { + action: 'wbf_save_discord', + nonce: WBF.nonce, + sub_action: 'disconnect', + }, function (res) { + $btn.prop('disabled', false); + if (res.success) { + wbfDcMsg(' ' + (res.data.message || 'Getrennt.'), '#16a34a'); + wbfDcSetBadge(false); + setTimeout(function () { location.reload(); }, 900); + } else { + wbfDcMsg(' ' + ((res.data && res.data.message) || 'Fehler.'), '#dc2626'); + } + }); + }); + +}(jQuery)); +// Overwrite last line — Discord handlers appended via patch: \ No newline at end of file