Add support page, admin features, and auth hardening.
Rename public affiliate route to /support with localized nav labels, and include affiliate/social/wallpaper admin, 2FA login, and related site updates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
202dc16a52
commit
fc45c35dbe
@@ -77,4 +77,63 @@ body {
|
||||
|
||||
.project-iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Affiliate links
|
||||
*/
|
||||
|
||||
.affiliate-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.affiliate-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.85rem 1.1rem;
|
||||
border-radius: 0.75rem;
|
||||
background-color: rgba(255, 255, 255, .05);
|
||||
border: 1px solid rgba(255, 255, 255, .1);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
transition: transform .2s ease, background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
|
||||
}
|
||||
|
||||
.affiliate-card:hover,
|
||||
.affiliate-card:focus {
|
||||
background-color: rgba(255, 255, 255, .1);
|
||||
border-color: rgba(255, 255, 255, .3);
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 .5rem 1.25rem rgba(0, 0, 0, .3);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.affiliate-logo {
|
||||
flex-shrink: 0;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
object-fit: contain;
|
||||
background: #fff;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.affiliate-text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.affiliate-title {
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.affiliate-desc {
|
||||
color: rgba(255, 255, 255, .6);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
var PasteImageModal = (function () {
|
||||
var bsModal, targetEl, previewEl, defaultText;
|
||||
var currentInputSelector, currentPreviewSelector;
|
||||
|
||||
function init() {
|
||||
var modalEl = document.getElementById('pasteImageModal');
|
||||
if (!modalEl || typeof bootstrap === 'undefined') return false;
|
||||
|
||||
targetEl = document.getElementById('pasteImageTarget');
|
||||
previewEl = document.getElementById('pasteImageModalPreview');
|
||||
defaultText = targetEl.textContent;
|
||||
bsModal = new bootstrap.Modal(modalEl);
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', function () {
|
||||
targetEl.textContent = defaultText;
|
||||
previewEl.style.display = 'none';
|
||||
previewEl.removeAttribute('src');
|
||||
targetEl.focus();
|
||||
});
|
||||
|
||||
targetEl.addEventListener('paste', function (e) {
|
||||
var clipboard = e.clipboardData || window.clipboardData;
|
||||
var items = clipboard ? clipboard.items : null;
|
||||
if (!items) return;
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
if (item.kind === 'file' && item.type.indexOf('image/') === 0) {
|
||||
e.preventDefault();
|
||||
|
||||
var blob = item.getAsFile();
|
||||
if (!blob) continue;
|
||||
|
||||
var ext = (blob.type.split('/')[1] || 'png').toLowerCase();
|
||||
var pastedFile = new File([blob], 'pasted-image-' + Date.now() + '.' + ext, { type: blob.type });
|
||||
|
||||
var input = document.querySelector(currentInputSelector);
|
||||
if (input) {
|
||||
var dt = new DataTransfer();
|
||||
dt.items.add(pastedFile);
|
||||
input.files = dt.files;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
var url = URL.createObjectURL(pastedFile);
|
||||
previewEl.src = url;
|
||||
previewEl.style.display = '';
|
||||
targetEl.textContent = 'Image pasted!';
|
||||
|
||||
if (currentPreviewSelector) {
|
||||
var extPreview = document.querySelector(currentPreviewSelector);
|
||||
if (extPreview) {
|
||||
extPreview.src = url;
|
||||
extPreview.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () { bsModal.hide(); }, 400);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function open(inputSelector, previewSelector) {
|
||||
if (!bsModal && !init()) return;
|
||||
currentInputSelector = inputSelector;
|
||||
currentPreviewSelector = previewSelector || null;
|
||||
bsModal.show();
|
||||
}
|
||||
|
||||
return { open: open };
|
||||
})();
|
||||
Reference in New Issue
Block a user