mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-07-28 04:22:51 +02:00
style(web): normalize heading, spacing, and radius scales across pages
- Page <h1>s: text-3xl font-bold everywhere (packet-detail, packet-group-detail, channels were text-2xl; channels icon bumped to match). - Page-header rows: mb-6 on all pages (list pages used mb-4). - Empty states: text-center py-8 opacity-70 (members used py-12, channels py-10 opacity-60). - QR backings and adopted-node rows: rounded-box like other panel-level surfaces; QR padding unified at p-2. - Home hero welcome text: max-w-[90%] sm:max-w-[70%] so narrow screens don't wrap into a skinny column (desktop unchanged). - Document the styling conventions in the components.js header so future pages don't drift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,18 @@
|
||||
* MeshCore Hub SPA - Shared UI Components
|
||||
*
|
||||
* Reusable rendering functions using lit-html.
|
||||
*
|
||||
* Styling conventions:
|
||||
* - Page <h1>: `text-3xl font-bold`; header row wrapper: `mb-6`.
|
||||
* - Content/detail cards: `card bg-base-100 shadow-xl`; stat cards and
|
||||
* table wrappers: `shadow-sm`; mobile list cards: `shadow-sm`.
|
||||
* - Muted text: `opacity-70` (primary), `opacity-60` (secondary),
|
||||
* `opacity-50` (timestamps/tertiary) — not `text-base-content/N`.
|
||||
* - Empty states: `text-center py-8 opacity-70`.
|
||||
* - Panel-level surfaces: `rounded-box`; small inline chips: `rounded`.
|
||||
* - Buttons: table-row icon actions `btn btn-xs btn-ghost`; card-level
|
||||
* labeled actions `btn btn-xs btn-outline` (+ `btn-error` on delete);
|
||||
* modal submits full-size `btn btn-primary`, inline/header actions `btn-sm`.
|
||||
*/
|
||||
|
||||
import { html, nothing } from 'lit-html';
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function render(container, params, router) {
|
||||
const displayContent = error ? lastContent : content;
|
||||
const displayTotal = error ? lastTotal : total;
|
||||
litRender(html`
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('entities.advertisements')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
|
||||
@@ -142,7 +142,7 @@ export async function render(container, params, router) {
|
||||
: nothing;
|
||||
|
||||
const emptyMessage = channelsList.length === 0
|
||||
? html`<div class="text-center py-10 opacity-60">
|
||||
? html`<div class="text-center py-8 opacity-70">
|
||||
${t('common.no_entity_found', { entity: t('entities.channels').toLowerCase() })}
|
||||
</div>`
|
||||
: nothing;
|
||||
@@ -194,9 +194,9 @@ export async function render(container, params, router) {
|
||||
}
|
||||
|
||||
litRender(html`
|
||||
<div class="mb-4">
|
||||
<h1 class="text-2xl font-bold flex items-center gap-2">
|
||||
${iconChannel('h-7 w-7')}
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold flex items-center gap-2">
|
||||
${iconChannel('h-8 w-8')}
|
||||
${t('channels.title')}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -58,8 +58,8 @@ function renderHeroSection({ networkName, logoUrl, logoInvertLight, networkCity,
|
||||
: nothing;
|
||||
|
||||
const welcomeText = networkWelcomeText
|
||||
? html`<p class="py-4 max-w-[70%]">${networkWelcomeText}</p>`
|
||||
: html`<p class="py-4 max-w-[70%]">
|
||||
? html`<p class="py-4 max-w-[90%] sm:max-w-[70%]">${networkWelcomeText}</p>`
|
||||
: html`<p class="py-4 max-w-[90%] sm:max-w-[70%]">
|
||||
${t('home.welcome_default', { network_name: networkName })}
|
||||
</p>`;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ export async function render(container, params, router) {
|
||||
<h1 class="text-3xl font-bold">${t('entities.members')}</h1>
|
||||
</div>
|
||||
|
||||
<div class="text-center py-12 opacity-70">
|
||||
<div class="text-center py-8 opacity-70">
|
||||
<p class="text-lg">${t('members_page.empty_state')}</p>
|
||||
<p class="text-sm mt-2">${t('members_page.empty_description')}</p>
|
||||
</div>`, container);
|
||||
|
||||
@@ -218,7 +218,7 @@ export async function render(container, params, router) {
|
||||
const displayContent = error ? lastContent : content;
|
||||
const displayTotal = error ? lastTotal : total;
|
||||
litRender(html`
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('entities.messages')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
|
||||
@@ -116,13 +116,13 @@ export async function render(container, params, router) {
|
||||
<div class="relative rounded-box overflow-hidden mb-6 shadow-xl" style="height: 180px;">
|
||||
<div id="header-map" class="absolute inset-0 z-0"></div>
|
||||
<div class="relative z-20 h-full p-3 flex items-center justify-end">
|
||||
<div id="qr-code" class="bg-white p-2 rounded shadow-lg"></div>
|
||||
<div id="qr-code" class="bg-white p-2 rounded-box shadow-lg"></div>
|
||||
</div>
|
||||
</div>`
|
||||
: html`
|
||||
<div class="card bg-base-100 shadow-xl mb-6">
|
||||
<div class="card-body flex-row items-center gap-4">
|
||||
<div id="qr-code" class="bg-white p-1 rounded"></div>
|
||||
<div id="qr-code" class="bg-white p-2 rounded-box"></div>
|
||||
<p class="text-sm opacity-70">${t('nodes.scan_to_add')}</p>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function render(container, params, router) {
|
||||
const displayContent = error ? lastContent : content;
|
||||
const displayTotal = error ? lastTotal : total;
|
||||
litRender(html`
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('entities.nodes')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
|
||||
@@ -29,8 +29,8 @@ export async function render(container, params, router) {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="text-2xl font-bold">${t('packets.detail_title')}</h1>
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('packets.detail_title')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
${content}`, container);
|
||||
|
||||
@@ -243,8 +243,8 @@ export async function render(container, params, router) {
|
||||
<li>${leaf || t('packets.detail_title')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="text-2xl font-bold">${t('packets.detail_title')}</h1>
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('packets.detail_title')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
${content}`, container);
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function render(container, params, router) {
|
||||
const displayContent = error ? lastContent : content;
|
||||
const displayTotal = error ? lastTotal : total;
|
||||
litRender(html`
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">${t('entities.packets')}</h1>
|
||||
${tzBadge}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ function renderAdoptedNode(node) {
|
||||
const relTime = node.last_seen ? formatRelativeTime(node.last_seen) : '-';
|
||||
const fullTime = node.last_seen ? formatDateTime(node.last_seen) : '-';
|
||||
|
||||
return html`<a href="/nodes/${node.public_key}" class="flex items-center justify-between gap-3 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors">
|
||||
return html`<a href="/nodes/${node.public_key}" class="flex items-center justify-between gap-3 p-3 bg-base-200 rounded-box hover:bg-base-300 transition-colors">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-medium text-sm truncate">${displayName}</div>
|
||||
<div class="font-mono text-xs opacity-60 truncate">${node.public_key}</div>
|
||||
|
||||
Reference in New Issue
Block a user