Add responsive mobile layout and improve viewport handling
Introduced CSS classes for targeted styling and implemented responsive breakpoints for mobile devices. Enhanced TopBar and AdminPanel layouts to adapt to smaller screens with reorganized grid structures and improved touch targets. Updated shell container to use dynamic viewport height (dvh) and added safe area insets for better mobile browser compatibility. Adjusted button sizes, spacing, and element wrapping for improved usability on narrow
This commit is contained in:
@@ -620,7 +620,7 @@ export default function App() {
|
|||||||
<div style={styles.bgMap} />
|
<div style={styles.bgMap} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={styles.shell}>
|
<div className="hp-shell" style={styles.shell}>
|
||||||
<TopBar
|
<TopBar
|
||||||
me={me}
|
me={me}
|
||||||
userMenuOpen={userMenuOpen}
|
userMenuOpen={userMenuOpen}
|
||||||
|
|||||||
@@ -89,24 +89,25 @@ export default function AdminPanel() {
|
|||||||
{users.map((u) => (
|
{users.map((u) => (
|
||||||
<div
|
<div
|
||||||
key={u.id}
|
key={u.id}
|
||||||
|
className="hp-admin-user-row"
|
||||||
style={{
|
style={{
|
||||||
...styles.userRow,
|
...styles.userRow,
|
||||||
gridTemplateColumns: "1fr 1fr 80px 90px 92px",
|
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ color: stylesTokens.textMain, fontWeight: 900 }}>
|
<div className="hp-admin-name" style={{ color: stylesTokens.textMain, fontWeight: 900 }}>
|
||||||
{u.display_name || "—"}
|
{u.display_name || "—"}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: stylesTokens.textDim, fontSize: 13 }}>{u.email}</div>
|
<div className="hp-admin-email" style={{ color: stylesTokens.textDim, fontSize: 13 }}>{u.email}</div>
|
||||||
<div style={{ textAlign: "center", fontWeight: 900, color: stylesTokens.textGold }}>
|
<div className="hp-admin-role" style={{ textAlign: "center", fontWeight: 900, color: stylesTokens.textGold }}>
|
||||||
{u.role}
|
{u.role}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ textAlign: "center", opacity: 0.85, color: stylesTokens.textMain }}>
|
<div className="hp-admin-status" style={{ textAlign: "center", opacity: 0.85, color: stylesTokens.textMain }}>
|
||||||
{u.disabled ? "disabled" : "active"}
|
{u.disabled ? "disabled" : "active"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
className="hp-admin-action"
|
||||||
onClick={() => deleteUser(u)}
|
onClick={() => deleteUser(u)}
|
||||||
style={{
|
style={{
|
||||||
...styles.secondaryBtn,
|
...styles.secondaryBtn,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function TopBar({
|
|||||||
const displayName = me ? ((me.display_name || "").trim() || me.email) : "";
|
const displayName = me ? ((me.display_name || "").trim() || me.email) : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.topBar}>
|
<div className="hp-topbar" style={styles.topBar}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontWeight: 900, color: stylesTokens.textGold }}>Notizbogen</div>
|
<div style={{ fontWeight: 900, color: stylesTokens.textGold }}>Notizbogen</div>
|
||||||
<div style={{ fontSize: 12, opacity: 0.8, color: stylesTokens.textDim }}>
|
<div style={{ fontSize: 12, opacity: 0.8, color: stylesTokens.textDim }}>
|
||||||
@@ -23,9 +23,10 @@ export default function TopBar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "nowrap" }} data-user-menu>
|
<div className="hp-topbar-actions" style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "nowrap" }} data-user-menu>
|
||||||
<div style={{ position: "relative" }}>
|
<div style={{ position: "relative" }}>
|
||||||
<button
|
<button
|
||||||
|
className="hp-topbar-user"
|
||||||
onClick={() => setUserMenuOpen((v) => !v)}
|
onClick={() => setUserMenuOpen((v) => !v)}
|
||||||
style={styles.userBtn}
|
style={styles.userBtn}
|
||||||
title="User Menü"
|
title="User Menü"
|
||||||
@@ -84,7 +85,7 @@ export default function TopBar({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onClick={onOpenNewGame} style={styles.primaryBtn}>
|
<button className="hp-topbar-new" onClick={onOpenNewGame} style={styles.primaryBtn}>
|
||||||
✦ New Game
|
✦ New Game
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -89,6 +89,31 @@ export function useHpGlobalStyles() {
|
|||||||
input:focus, select:focus { border-color: var(--hp-textGold) !important; box-shadow: 0 0 0 3px color-mix(in srgb, var(--hp-textGold) 16%, transparent); }
|
input:focus, select:focus { border-color: var(--hp-textGold) !important; box-shadow: 0 0 0 3px color-mix(in srgb, var(--hp-textGold) 16%, transparent); }
|
||||||
.hp-row { transition: background 140ms ease, transform 140ms ease, box-shadow 140ms ease; }
|
.hp-row { transition: background 140ms ease, transform 140ms ease, box-shadow 140ms ease; }
|
||||||
.hp-row:hover { box-shadow: inset 0 0 0 1px rgba(233,216,166,0.12); }
|
.hp-row:hover { box-shadow: inset 0 0 0 1px rgba(233,216,166,0.12); }
|
||||||
|
.hp-topbar-actions { margin-left: auto; }
|
||||||
|
.hp-admin-user-row { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.5fr) 70px 76px 86px; }
|
||||||
|
.hp-admin-action { min-width: 0; }
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.hp-shell { padding: calc(12px + env(safe-area-inset-top)) 10px calc(28px + env(safe-area-inset-bottom)) !important; }
|
||||||
|
.hp-topbar { align-items: flex-start !important; padding: 12px !important; flex-wrap: wrap !important; }
|
||||||
|
.hp-topbar-actions { width: 100%; margin-left: 0; justify-content: stretch; }
|
||||||
|
.hp-topbar-user, .hp-topbar-new { flex: 1; min-height: 44px; }
|
||||||
|
.hp-topbar-user { justify-content: center; }
|
||||||
|
.hp-admin-user-row { grid-template-columns: minmax(0, 1fr) auto; gap: 5px 8px; padding: 11px !important; }
|
||||||
|
.hp-admin-name { grid-column: 1; grid-row: 1; }
|
||||||
|
.hp-admin-email { grid-column: 1; grid-row: 2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.hp-admin-role { grid-column: 2; grid-row: 1; }
|
||||||
|
.hp-admin-status { grid-column: 2; grid-row: 2; }
|
||||||
|
.hp-admin-action { grid-column: 1 / -1; grid-row: 3; width: 100%; min-height: 42px; }
|
||||||
|
.hp-row { grid-template-columns: minmax(0, 1fr) 42px 62px !important; gap: 7px !important; padding: 12px 11px !important; }
|
||||||
|
.hp-row button { min-height: 40px; }
|
||||||
|
button { min-height: 42px; }
|
||||||
|
input, select { min-height: 44px; box-sizing: border-box; }
|
||||||
|
.hp-topbar + * { margin-top: 12px !important; }
|
||||||
|
}
|
||||||
|
@media (max-width: 360px) {
|
||||||
|
.hp-row { grid-template-columns: minmax(0, 1fr) 38px 56px !important; font-size: 14px; }
|
||||||
|
.hp-topbar { gap: 8px !important; }
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ export const styles = {
|
|||||||
background: "linear-gradient(145deg, rgba(27,25,30,0.98), rgba(11,11,14,0.98))",
|
background: "linear-gradient(145deg, rgba(27,25,30,0.98), rgba(11,11,14,0.98))",
|
||||||
boxShadow: "0 24px 70px rgba(0,0,0,0.78), inset 0 1px 0 rgba(255,255,255,0.07)",
|
boxShadow: "0 24px 70px rgba(0,0,0,0.78), inset 0 1px 0 rgba(255,255,255,0.07)",
|
||||||
padding: 16,
|
padding: 16,
|
||||||
maxHeight: "calc(100vh - 32px)",
|
maxHeight: "calc(100dvh - 32px)",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
},
|
},
|
||||||
modalHeader: {
|
modalHeader: {
|
||||||
|
|||||||
Reference in New Issue
Block a user