用 Tailwind CSS 重写 Timestamp 页面的 MUI 基础排版组件
This commit is contained in:
+31
-45
@@ -1,9 +1,7 @@
|
|||||||
import { Box, Container, MenuItem, Select, Stack, TextField } from '@mui/material';
|
|
||||||
import { Clock } from 'lucide-react';
|
import { Clock } from 'lucide-react';
|
||||||
import Button from '@/components/Button';
|
|
||||||
import PageHeader from '@/components/PageHeader';
|
import PageHeader from '@/components/PageHeader';
|
||||||
import SwitchButtonGroup from '@/components/SwitchButtonGroup';
|
import SwitchButtonGroup from '@/components/SwitchButtonGroup';
|
||||||
import { timestampPageStyles, ZONES } from '@/config/pageTheme';
|
import { ZONES } from '@/config/pageTheme';
|
||||||
import LiveClock from './LiveClock';
|
import LiveClock from './LiveClock';
|
||||||
import ResultView from './ResultView';
|
import ResultView from './ResultView';
|
||||||
import { useTimestampConverter } from './useTimestampConverter';
|
import { useTimestampConverter } from './useTimestampConverter';
|
||||||
@@ -28,8 +26,8 @@ export default function Index() {
|
|||||||
} = useTimestampConverter();
|
} = useTimestampConverter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<div className="min-h-screen">
|
||||||
<Container maxWidth="lg" sx={{ p: 2 }}>
|
<div className="max-w-7xl mx-auto p-4">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={t('timestamp:pageTitle')}
|
title={t('timestamp:pageTitle')}
|
||||||
@@ -41,9 +39,9 @@ export default function Index() {
|
|||||||
<LiveClock unit={unit} onUseNow={handleUseNow} />
|
<LiveClock unit={unit} onUseNow={handleUseNow} />
|
||||||
|
|
||||||
{/* 桌面端 md+ 左右分栏;移动端单栏堆叠 */}
|
{/* 桌面端 md+ 左右分栏;移动端单栏堆叠 */}
|
||||||
<Box sx={timestampPageStyles.LAYOUT_GRID}>
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 items-stretch">
|
||||||
{/* 左栏:转换工作台 */}
|
{/* 左栏:转换工作台 */}
|
||||||
<Box sx={timestampPageStyles.CONVERSION_CARD}>
|
<div className="p-5 rounded-xl bg-white border border-gray-200 shadow-sm">
|
||||||
{/* 模式切换 */}
|
{/* 模式切换 */}
|
||||||
<SwitchButtonGroup
|
<SwitchButtonGroup
|
||||||
value={mode}
|
value={mode}
|
||||||
@@ -56,26 +54,22 @@ export default function Index() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 输入区 */}
|
{/* 输入区 */}
|
||||||
<Stack spacing={1.5}>
|
<div className="flex flex-col gap-3">
|
||||||
<TextField
|
<input
|
||||||
|
type="text"
|
||||||
placeholder={
|
placeholder={
|
||||||
mode === 'ts2dt' ? t('timestamp:placeholderTs') : t('timestamp:placeholderDate')
|
mode === 'ts2dt' ? t('timestamp:placeholderTs') : t('timestamp:placeholderDate')
|
||||||
}
|
}
|
||||||
value={mode === 'ts2dt' ? tsInput : dtInput}
|
value={mode === 'ts2dt' ? tsInput : dtInput}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
error={!!error}
|
className={`w-full px-4 py-2.5 rounded-lg border ${
|
||||||
helperText={error}
|
error ? 'border-red-500' : 'border-gray-300'
|
||||||
fullWidth
|
} bg-white text-sm font-mono font-semibold focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all`}
|
||||||
sx={timestampPageStyles.INPUT_STYLE}
|
|
||||||
/>
|
/>
|
||||||
|
{error && <p className="text-red-500 text-xs mt-1">{error}</p>}
|
||||||
|
|
||||||
{/* 单位+时区紧凑横排 */}
|
{/* 单位+时区紧凑横排 */}
|
||||||
<Stack
|
<div className="flex flex-wrap gap-3 w-full">
|
||||||
direction="row"
|
|
||||||
spacing={1.5}
|
|
||||||
useFlexGap
|
|
||||||
sx={{ width: '100%', flexWrap: 'wrap' }}
|
|
||||||
>
|
|
||||||
<SwitchButtonGroup
|
<SwitchButtonGroup
|
||||||
value={unit}
|
value={unit}
|
||||||
options={[
|
options={[
|
||||||
@@ -87,43 +81,35 @@ export default function Index() {
|
|||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Select
|
<select
|
||||||
value={zone}
|
value={zone}
|
||||||
onChange={(e) => setZone(e.target.value as typeof zone)}
|
onChange={(e) => setZone(e.target.value as typeof zone)}
|
||||||
sx={{
|
className="flex-1 min-w-0 px-4 py-2.5 rounded-lg border border-gray-300 bg-white text-sm font-mono font-semibold focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||||
...timestampPageStyles.INPUT_STYLE,
|
|
||||||
flex: 1,
|
|
||||||
minWidth: 0,
|
|
||||||
borderRadius: 4,
|
|
||||||
'& .MuiSelect-select': {
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
MenuProps={timestampPageStyles.SELECT_MENU_PROPS}
|
|
||||||
>
|
>
|
||||||
{ZONES.map((z) => (
|
{ZONES.map((z) => (
|
||||||
<MenuItem key={z} value={z} sx={{ fontSize: '0.8rem', fontWeight: 600 }}>
|
<option key={z} value={z} className="text-sm font-semibold">
|
||||||
{z}
|
{z}
|
||||||
</MenuItem>
|
</option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</select>
|
||||||
</Stack>
|
</div>
|
||||||
</Stack>
|
</div>
|
||||||
|
|
||||||
{/* 立即转换 */}
|
{/* 立即转换 */}
|
||||||
<Button variant="contained" onClick={convert} sx={timestampPageStyles.CONVERT_BUTTON}>
|
<button
|
||||||
|
onClick={convert}
|
||||||
|
className="block mx-auto mt-4 mb-1 max-w-[240px] w-full py-2.5 text-sm font-semibold rounded-lg bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all"
|
||||||
|
>
|
||||||
{t('timestamp:convertButton')}
|
{t('timestamp:convertButton')}
|
||||||
</Button>
|
</button>
|
||||||
</Box>
|
</div>
|
||||||
|
|
||||||
{/* 右栏:结果展示卡片 */}
|
{/* 右栏:结果展示卡片 */}
|
||||||
<Box sx={timestampPageStyles.RESULT_COLUMN_CARD}>
|
<div className="p-5 rounded-xl bg-white border border-gray-200 shadow-sm h-full flex flex-col">
|
||||||
<ResultView result={result} mode={mode} unit={unit} zone={zone} showEmptyPlaceholder />
|
<ResultView result={result} mode={mode} unit={unit} zone={zone} showEmptyPlaceholder />
|
||||||
</Box>
|
</div>
|
||||||
</Box>
|
</div>
|
||||||
</Container>
|
</div>
|
||||||
</Box>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user