style(appShell): 优化应用外壳及底部导航样式与结构
- 在 tailwind 配置中添加应用外壳相关的 safelist 类名 - 替换 App.tsx 中应用外壳容器的类名,去除多余的内边距容器 - 在现代和遗留样式文件中新增移动端全屏、桌面居中列的样式规则 - 新增底部导航外层和内层的样式及响应式布局支持 - appShell.ts 中将样式类改为统一的 x8- 前缀类名 - BottomNav 组件使用新的样式类名以匹配样式调整 - Home 页面 ListRow 组件支持可选缩略图展示,增加界面展示丰富度
This commit is contained in:
+3
-5
@@ -22,7 +22,7 @@ import SelectPage from "./pages/SelectPage";
|
||||
import CommunityPage from "./pages/CommunityPage";
|
||||
import { AIDrawerProvider } from "./contexts/AIDrawerContext";
|
||||
import DesktopAIShell from "./components/DesktopAIShell";
|
||||
import { appShellColumnClass, appShellGutterClass } from "./lib/appShell";
|
||||
import { appShellColumnClass, appShellOuterClass } from "./lib/appShell";
|
||||
|
||||
const EQPage = lazy(() => import("./pages/EQPage"));
|
||||
const AIPage = lazy(() => import("./pages/AIPage"));
|
||||
@@ -75,10 +75,8 @@ function App() {
|
||||
<Toaster />
|
||||
<Router hook={useHashLocation}>
|
||||
<AIDrawerProvider>
|
||||
<div
|
||||
className={`min-h-dvh bg-[#0d1117] flex justify-center ${appShellGutterClass}`}
|
||||
>
|
||||
<div className={`min-h-dvh ${appShellColumnClass}`}>
|
||||
<div className={appShellOuterClass}>
|
||||
<div className={appShellColumnClass}>
|
||||
<DesktopAIShell>
|
||||
<AppRouter />
|
||||
</DesktopAIShell>
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import { Link, useLocation } from "wouter";
|
||||
import { useMemo } from "react";
|
||||
import { appShellColumnClass, appShellGutterClass } from "@/lib/appShell";
|
||||
import { bottomNavInnerClass, bottomNavOuterClass } from "@/lib/appShell";
|
||||
|
||||
type BottomNavLocale = NonNullable<(typeof localeZh)["bottomNav"]>;
|
||||
|
||||
@@ -57,10 +57,10 @@ export default function BottomNav() {
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={`fixed inset-x-0 bottom-0 z-50 flex justify-center pointer-events-none ${appShellGutterClass}`}
|
||||
className={bottomNavOuterClass}
|
||||
>
|
||||
<div
|
||||
className={`pointer-events-auto ${appShellColumnClass}`}
|
||||
className={bottomNavInnerClass}
|
||||
style={{
|
||||
background: "rgba(10, 10, 12, 0.96)",
|
||||
backdropFilter: "blur(40px) saturate(200%)",
|
||||
|
||||
@@ -119,6 +119,8 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@@ -176,6 +178,61 @@
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* App shell: mobile full-bleed, desktop centered column (modern + legacy share class names). */
|
||||
.x8-app-shell-outer {
|
||||
min-height: 100dvh;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: #0d1117;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.x8-app-shell-column {
|
||||
min-height: 100dvh;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.x8-bottom-nav-outer {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
justify-content: center;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.x8-bottom-nav-inner {
|
||||
pointer-events: auto;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.x8-app-shell-outer,
|
||||
.x8-bottom-nav-outer {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.x8-app-shell-column,
|
||||
.x8-bottom-nav-inner {
|
||||
max-width: 1180px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.container {
|
||||
padding-left: 1.5rem;
|
||||
|
||||
@@ -6,9 +6,22 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
html,
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
overscroll-behavior-x: none;
|
||||
}
|
||||
#root {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: #000;
|
||||
color: #f2f2f2;
|
||||
@@ -44,6 +57,62 @@ body {
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* App shell: mobile full-bleed, desktop centered column (plain CSS for Chrome 91). */
|
||||
.x8-app-shell-outer {
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: #0d1117;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.x8-app-shell-column {
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.x8-bottom-nav-outer {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
justify-content: center;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.x8-bottom-nav-inner {
|
||||
pointer-events: auto;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.x8-app-shell-outer,
|
||||
.x8-bottom-nav-outer {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.x8-app-shell-column,
|
||||
.x8-bottom-nav-inner {
|
||||
max-width: 1180px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match modern .cyan-slider styling (input[type=range]) for legacy build. */
|
||||
.cyan-slider {
|
||||
-webkit-appearance: none;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/** Centered phone-style shell width (desktop / ultrawide). */
|
||||
export const APP_SHELL_MAX_PX = 1180;
|
||||
|
||||
/** Inner column inside horizontal gutters — use with a flex/grid centering parent. */
|
||||
export const appShellColumnClass =
|
||||
"w-full min-w-0 max-w-[min(1180px,100%)]";
|
||||
|
||||
export const appShellGutterClass = "px-4 sm:px-6";
|
||||
/** Responsive rules live in `.x8-app-shell-*` (index.css + index.legacy.css). */
|
||||
export const appShellOuterClass = "x8-app-shell-outer";
|
||||
export const appShellColumnClass = "x8-app-shell-column";
|
||||
export const bottomNavOuterClass = "x8-bottom-nav-outer";
|
||||
export const bottomNavInnerClass = "x8-bottom-nav-inner";
|
||||
|
||||
@@ -135,7 +135,7 @@ function IOSToggle({ checked, onChange }: { checked: boolean; onChange: (v: bool
|
||||
|
||||
// ── List row ──
|
||||
function ListRow({
|
||||
icon, label, value, onClick, toggle, checked, onToggle,
|
||||
icon, label, value, onClick, toggle, checked, onToggle, thumbnailSrc,
|
||||
}: {
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
@@ -144,6 +144,8 @@ function ListRow({
|
||||
toggle?: boolean;
|
||||
checked?: boolean;
|
||||
onToggle?: (v: boolean) => void;
|
||||
/** Optional small thumbnail shown between value text and chevron. */
|
||||
thumbnailSrc?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="ios-list-row cursor-pointer" onClick={onClick}>
|
||||
@@ -157,7 +159,15 @@ function ListRow({
|
||||
{toggle ? (
|
||||
<IOSToggle checked={!!checked} onChange={onToggle ?? (() => {})} />
|
||||
) : (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
{thumbnailSrc && (
|
||||
<img
|
||||
src={thumbnailSrc}
|
||||
alt=""
|
||||
className="w-16 h-12 rounded-[8px] object-cover flex-shrink-0"
|
||||
style={{ border: "1px solid rgba(255,255,255,0.12)" }}
|
||||
/>
|
||||
)}
|
||||
{value && <span className="ios-row-value">{value}</span>}
|
||||
<ChevronRight size={16} className="ios-chevron" />
|
||||
</div>
|
||||
@@ -873,6 +883,7 @@ export default function Home() {
|
||||
icon={<Gauge size={16} />}
|
||||
label={homeText.vu ?? "VU表"}
|
||||
value={vuLabel}
|
||||
thumbnailSrc={`${import.meta.env.BASE_URL}vu/vu${(ds.vu ?? 0) + 1}.png`}
|
||||
onClick={() => setLocation("/vu")}
|
||||
/>
|
||||
<ListRow
|
||||
|
||||
@@ -29,5 +29,11 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
safelist: [
|
||||
"x8-app-shell-outer",
|
||||
"x8-app-shell-column",
|
||||
"x8-bottom-nav-outer",
|
||||
"x8-bottom-nav-inner",
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user