From 903d175f2d47a33d37325ecaba57d8bd4880de12 Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 31 Aug 2026 11:45:02 +0200 Subject: [PATCH] Polish responsive design across all screen sizes and refine card blocks - Enhance SurfaceCard with refined borders, layered shadows, and polished primary-tinted header with an icon container - Update homepage blocks (hero, features, stats, login, news, photos) for proper mobile/tablet/desktop responsiveness and tighter mobile spacing - Improve content-card, stat-block, card-grid and card styling with subtle depth (layered shadow + inner hairline) and smoother hover states - Refine site header, footer, top header and site layout spacing for small screens while keeping a consistent professional look on large screens - Add min-tap-height targets and responsive typography on mobile --- src/app/(site)/layout.tsx | 2 +- src/app/(site)/page.tsx | 86 ++++++++++----------- src/app/globals.css | 128 ++++++++++++++++++++++++-------- src/components/site-footer.tsx | 6 +- src/components/site-header.tsx | 28 ++++--- src/components/surface-card.tsx | 39 ++++++---- src/components/top-header.tsx | 12 +-- 7 files changed, 194 insertions(+), 107 deletions(-) diff --git a/src/app/(site)/layout.tsx b/src/app/(site)/layout.tsx index c151250f..3bed6031 100644 --- a/src/app/(site)/layout.tsx +++ b/src/app/(site)/layout.tsx @@ -28,7 +28,7 @@ export default async function SiteLayout({ ) : null}
-
+
{children}
diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx index cef6a1ac..898cdc5b 100644 --- a/src/app/(site)/page.tsx +++ b/src/app/(site)/page.tsx @@ -118,11 +118,11 @@ export default async function Home() { ]; return ( -
+
{/* ── Top Bar ── */}
-
+
{logo ? ( )} {hotelName}

{tp("welcomeBody")}

-
+
-
+
{features.map((f) => (
- +

{f.desc} @@ -325,7 +331,7 @@ export default async function Home() { {/* ── Stats + Login ── */} -

+
{[ { value: users, @@ -350,13 +356,13 @@ export default async function Home() { ].map((s) => ( -
+
@@ -373,7 +379,7 @@ export default async function Home() { -
+
{recentUsers.map((u) => (
{u.username} @@ -431,14 +433,14 @@ export default async function Home() { actionLabel={tp("allNews")} > {articles.length > 0 ? ( -
+
{articles.slice(0, 4).map((a) => (
→
-

+

{a.title}

{formatDate(a.createdAt, "date", "")} @@ -500,7 +502,7 @@ export default async function Home() { diff --git a/src/app/globals.css b/src/app/globals.css index 39463b0d..a823d23c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -243,6 +243,7 @@ summary, color 0.15s ease-in-out, background-color 0.15s ease-in-out; border-radius: 0.5rem; + min-height: 44px; } .nav-item:hover { color: var(--color-primary-readable, var(--color-primary)); @@ -262,6 +263,9 @@ summary, transition: background-color 0.1s ease-in-out, color 0.1s ease-in-out; + min-height: 44px; + display: flex; + align-items: center; } .dropdown-item:hover { background-color: color-mix(in srgb, var(--color-primary) 12%, transparent); @@ -275,7 +279,9 @@ summary, background-color: var(--color-dropdown); border: 1px solid color-mix(in srgb, var(--color-text-muted) 14%, transparent); - box-shadow: 0 8px 32px color-mix(in srgb, rgb(0, 0, 0) 20%, transparent); + box-shadow: + 0 8px 32px color-mix(in srgb, rgb(0, 0, 0) 20%, transparent), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 8%, transparent); } } @@ -495,27 +501,36 @@ a:hover { ); border: 1px solid color-mix(in srgb, var(--color-primary) 20%, transparent); border-radius: var(--radius-lg); - padding: 2rem 2.25rem; + padding: 1.5rem 1.75rem; box-shadow: var(--shadow-card); margin-bottom: 1.5rem; } .card { background: var(--color-surface); color: var(--color-surface-text-readable, var(--color-text-readable)); - border: 1px solid color-mix(in srgb, var(--color-text-muted) 12%, transparent); + border: 1px solid color-mix(in srgb, var(--color-text-muted) 10%, transparent); border-radius: var(--card-border-radius); - box-shadow: var(--shadow-card); + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.04), + 0 2px 8px rgba(0, 0, 0, 0.03), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent); padding: 1.1rem 1.25rem; transition: transform 0.2s ease, box-shadow 0.2s ease; } .card:hover { - box-shadow: var(--shadow-card-hover); + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.06), + 0 8px 24px rgba(0, 0, 0, 0.04), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 8%, transparent); } .card.hover:hover { transform: translateY(-3px); - box-shadow: var(--shadow-card-hover); + box-shadow: + 0 6px 16px rgba(0, 0, 0, 0.08), + 0 12px 32px rgba(0, 0, 0, 0.06), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 10%, transparent); } .article-img { width: 100%; @@ -799,26 +814,34 @@ tbody tr:hover { border: 1px solid color-mix( in srgb, - var(--color-text-muted-readable, var(--color-text-muted)) 12%, + var(--color-text-muted-readable, var(--color-text-muted)) 10%, transparent ); border-radius: var(--radius-lg); - box-shadow: var(--shadow-card); + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.04), + 0 2px 8px rgba(0, 0, 0, 0.03), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent); overflow: hidden; - transition: box-shadow 0.2s ease; + transition: + box-shadow 0.2s ease, + transform 0.2s ease; } .content-card:hover { - box-shadow: var(--shadow-card-hover); + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.06), + 0 8px 24px rgba(0, 0, 0, 0.04), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 8%, transparent); } .content-card-head { display: flex; align-items: center; gap: 0.75rem; - padding: 0.9rem 1.1rem; + padding: 0.85rem 1.1rem; background: linear-gradient( 135deg, - color-mix(in srgb, var(--color-primary) 10%, var(--color-surface)), - color-mix(in srgb, var(--color-primary) 5%, var(--color-surface)) + color-mix(in srgb, var(--color-primary) 8%, var(--color-surface)), + color-mix(in srgb, var(--color-primary) 4%, var(--color-surface)) ); border-bottom: 1px solid color-mix( @@ -829,19 +852,19 @@ tbody tr:hover { } .content-card-icon { flex: none; - width: 44px; - height: 44px; - border-radius: 999px; + width: 36px; + height: 36px; + border-radius: 10px; display: grid; place-items: center; - font-size: 1.25rem; + font-size: 1.1rem; background: linear-gradient( 135deg, - color-mix(in srgb, var(--color-primary) 22%, var(--color-surface)), - color-mix(in srgb, var(--color-primary) 12%, var(--color-surface)) + color-mix(in srgb, var(--color-primary) 18%, var(--color-surface)), + color-mix(in srgb, var(--color-primary) 10%, var(--color-surface)) ); box-shadow: inset 0 0 0 1px - color-mix(in srgb, var(--color-primary) 30%, transparent); + color-mix(in srgb, var(--color-primary) 16%, transparent); } .content-card-head-text { min-width: 0; @@ -850,7 +873,7 @@ tbody tr:hover { .content-card-title { margin: 0; font-weight: 700; - font-size: 1rem; + font-size: 0.92rem; line-height: 1.3; color: var( --color-surface-text-readable, @@ -859,7 +882,7 @@ tbody tr:hover { } .content-card-subtitle { margin: 0.15rem 0 0; - font-size: 0.78rem; + font-size: 0.75rem; color: var(--color-text-muted-readable, var(--color-text-muted)); } .content-card-action { @@ -872,28 +895,33 @@ tbody tr:hover { /* Responsive card grids (atom: 1 / sm2 / md3 / lg4). */ .card-grid { display: grid; - gap: 1rem; + gap: 0.75rem; grid-template-columns: 1fr; } @media (min-width: 40rem) { .card-grid.sm-2 { grid-template-columns: repeat(2, 1fr); + gap: 1rem; } } @media (min-width: 48rem) { .card-grid.md-2 { grid-template-columns: repeat(2, 1fr); + gap: 1rem; } .card-grid.md-3 { grid-template-columns: repeat(3, 1fr); + gap: 1rem; } } @media (min-width: 64rem) { .card-grid.lg-3 { grid-template-columns: repeat(3, 1fr); + gap: 1.125rem; } .card-grid.lg-4 { grid-template-columns: repeat(4, 1fr); + gap: 1.125rem; } } @@ -901,29 +929,41 @@ tbody tr:hover { .stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); - gap: 0.85rem; + gap: 0.75rem; } .stat-block { - background: var(--color-background); + background: var(--color-surface); border: 1px solid color-mix( in srgb, - var(--color-text-muted-readable, var(--color-text-muted)) 12%, + var(--color-text-muted-readable, var(--color-text-muted)) 10%, transparent ); - border-radius: 12px; + border-radius: var(--radius-sm); padding: 0.85rem 1rem; text-align: center; + transition: + box-shadow 0.2s ease, + transform 0.2s ease; + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.03), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 5%, transparent); +} +.stat-block:hover { + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.06), + 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 8%, transparent); + transform: translateY(-1px); } .stat-block-value { - font-size: 1.6rem; + font-size: 1.5rem; font-weight: 800; line-height: 1.1; color: var(--color-primary-readable, var(--color-primary)); } .stat-block-label { margin-top: 0.2rem; - font-size: 0.78rem; + font-size: 0.75rem; color: var(--color-text-muted-readable, var(--color-text-muted)); } @@ -1269,11 +1309,16 @@ tbody tr:hover { h2 { font-size: clamp(1.1rem, 4vw, var(--size-heading-h2, 22px)); } + h3 { + font-size: clamp(0.95rem, 3.5vw, var(--size-heading-h3, 18px)); + } .hero { padding: 1.25rem 1rem; + border-radius: var(--radius-md); } .card { padding: 0.85rem 1rem; + border-radius: var(--radius-md); } .admin-card { padding: 0.85rem; @@ -1290,17 +1335,32 @@ tbody tr:hover { } .stat-grid { grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + gap: 0.6rem; + } + .stat-block { + padding: 0.65rem 0.5rem; + border-radius: var(--radius-sm); + } + .stat-block-value { + font-size: 1.25rem; } .btn { font-size: 13px; padding: 0.4rem 0.85rem; + min-height: 44px; } .content-card-head { - padding: 0.7rem 0.85rem; + padding: 0.65rem 0.85rem; } .content-card-body { padding: 0.85rem; } + .content-card-icon { + width: 32px; + height: 32px; + border-radius: 8px; + font-size: 0.95rem; + } .nav-item { white-space: normal; text-wrap: balance; @@ -1312,6 +1372,13 @@ tbody tr:hover { .dropdown-item { font-size: 13px; padding: 0.6rem 0.85rem; + min-height: 44px; + } + .content-card-title { + font-size: 0.85rem; + } + .content-card-subtitle { + font-size: 0.7rem; } } @@ -1321,6 +1388,7 @@ tbody tr:hover { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; + border-radius: var(--radius-sm); } } diff --git a/src/components/site-footer.tsx b/src/components/site-footer.tsx index 0364e3f5..b29d622b 100644 --- a/src/components/site-footer.tsx +++ b/src/components/site-footer.tsx @@ -9,13 +9,15 @@ export async function SiteFooter() { return (

-
+
{t("copyright", { year, hotel: hotelName })}
diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index 4fcfe59b..00edbb0f 100644 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -36,7 +36,7 @@ export async function SiteHeader() { return (
{/* Background image */}
{/* Content */} -
+
{logo ? ( {hotelName} ) : ( @@ -95,7 +99,7 @@ export async function SiteHeader() { className="font-black tracking-tight leading-none text-white" style={{ fontFamily: "var(--font-nunito)", - fontSize: "clamp(2.8rem, 8vw, 5.5rem)", + fontSize: "clamp(2rem, 7vw, 5.5rem)", textShadow: "0 2px 20px rgba(0,0,0,0.4), 0 8px 40px rgba(0,0,0,0.2)", letterSpacing: "0.04em", @@ -104,7 +108,7 @@ export async function SiteHeader() { {hotelName}

- + - + {t("online", { count: online, hotel: hotelName })} diff --git a/src/components/surface-card.tsx b/src/components/surface-card.tsx index 19c2722f..5703f84e 100644 --- a/src/components/surface-card.tsx +++ b/src/components/surface-card.tsx @@ -3,11 +3,11 @@ import type { CSSProperties, ReactNode } from "react"; import Link from "@/components/link"; const CARD_BORDER = - "color-mix(in srgb, var(--color-text-muted) 12%, transparent)"; + "color-mix(in srgb, var(--color-text-muted) 10%, transparent)"; const CARD_DIVIDER = "color-mix(in srgb, var(--color-text-muted) 8%, transparent)"; const CARD_HEADER_BG = - "color-mix(in srgb, var(--color-primary) 10%, var(--color-surface))"; + "linear-gradient(135deg, color-mix(in srgb, var(--color-primary) 8%, var(--color-surface)), color-mix(in srgb, var(--color-primary) 4%, var(--color-surface)))"; export interface SurfaceCardProps { children: ReactNode; @@ -45,28 +45,39 @@ export function SurfaceCard({ return (

{hasHeader && (
{icon && ( - +
+ +
)} {title && (

{actionLabel} diff --git a/src/components/top-header.tsx b/src/components/top-header.tsx index 240014af..e643a0c6 100644 --- a/src/components/top-header.tsx +++ b/src/components/top-header.tsx @@ -161,16 +161,16 @@ export async function TopHeader({ session }: { session: Session | null }) { return (
-
+
{t("online", { count: online, hotel: hotelName })} @@ -179,7 +179,7 @@ export async function TopHeader({ session }: { session: Session | null }) {
-
+