feat: enhance StorageCleanerPage with accordion for storage options and immediate preference saving (#4)

This commit is contained in:
LingandRX
2026-04-05 17:57:54 +08:00
committed by GitHub
parent 8bc11eb696
commit 979b45a898
+117 -13
View File
@@ -8,9 +8,14 @@ import {
FormControlLabel, FormControlLabel,
Alert, Alert,
Snackbar, Snackbar,
Accordion,
AccordionSummary,
AccordionDetails,
Divider,
} from '@mui/material'; } from '@mui/material';
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { storageUtil } from '@/utils/chromeStorage'; import { storageUtil } from '@/utils/chromeStorage';
import type { StorageCleanerOptions, CleaningResult, StorageCleanerPreferences } from 'types/storage'; import type { StorageCleanerOptions, CleaningResult, StorageCleanerPreferences } from 'types/storage';
import { import {
@@ -76,8 +81,57 @@ export default function StorageCleanerPage() {
loadInfo(); loadInfo();
}, []); }, []);
const handleOptionChange = useCallback((key: keyof StorageCleanerOptions) => { const handleAutoRefreshChange = useCallback(async (checked: boolean) => {
setOptions((prev) => ({ ...prev, [key]: !prev[key] })); setAutoRefresh(checked);
// Save preference immediately
const prefs = await storageUtil.get(
'storageCleaner/preferences',
DEFAULT_PREFERENCES,
);
await storageUtil.set('storageCleaner/preferences', {
...(prefs || DEFAULT_PREFERENCES),
autoRefresh: checked,
});
}, []);
const handleOptionChange = useCallback(async (key: keyof StorageCleanerOptions) => {
setOptions((prev) => {
const newOptions = { ...prev, [key]: !prev[key] };
// Save options immediately
storageUtil.get('storageCleaner/preferences', DEFAULT_PREFERENCES)
.then(prefs => {
storageUtil.set('storageCleaner/preferences', {
...(prefs || DEFAULT_PREFERENCES),
selectedTypes: newOptions,
});
});
return newOptions;
});
}, []);
const allSelected = Object.values(options).every(Boolean);
const someSelected = Object.values(options).some(Boolean) && !allSelected;
const handleSelectAll = useCallback(async (checked: boolean) => {
const newOptions = {
localStorage: checked,
sessionStorage: checked,
indexedDB: checked,
cookies: checked,
cacheStorage: checked,
serviceWorkers: checked,
};
setOptions(newOptions);
// Save options immediately
const prefs = await storageUtil.get(
'storageCleaner/preferences',
DEFAULT_PREFERENCES,
);
await storageUtil.set('storageCleaner/preferences', {
...(prefs || DEFAULT_PREFERENCES),
selectedTypes: newOptions,
});
}, []); }, []);
const handleClean = useCallback(async () => { const handleClean = useCallback(async () => {
@@ -148,67 +202,111 @@ export default function StorageCleanerPage() {
</Box> </Box>
{/* Storage Type Options */} {/* Storage Type Options */}
<Box sx={{ mb: 2 }}> <Accordion
<Typography variant="subtitle1" sx={{ mb: 1 }}> disableGutters
elevation={0}
sx={{
bgcolor: 'grey.50',
borderRadius: 2,
mb: 2,
'&:before': { display: 'none' },
'&.Mui-expanded': { m: 0, mb: 2 },
}}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon sx={{ fontSize: '1.1rem' }} />}
sx={{
px: 2,
minHeight: 48,
'&.Mui-expanded': { minHeight: 48 },
'& .MuiAccordionSummary-content': { my: 1, '&.Mui-expanded': { my: 1 } },
}}
>
<Typography variant="subtitle2" sx={{ fontWeight: 600, color: 'text.primary' }}>
{allSelected ? '(全部)' : someSelected ? '(部分)' : '(未选)'}
</Typography> </Typography>
</AccordionSummary>
<AccordionDetails sx={{ px: 2, pt: 0, pb: 1.5 }}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}> <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.localStorage} checked={options.localStorage}
onChange={() => handleOptionChange('localStorage')} onChange={() => handleOptionChange('localStorage')}
/> />
} }
label="localStorage" label={<Typography variant="body2">localStorage</Typography>}
/> />
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.sessionStorage} checked={options.sessionStorage}
onChange={() => handleOptionChange('sessionStorage')} onChange={() => handleOptionChange('sessionStorage')}
/> />
} }
label="sessionStorage" label={<Typography variant="body2">sessionStorage</Typography>}
/> />
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.indexedDB} checked={options.indexedDB}
onChange={() => handleOptionChange('indexedDB')} onChange={() => handleOptionChange('indexedDB')}
/> />
} }
label="IndexedDB" label={<Typography variant="body2">IndexedDB</Typography>}
/> />
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.cookies} checked={options.cookies}
onChange={() => handleOptionChange('cookies')} onChange={() => handleOptionChange('cookies')}
/> />
} }
label="Cookies" label={<Typography variant="body2">Cookies</Typography>}
/> />
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.cacheStorage} checked={options.cacheStorage}
onChange={() => handleOptionChange('cacheStorage')} onChange={() => handleOptionChange('cacheStorage')}
/> />
} }
label="Cache Storage" label={<Typography variant="body2">Cache Storage</Typography>}
/> />
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
size="small"
checked={options.serviceWorkers} checked={options.serviceWorkers}
onChange={() => handleOptionChange('serviceWorkers')} onChange={() => handleOptionChange('serviceWorkers')}
/> />
} }
label="Service Workers" label={<Typography variant="body2">Service Workers</Typography>}
/>
<Divider sx={{ my: 1, opacity: 0.6 }} />
<FormControlLabel
control={
<Checkbox
size="small"
checked={allSelected}
indeterminate={someSelected}
onChange={(e) => handleSelectAll(e.target.checked)}
/>
}
label={
<Typography variant="body2" sx={{ fontWeight: 600 }}>
</Typography>
}
/> />
</Box> </Box>
</Box> </AccordionDetails>
</Accordion>
{/* Auto Refresh Option */} {/* Auto Refresh Option */}
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
@@ -216,7 +314,7 @@ export default function StorageCleanerPage() {
control={ control={
<Checkbox <Checkbox
checked={autoRefresh} checked={autoRefresh}
onChange={(e) => setAutoRefresh(e.target.checked)} onChange={(e) => handleAutoRefreshChange(e.target.checked)}
/> />
} }
label="清理完成后自动刷新页面" label="清理完成后自动刷新页面"
@@ -228,6 +326,12 @@ export default function StorageCleanerPage() {
<Button <Button
variant="contained" variant="contained"
onClick={() => setShowConfirm(true)} onClick={() => setShowConfirm(true)}
sx={{
py: 1.6, borderRadius: 3, fontSize: '1rem', fontWeight: 600, textTransform: 'none',
bgcolor: 'primary.main', transition: 'all 0.2s',
'&:hover': { bgcolor: 'primary.dark', transform: 'translateY(-1px)' },
'&:active': { transform: 'translateY(0)' }
}}
disabled={loading} disabled={loading}
fullWidth fullWidth
> >