进度条图标自定义

This commit is contained in:
mtvpls
2026-02-21 02:13:50 +08:00
parent 5d2f944346
commit f02dce869c
7 changed files with 273 additions and 1 deletions
+170
View File
@@ -6268,6 +6268,9 @@ const ThemeConfigComponent = ({
customCSS: '',
enableCache: true,
cacheMinutes: 1440, // 默认1天(1440分钟)
progressThumbType: 'default' as 'default' | 'preset' | 'custom',
progressThumbPresetId: '',
progressThumbCustomUrl: '',
});
const [loginBackgroundImages, setLoginBackgroundImages] = useState<string[]>(['']);
const [registerBackgroundImages, setRegisterBackgroundImages] = useState<string[]>(['']);
@@ -6280,6 +6283,9 @@ const ThemeConfigComponent = ({
customCSS: config.ThemeConfig.customCSS || '',
enableCache: config.ThemeConfig.enableCache !== false,
cacheMinutes: config.ThemeConfig.cacheMinutes || 1440,
progressThumbType: config.ThemeConfig.progressThumbType || 'default',
progressThumbPresetId: config.ThemeConfig.progressThumbPresetId || '',
progressThumbCustomUrl: config.ThemeConfig.progressThumbCustomUrl || '',
});
// 解析背景图配置
@@ -6711,6 +6717,170 @@ const ThemeConfigComponent = ({
</p>
</div>
{/* 进度条图标配置 */}
<div className='bg-white dark:bg-gray-800 rounded-lg p-6 border border-gray-200 dark:border-gray-700'>
<h3 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2'>
<Palette className='w-5 h-5' />
</h3>
<p className='text-sm text-gray-600 dark:text-gray-400 mb-4'>
</p>
{/* 图标类型选择 */}
<div className='space-y-4 mb-6'>
<label className='flex items-center space-x-3 cursor-pointer'>
<input
type='radio'
checked={themeSettings.progressThumbType === 'default'}
onChange={() =>
setThemeSettings((prev) => ({
...prev,
progressThumbType: 'default',
}))
}
className='w-4 h-4 text-blue-600'
/>
<span className='text-gray-900 dark:text-gray-100'>
</span>
</label>
<label className='flex items-center space-x-3 cursor-pointer'>
<input
type='radio'
checked={themeSettings.progressThumbType === 'preset'}
onChange={() =>
setThemeSettings((prev) => ({
...prev,
progressThumbType: 'preset',
}))
}
className='w-4 h-4 text-blue-600'
/>
<span className='text-gray-900 dark:text-gray-100'>
</span>
</label>
<label className='flex items-center space-x-3 cursor-pointer'>
<input
type='radio'
checked={themeSettings.progressThumbType === 'custom'}
onChange={() =>
setThemeSettings((prev) => ({
...prev,
progressThumbType: 'custom',
}))
}
className='w-4 h-4 text-blue-600'
/>
<span className='text-gray-900 dark:text-gray-100'>
</span>
</label>
</div>
{/* 预制图标选择 */}
{themeSettings.progressThumbType === 'preset' && (
<div className='space-y-3 mb-4'>
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
</label>
<div className='grid grid-cols-2 md:grid-cols-3 gap-3'>
{[
{ id: 'renako', name: '玲奈子', url: '/icons/q/renako.png', color: '#ec4899' },
].map((thumb) => (
<button
key={thumb.id}
type='button'
onClick={() =>
setThemeSettings((prev) => ({
...prev,
progressThumbPresetId: thumb.id,
}))
}
className={`relative p-4 border-2 rounded-lg transition-all ${
themeSettings.progressThumbPresetId === thumb.id
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
: 'border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500'
}`}
>
<div className='flex flex-col items-center gap-2'>
<img
src={thumb.url}
alt={thumb.name}
className='w-12 h-12 object-contain'
onError={(e) => {
(e.target as HTMLImageElement).src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="48" height="48"%3E%3Crect width="48" height="48" fill="%23ddd"/%3E%3Ctext x="50%25" y="50%25" text-anchor="middle" dy=".3em" fill="%23999"%3E?%3C/text%3E%3C/svg%3E';
}}
/>
<span className='text-sm font-medium text-gray-700 dark:text-gray-300 text-center'>
{thumb.name}
</span>
<div
className='w-8 h-2 rounded-full'
style={{ backgroundColor: thumb.color }}
title='进度条颜色'
/>
</div>
{themeSettings.progressThumbPresetId === thumb.id && (
<div className='absolute top-2 right-2'>
<Check className='w-5 h-5 text-blue-600 dark:text-blue-400' />
</div>
)}
</button>
))}
</div>
<p className='text-xs text-gray-500 dark:text-gray-400 mt-2'>
</p>
</div>
)}
{/* 自定义图标URL输入 */}
{themeSettings.progressThumbType === 'custom' && (
<div className='space-y-3'>
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
URL
</label>
<input
type='text'
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400'
placeholder='例如: https://example.com/icon.png'
value={themeSettings.progressThumbCustomUrl}
onChange={(e) =>
setThemeSettings((prev) => ({
...prev,
progressThumbCustomUrl: e.target.value,
}))
}
/>
<p className='text-xs text-gray-500 dark:text-gray-400'>
PNGJPGGIFWebP 32x32pxURL必须可公开访问
</p>
{themeSettings.progressThumbCustomUrl && (
<div className='mt-2 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg'>
<p className='text-xs text-gray-600 dark:text-gray-400 mb-2'></p>
<img
src={themeSettings.progressThumbCustomUrl}
alt='自定义图标预览'
className='w-12 h-12 object-contain border border-gray-300 dark:border-gray-600 rounded'
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
const parent = (e.target as HTMLImageElement).parentElement;
if (parent && !parent.querySelector('.error-msg')) {
const errorMsg = document.createElement('p');
errorMsg.className = 'text-xs text-red-500 error-msg';
errorMsg.textContent = '图片加载失败,请检查URL是否正确';
parent.appendChild(errorMsg);
}
}}
/>
</div>
)}
</div>
)}
</div>
{/* 保存按钮 */}
<div className='flex justify-end'>
<button