Bilder Aspect + name centered + Preview
This commit is contained in:
14
backend/package-lock.json
generated
14
backend/package-lock.json
generated
@@ -457,13 +457,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz",
|
||||
"integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==",
|
||||
"version": "26.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.5.0.tgz",
|
||||
"integrity": "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~8.3.0"
|
||||
"undici-types": "~8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
@@ -2708,9 +2708,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
|
||||
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz",
|
||||
"integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
.scrap-item:hover { transform: scale(1.04) rotate(0deg) !important; z-index: 2; }
|
||||
|
||||
.scrap-item.polaroid { padding: 10px 10px 30px; width: 220px; }
|
||||
.scrap-item.polaroid img { width: 100%; height: 190px; object-fit: cover; display: block; }
|
||||
.scrap-item.polaroid img { display: block; max-width: 100%; max-height: 260px; width: auto; height: auto; margin: 0 auto; }
|
||||
|
||||
.scrap-item.text-note { width: 220px; min-height: 160px; padding: 1.2em; background: #fef7d6; font-family: Georgia, serif; }
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
box-shadow: var(--shadow);
|
||||
overflow: hidden;
|
||||
border: 2px dashed var(--mustard);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.cover-stickers { position: absolute; inset: 0; }
|
||||
.cover-sticker {
|
||||
@@ -75,8 +78,6 @@
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
text-align: center;
|
||||
top: 42%;
|
||||
transform: translateY(-50%);
|
||||
padding: 0.6em 1.2em;
|
||||
}
|
||||
.cover-title {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
background: var(--paper-2); border-radius: 10px; box-shadow: var(--shadow);
|
||||
padding: 1em; width: 220px; position: relative;
|
||||
}
|
||||
.block-item img { width: 100%; height: 140px; object-fit: cover; border-radius: 6px; }
|
||||
.block-item img { display: block; max-width: 100%; max-height: 220px; width: auto; height: auto; margin: 0 auto; border-radius: 6px; }
|
||||
.block-item audio { width: 100%; margin-top: 0.4em; }
|
||||
.block-item textarea { min-height: 4em; font-size: 0.9rem; }
|
||||
.block-item .block-caption { font-size: 0.82rem; margin-top: 0.5em; }
|
||||
@@ -36,3 +36,23 @@
|
||||
position: absolute; top: -8px; left: 10px; font-size: 0.7rem; font-weight: 700;
|
||||
background: var(--mustard); color: #533; padding: 0.1em 0.6em; border-radius: 999px;
|
||||
}
|
||||
|
||||
.preview-modal-backdrop {
|
||||
position: fixed; inset: 0; background: rgba(75,59,107,0.45);
|
||||
display: flex; align-items: flex-start; justify-content: center;
|
||||
z-index: 100; padding: 2em 1em; overflow-y: auto;
|
||||
}
|
||||
.preview-modal {
|
||||
background: var(--paper);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 12px 40px rgba(0,0,0,0.3);
|
||||
width: 100%; max-width: 780px;
|
||||
max-height: calc(100vh - 4em);
|
||||
display: flex; flex-direction: column; overflow: hidden;
|
||||
}
|
||||
.preview-modal-head {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 1em; padding: 1em 1.4em; background: var(--paper-2);
|
||||
border-bottom: 2px solid var(--line); flex-wrap: wrap;
|
||||
}
|
||||
.preview-modal-body { overflow-y: auto; padding: 0.5em; }
|
||||
|
||||
@@ -278,4 +278,80 @@ async function moveBlock(id, dir) {
|
||||
if (res.ok) { currentFriend = data.friend; renderBlocks(); }
|
||||
}
|
||||
|
||||
// --- Vorschau: rendert die Seite genauso wie später im Freundesbuch-Viewer ---
|
||||
function randomRotation(seed) {
|
||||
const angles = [-6, -4, -2, 2, 4, 6, -3, 3, 5, -5];
|
||||
return angles[seed % angles.length];
|
||||
}
|
||||
|
||||
function renderPreview() {
|
||||
const f = currentFriend;
|
||||
const container = document.getElementById('previewContent');
|
||||
|
||||
const profileHtml = f.profileImage
|
||||
? `<img class="page-profile-pic" src="${uploadUrl(f.profileImage)}" />`
|
||||
: `<div class="page-profile-pic placeholder">${(f.name || '?')[0].toUpperCase()}</div>`;
|
||||
|
||||
const sbEntries = STECKBRIEF_FIELDS
|
||||
.map(([key, label]) => [label, (f.steckbrief || {})[key]])
|
||||
.filter(([, v]) => v && String(v).trim());
|
||||
const sbHtml = sbEntries.length
|
||||
? `<div class="sb-grid">${sbEntries.map(([label, v]) => `
|
||||
<div class="sb-row"><span class="sb-key">${escapeHtml(label)}</span><span class="sb-val">${escapeHtml(v)}</span></div>
|
||||
`).join('')}</div>`
|
||||
: `<p class="muted">Noch nichts eingetragen.</p>`;
|
||||
|
||||
const blocks = [...(f.blocks || [])].sort((a, b) => a.order - b.order);
|
||||
const blocksHtml = blocks.length
|
||||
? blocks.map((b, i) => {
|
||||
const rot = randomRotation(i + f.id.length);
|
||||
if (b.type === 'image') {
|
||||
return `<div class="scrap-item polaroid" style="transform: rotate(${rot}deg);">
|
||||
<img src="${uploadUrl(b.filename)}" />
|
||||
${b.caption ? `<div class="scrap-caption">${escapeHtml(b.caption)}</div>` : ''}
|
||||
</div>`;
|
||||
}
|
||||
if (b.type === 'audio') {
|
||||
return `<div class="scrap-item audio-note" style="transform: rotate(${rot * 0.5}deg);">
|
||||
${b.coverFilename ? `<img class="audio-cover" src="${uploadUrl(b.coverFilename)}" />` : ''}
|
||||
<div>🎙️${b.caption ? ' ' + escapeHtml(b.caption) : ''}</div>
|
||||
<audio controls src="${uploadUrl(b.filename)}"></audio>
|
||||
</div>`;
|
||||
}
|
||||
return `<div class="scrap-item text-note" style="transform: rotate(${rot * 0.5}deg);">
|
||||
<p>${escapeHtml(b.content).replace(/\n/g, '<br/>')}</p>
|
||||
${b.caption ? `<div class="scrap-caption">${escapeHtml(b.caption)}</div>` : ''}
|
||||
</div>`;
|
||||
}).join('')
|
||||
: '<p class="muted">Noch keine Erinnerungen hinzugefügt.</p>';
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="friend-page">
|
||||
<div class="page-head">
|
||||
<div class="tape"></div>
|
||||
${profileHtml}
|
||||
<h1>${escapeHtml(f.name)}</h1>
|
||||
</div>
|
||||
<div class="steckbrief-card">
|
||||
<h2>Steckbrief</h2>
|
||||
${sbHtml}
|
||||
</div>
|
||||
<div class="scrap-grid">
|
||||
${blocksHtml}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
document.getElementById('previewBtn').addEventListener('click', () => {
|
||||
renderPreview();
|
||||
document.getElementById('previewModal').style.display = 'flex';
|
||||
});
|
||||
document.getElementById('previewCloseBtn').addEventListener('click', () => {
|
||||
document.getElementById('previewModal').style.display = 'none';
|
||||
});
|
||||
document.getElementById('previewModal').addEventListener('click', (e) => {
|
||||
if (e.target.id === 'previewModal') document.getElementById('previewModal').style.display = 'none';
|
||||
});
|
||||
|
||||
init();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<title>Freundesbuch</title>
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
<link rel="stylesheet" href="/friend/friend.css" />
|
||||
<link rel="stylesheet" href="/book/book.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -26,7 +27,10 @@
|
||||
<div id="editorRoot" style="display:none;">
|
||||
<div class="top-bar card" style="border-radius:0;">
|
||||
<h1 style="margin:0;" id="pageTitle">📖 Freund</h1>
|
||||
<div id="adminBackWrap"><a class="btn secondary" href="/admin">← Zur Übersicht</a></div>
|
||||
<div style="display:flex; gap:0.6em; flex-wrap:wrap;">
|
||||
<button type="button" class="secondary" id="previewBtn">👀 Vorschau</button>
|
||||
<div id="adminBackWrap"><a class="btn secondary" href="/admin">← Zur Übersicht</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
@@ -82,6 +86,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vorschau-Modal: zeigt die Seite so, wie sie später im Freundesbuch aussieht -->
|
||||
<div id="previewModal" class="preview-modal-backdrop" style="display:none;">
|
||||
<div class="preview-modal">
|
||||
<div class="preview-modal-head">
|
||||
<h2 style="margin:0;">👀 So sieht deine Seite im Freundesbuch aus</h2>
|
||||
<button type="button" class="secondary" id="previewCloseBtn">Schließen</button>
|
||||
</div>
|
||||
<div class="preview-modal-body">
|
||||
<div id="previewContent" class="book-root" style="padding:1.5em 0.5em;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/friend/friend.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -212,7 +212,7 @@ async function buildFullHtml(friends, bookTitle) {
|
||||
.blocks { display: flex; flex-wrap: wrap; gap: 6mm; }
|
||||
.pdf-block { background: #fff; padding: 4mm; box-shadow: 0 3px 10px rgba(0,0,0,0.15); }
|
||||
.polaroid { padding: 4mm 4mm 10mm; width: 58mm; }
|
||||
.polaroid img { width: 100%; height: 48mm; object-fit: cover; display: block; }
|
||||
.polaroid img { display: block; max-width: 100%; max-height: 55mm; width: auto; height: auto; margin: 0 auto; }
|
||||
.text-block { width: 58mm; min-height: 40mm; background: #fef7d6; font-family: Georgia, serif; font-size: 12px; }
|
||||
.audio-block { width: 58mm; min-height: 30mm; background: #e8f3ec; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; font-size: 13px; padding: 3mm; }
|
||||
.audio-cover { width: 100%; height: 30mm; object-fit: cover; border-radius: 4px; margin-bottom: 2mm; }
|
||||
|
||||
Reference in New Issue
Block a user