新增公告功能
This commit is contained in:
45
src/App.tsx
45
src/App.tsx
@ -1,9 +1,11 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { Container, CssBaseline, ThemeProvider, createTheme, Box, Tabs, Tab, Paper } from '@mui/material';
|
import { Container, CssBaseline, ThemeProvider, createTheme, Box, Tabs, Tab, Paper, Button, Typography } from '@mui/material';
|
||||||
|
import GitHubIcon from '@mui/icons-material/GitHub';
|
||||||
import { RecordForm } from './components/RecordForm';
|
import { RecordForm } from './components/RecordForm';
|
||||||
import { StatsChart } from './components/StatsChart';
|
import { StatsChart } from './components/StatsChart';
|
||||||
import { HistoryList } from './components/HistoryList';
|
import { HistoryList } from './components/HistoryList';
|
||||||
|
import { UpdateDialog } from './components/UpdateDialog';
|
||||||
|
|
||||||
interface TabPanelProps {
|
interface TabPanelProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
@ -89,6 +91,7 @@ function App() {
|
|||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<Box sx={{ minHeight: '100vh', backgroundColor: 'background.default' }}>
|
<Box sx={{ minHeight: '100vh', backgroundColor: 'background.default' }}>
|
||||||
|
<UpdateDialog />
|
||||||
<Container maxWidth="md" sx={{ py: 4 }}>
|
<Container maxWidth="md" sx={{ py: 4 }}>
|
||||||
<Paper sx={{ p: 3 }}>
|
<Paper sx={{ p: 3 }}>
|
||||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||||
@ -99,6 +102,46 @@ function App() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<TabPanel value={tabValue} index={0}>
|
<TabPanel value={tabValue} index={0}>
|
||||||
|
{/* 添加 GitHub Star 按钮 */}
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1,
|
||||||
|
mb: 4
|
||||||
|
}}>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle2"
|
||||||
|
sx={{
|
||||||
|
color: 'text.secondary',
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '0.875rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
祝愿所有给本项目Star的小伙伴牛子长度翻倍!
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
startIcon={<GitHubIcon />}
|
||||||
|
onClick={() => window.open('https://github.com/zzzdajb/DickHelper', '_blank')}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
background: 'linear-gradient(45deg, #24292e 30%, #40464e 90%)',
|
||||||
|
'&:hover': {
|
||||||
|
background: 'linear-gradient(45deg, #40464e 30%, #586069 90%)',
|
||||||
|
transform: 'translateY(-2px)',
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.15)'
|
||||||
|
},
|
||||||
|
transition: 'all 0.3s ease'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
⭐ Star on GitHub
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||||
<Box>
|
<Box>
|
||||||
<RecordForm />
|
<RecordForm />
|
||||||
|
@ -186,7 +186,7 @@ export const RecordForm = () => {
|
|||||||
WebkitBackgroundClip: 'text',
|
WebkitBackgroundClip: 'text',
|
||||||
WebkitTextFillColor: 'transparent'
|
WebkitTextFillColor: 'transparent'
|
||||||
}}>
|
}}>
|
||||||
记录新的自慰
|
记录新的手艺活
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Box, Typography, Grid, Paper, Button } from '@mui/material';
|
import { Box, Typography, Grid, Paper } from '@mui/material'; // 删除 Button 导入
|
||||||
import { StorageService } from '../services/storage';
|
import { StorageService } from '../services/storage';
|
||||||
import { MasturbationRecord, MasturbationStats } from '../types/record';
|
import { MasturbationRecord, MasturbationStats } from '../types/record';
|
||||||
import GitHubIcon from '@mui/icons-material/GitHub';
|
// 删除 GitHubIcon 导入
|
||||||
|
|
||||||
const DAYS_IN_WEEK = 7;
|
const DAYS_IN_WEEK = 7;
|
||||||
const WEEKS_TO_SHOW = 4; // 将显示时间范围改为4周
|
const WEEKS_TO_SHOW = 4; // 将显示时间范围改为4周
|
||||||
const WEEKDAYS = ['一', '二', '三', '四', '五', '六', '日'];
|
const WEEKDAYS = ['一', '二', '三', '四', '五', '六', '日'];
|
||||||
const GITHUB_REPO_URL = 'https://github.com/zzzdajb/DickHelper'; // 替换为实际的Github仓库地址
|
// 删除 GITHUB_REPO_URL 常量
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统计图表组件
|
* 统计图表组件
|
||||||
@ -165,44 +165,7 @@ export const StatsChart = () => {
|
|||||||
统计数据
|
统计数据
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{
|
{/* 删除整个 GitHub Star 按钮的 Box 组件 */}
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 1,
|
|
||||||
mb: 4
|
|
||||||
}}>
|
|
||||||
<Typography
|
|
||||||
variant="subtitle2"
|
|
||||||
sx={{
|
|
||||||
color: 'text.secondary',
|
|
||||||
fontWeight: 500,
|
|
||||||
fontSize: '0.875rem'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
求求你给个Star!
|
|
||||||
</Typography>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
startIcon={<GitHubIcon />}
|
|
||||||
onClick={() => window.open(GITHUB_REPO_URL, '_blank')}
|
|
||||||
sx={{
|
|
||||||
borderRadius: 2,
|
|
||||||
textTransform: 'none',
|
|
||||||
fontWeight: 600,
|
|
||||||
background: 'linear-gradient(45deg, #24292e 30%, #40464e 90%)',
|
|
||||||
'&:hover': {
|
|
||||||
background: 'linear-gradient(45deg, #40464e 30%, #586069 90%)',
|
|
||||||
transform: 'translateY(-2px)',
|
|
||||||
boxShadow: '0 4px 12px rgba(0,0,0,0.15)'
|
|
||||||
},
|
|
||||||
transition: 'all 0.3s ease'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⭐ Star on GitHub
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Grid container spacing={2} sx={{ mb: 3 }} columns={12}>
|
<Grid container spacing={2} sx={{ mb: 3 }} columns={12}>
|
||||||
<Grid item xs={12} sm={6}>
|
<Grid item xs={12} sm={6}>
|
||||||
@ -371,7 +334,7 @@ export const StatsChart = () => {
|
|||||||
color: 'text.primary'
|
color: 'text.primary'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
自慰日历
|
发射日历
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
155
src/components/UpdateDialog.tsx
Normal file
155
src/components/UpdateDialog.tsx
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Box } from '@mui/material';
|
||||||
|
|
||||||
|
interface UpdateInfo {
|
||||||
|
version: string;
|
||||||
|
date: string;
|
||||||
|
changes: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERSION_HISTORY: UpdateInfo[] = [
|
||||||
|
{
|
||||||
|
version: 'v0.1.1',
|
||||||
|
date: '2025-02-20',
|
||||||
|
changes: [
|
||||||
|
'非常感谢每一个给我Star的小伙伴!',
|
||||||
|
'新增更新公告弹窗,方便用户了解最新变化',
|
||||||
|
'调整了一些文字内容,防止尴尬',
|
||||||
|
'修复了一些已知问题'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: 'v0.1.0',
|
||||||
|
date: '2025-02-20',
|
||||||
|
changes: [
|
||||||
|
'正式发布',
|
||||||
|
'基础记录功能',
|
||||||
|
'统计图表功能',
|
||||||
|
'历史记录管理'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const LOCAL_STORAGE_KEY = 'next_update_notice_date';
|
||||||
|
|
||||||
|
export const UpdateDialog = () => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const nextNoticeDate = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (!nextNoticeDate || new Date(nextNoticeDate) <= now) {
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClose = (dontShowFor3Days: boolean = false) => {
|
||||||
|
setOpen(false);
|
||||||
|
// 只有当用户选择"3天内不再提示
|
||||||
|
if (dontShowFor3Days) {
|
||||||
|
const nextDate = new Date();
|
||||||
|
nextDate.setDate(nextDate.getDate() + 3);
|
||||||
|
localStorage.setItem(LOCAL_STORAGE_KEY, nextDate.toISOString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
aria-labelledby="update-dialog-title"
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<DialogTitle id="update-dialog-title" sx={{
|
||||||
|
background: 'linear-gradient(45deg, #2196f3 30%, #64b5f6 90%)',
|
||||||
|
color: 'white',
|
||||||
|
fontWeight: 700
|
||||||
|
}}>
|
||||||
|
更新公告
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent sx={{ mt: 2, maxHeight: 400, overflowY: 'auto' }}>
|
||||||
|
{VERSION_HISTORY.map((version, versionIndex) => (
|
||||||
|
<Box key={version.version} sx={{ mb: versionIndex < VERSION_HISTORY.length - 1 ? 4 : 2 }}>
|
||||||
|
<Typography variant="h6" sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
color: versionIndex === 0 ? 'primary.main' : 'text.primary',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1
|
||||||
|
}}>
|
||||||
|
{version.version}
|
||||||
|
{versionIndex === 0 && (
|
||||||
|
<Typography
|
||||||
|
component="span"
|
||||||
|
variant="caption"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'primary.main',
|
||||||
|
color: 'white',
|
||||||
|
px: 1,
|
||||||
|
py: 0.5,
|
||||||
|
borderRadius: 1,
|
||||||
|
fontSize: '0.75rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
最新
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle2" color="text.secondary" sx={{ mb: 2 }}>
|
||||||
|
发布日期:{version.date}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle1" sx={{ fontWeight: 500, mb: 1 }}>
|
||||||
|
更新内容:
|
||||||
|
</Typography>
|
||||||
|
<Box component="ul" sx={{ mt: 0, pl: 2 }}>
|
||||||
|
{version.changes.map((change, index) => (
|
||||||
|
<Typography
|
||||||
|
key={index}
|
||||||
|
component="li"
|
||||||
|
variant="body1"
|
||||||
|
sx={{ mb: 1, color: 'text.secondary' }}
|
||||||
|
>
|
||||||
|
{change}
|
||||||
|
</Typography>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions sx={{ p: 2, pt: 0, gap: 1 }}>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleClose(true)}
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
color: 'primary.main',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: 'primary.dark',
|
||||||
|
backgroundColor: 'rgba(33, 150, 243, 0.08)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
3天内不再提示
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleClose()}
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
px: 3,
|
||||||
|
background: 'linear-gradient(45deg, #2196f3 30%, #64b5f6 90%)',
|
||||||
|
'&:hover': {
|
||||||
|
background: 'linear-gradient(45deg, #1976d2 30%, #2196f3 90%)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
我知道了
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
Reference in New Issue
Block a user