feat: add QR share button to profile and fix mobile header layout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SITO 2026-05-01 01:48:13 +02:00
parent 9ee8fd60cd
commit dad3871c65
4 changed files with 117 additions and 46 deletions

View file

@ -60,63 +60,68 @@ pre, code {
display: flex !important; display: flex !important;
flex-direction: row !important; flex-direction: row !important;
flex-wrap: wrap !important; flex-wrap: wrap !important;
width: 100% !important;
max-width: 100% !important;
padding: 4px 2px !important;
gap: 2px !important;
align-items: center !important; align-items: center !important;
}
.header-content {
display: flex !important;
flex-wrap: wrap !important;
width: 100% !important; width: 100% !important;
max-width: 100% !important; padding: 2px 4px !important;
padding: 2px !important; gap: 0 !important;
gap: 4px !important;
} }
body div.top-bar-left { .top-bar-left {
display: contents !important; display: flex !important;
} flex-direction: row !important;
align-items: center !important;
body div.top-bar-left > a.logo-icon { flex: 1 !important;
flex: 0 0 100% !important; flex-wrap: nowrap !important;
} gap: 2px !important;
width: auto !important;
body div.top-bar-left > nav, max-width: none !important;
body div.top-bar-left > nav > ul, padding: 0 !important;
body div.top-bar-right, }
body div.top-bar-right nav,
body div.top-bar-right nav ul { .top-bar-right {
display: contents !important; display: flex !important;
} flex-direction: row !important;
align-items: center !important;
body div.top-bar-left nav ul li a, flex-shrink: 0 !important;
body div.top-bar-right nav ul li a { flex-wrap: nowrap !important;
padding: 5px 5px !important; gap: 2px !important;
font-size: 0.82rem !important; width: auto !important;
min-height: auto !important; max-width: none !important;
border: none !important; padding: 0 !important;
} }
.top-bar-left, .top-bar-mid, .top-bar-right { .top-bar-left nav,
.top-bar-right nav {
display: flex !important; display: flex !important;
flex-direction: column !important;
width: 100% !important;
max-width: 100% !important;
align-items: stretch !important;
gap: 4px !important;
} }
.top-bar-left nav ul, .top-bar-left nav ul,
.top-bar-mid nav ul,
.top-bar-right nav ul { .top-bar-right nav ul {
display: flex !important; display: flex !important;
flex-wrap: wrap !important; flex-direction: row !important;
gap: 4px !important; flex-wrap: nowrap !important;
gap: 2px !important;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;
list-style: none !important;
}
a.logo-icon img.logo-icon {
width: 28px !important;
height: 28px !important;
display: block !important;
}
.header nav ul li a,
.top-bar-left nav ul li a,
.top-bar-right nav ul li a {
padding: 4px 6px !important;
font-size: 0.75rem !important;
min-height: auto !important;
border: none !important;
white-space: nowrap !important;
display: inline-block !important;
line-height: 1.2 !important;
} }
.oasis-nav-header { font-size: 0.85rem !important; } .oasis-nav-header { font-size: 0.85rem !important; }

View file

@ -4315,3 +4315,43 @@ button, input[type="submit"], input[type="button"], .filter-btn {
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px; gap: 20px;
} }
/* ---- QR Compartir ID (details/summary en perfil) ---- */
.qr-share-details {
margin: 8px 0;
width: 100%;
}
.qr-share-btn {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
padding: 8px 16px;
border-radius: 8px;
font-size: 0.9rem;
font-weight: bold;
list-style: none;
user-select: none;
}
.qr-share-btn::-webkit-details-marker { display: none; }
.qr-share-panel {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 16px 8px;
margin-top: 8px;
border-radius: 12px;
}
.qr-share-id {
font-family: monospace;
font-size: 0.7rem;
word-break: break-all;
text-align: center;
max-width: 280px;
opacity: 0.7;
}

View file

@ -329,3 +329,19 @@ a.user-link:focus {
.qr-code svg path { .qr-code svg path {
fill: #FFD700; fill: #FFD700;
} }
.qr-share-btn {
background-color: #2a2a00;
color: #FFD700;
border: 1px solid #555;
}
.qr-share-btn:hover {
background-color: #3a3a00;
border-color: #FFD700;
}
.qr-share-panel {
background-color: #1A1A1A;
border: 1px solid #333;
}

View file

@ -2,6 +2,7 @@
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
const QRCode = require('../server/node_modules/qrcode');
const envPaths = require("../server/node_modules/env-paths"); const envPaths = require("../server/node_modules/env-paths");
const debug = require("../server/node_modules/debug")("oasis"); const debug = require("../server/node_modules/debug")("oasis");
@ -1514,7 +1515,7 @@ exports.editProfileView = ({ name, description }) =>
) )
); );
exports.authorView = ({ exports.authorView = async ({
avatarUrl, avatarUrl,
description, description,
feedId, feedId,
@ -1562,6 +1563,8 @@ exports.authorView = ({
const { lastActivityBadge } = require('./inhabitants_view'); const { lastActivityBadge } = require('./inhabitants_view');
const qrSvg = feedId ? await QRCode.toString(feedId, { type: 'svg' }) : '';
const prefix = section( const prefix = section(
{ class: "message" }, { class: "message" },
div( div(
@ -1572,6 +1575,13 @@ exports.authorView = ({
), ),
pre({ class: "md-mention", innerHTML: sanitizeHtml(markdownMention) }), pre({ class: "md-mention", innerHTML: sanitizeHtml(markdownMention) }),
p(a({ class: "user-link", href: `/author/${encodeURIComponent(feedId)}` }, feedId)), p(a({ class: "user-link", href: `/author/${encodeURIComponent(feedId)}` }, feedId)),
qrSvg ? details({ class: 'qr-share-details' },
summary({ class: 'qr-share-btn' }, '⬡ Compartir ID'),
div({ class: 'qr-share-panel' },
div({ class: 'qr-code qr-code-profile', innerHTML: qrSvg }),
p({ class: 'qr-share-id' }, feedId)
)
) : null,
div({ class: "profile-metrics" }, div({ class: "profile-metrics" },
p(`${i18n.bankingUserEngagementScore}: `, strong(karmaScore !== undefined ? karmaScore : 0)), p(`${i18n.bankingUserEngagementScore}: `, strong(karmaScore !== undefined ? karmaScore : 0)),
...lastActivityBadge({ lastActivityBucket: bucket }, true), ...lastActivityBadge({ lastActivityBucket: bucket }, true),