mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-15 12:24:41 +08:00
feat: admin config subscription
This commit is contained in:
@@ -149,11 +149,6 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
|
||||
// 当前登录用户名
|
||||
const currentUsername = getAuthInfoFromBrowserCookie()?.username || null;
|
||||
|
||||
// 检测存储类型是否为 upstash
|
||||
const isUpstashStorage =
|
||||
typeof window !== 'undefined' &&
|
||||
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash';
|
||||
|
||||
useEffect(() => {
|
||||
if (config?.UserConfig) {
|
||||
setUserSettings({
|
||||
@@ -314,26 +309,19 @@ const UserConfig = ({ config, role, refreshConfig }: UserConfigProps) => {
|
||||
</h4>
|
||||
<div className='flex items-center justify-between'>
|
||||
<label
|
||||
className={`text-gray-700 dark:text-gray-300 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
className={`text-gray-700 dark:text-gray-300
|
||||
}`}
|
||||
>
|
||||
允许新用户注册
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<button
|
||||
onClick={() =>
|
||||
!isUpstashStorage &&
|
||||
toggleAllowRegister(!userSettings.enableRegistration)
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${userSettings.enableRegistration
|
||||
? 'bg-green-600'
|
||||
: 'bg-gray-200 dark:bg-gray-700'
|
||||
} ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${userSettings.enableRegistration
|
||||
@@ -976,11 +964,6 @@ const CategoryConfig = ({
|
||||
from: 'config',
|
||||
});
|
||||
|
||||
// 检测存储类型是否为 upstash
|
||||
const isUpstashStorage =
|
||||
typeof window !== 'undefined' &&
|
||||
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash';
|
||||
|
||||
// dnd-kit 传感器
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
@@ -1066,7 +1049,6 @@ const CategoryConfig = ({
|
||||
};
|
||||
|
||||
const handleDragEnd = (event: any) => {
|
||||
if (isUpstashStorage) return;
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id) return;
|
||||
const oldIndex = categories.findIndex(
|
||||
@@ -1107,10 +1089,9 @@ const CategoryConfig = ({
|
||||
className='hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors select-none'
|
||||
>
|
||||
<td
|
||||
className={`px-2 py-4 ${isUpstashStorage ? 'text-gray-200' : 'cursor-grab text-gray-400'
|
||||
}`}
|
||||
className="px-2 py-4 cursor-grab text-gray-400"
|
||||
style={{ touchAction: 'none' }}
|
||||
{...(isUpstashStorage ? {} : { ...attributes, ...listeners })}
|
||||
{...{ ...attributes, ...listeners }}
|
||||
>
|
||||
<GripVertical size={16} />
|
||||
</td>
|
||||
@@ -1146,20 +1127,16 @@ const CategoryConfig = ({
|
||||
<td className='px-6 py-4 whitespace-nowrap text-right text-sm font-medium space-x-2'>
|
||||
<button
|
||||
onClick={() =>
|
||||
!isUpstashStorage &&
|
||||
handleToggleEnable(category.query, category.type)
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium ${isUpstashStorage
|
||||
? 'bg-gray-400 cursor-not-allowed text-white'
|
||||
: !category.disabled
|
||||
? 'bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300 hover:bg-red-200 dark:hover:bg-red-900/60'
|
||||
: 'bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300 hover:bg-green-200 dark:hover:bg-green-900/60'
|
||||
className={`inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium ${!category.disabled
|
||||
? 'bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300 hover:bg-red-200 dark:hover:bg-red-900/60'
|
||||
: 'bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300 hover:bg-green-200 dark:hover:bg-green-900/60'
|
||||
} transition-colors`}
|
||||
>
|
||||
{!category.disabled ? '禁用' : '启用'}
|
||||
</button>
|
||||
{category.from !== 'config' && !isUpstashStorage && (
|
||||
{category.from !== 'config' && (
|
||||
<button
|
||||
onClick={() => handleDelete(category.query, category.type)}
|
||||
className='inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 hover:bg-gray-200 dark:bg-gray-700/40 dark:hover:bg-gray-700/60 dark:text-gray-200 transition-colors'
|
||||
@@ -1186,25 +1163,16 @@ const CategoryConfig = ({
|
||||
<div className='flex items-center justify-between'>
|
||||
<h4 className='text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||
自定义分类列表
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过配置文件修改)
|
||||
</span>
|
||||
)}
|
||||
</h4>
|
||||
<button
|
||||
onClick={() => !isUpstashStorage && setShowAddForm(!showAddForm)}
|
||||
disabled={isUpstashStorage}
|
||||
className={`px-3 py-1 text-sm rounded-lg transition-colors ${isUpstashStorage
|
||||
? 'bg-gray-400 cursor-not-allowed text-white'
|
||||
: 'bg-green-600 hover:bg-green-700 text-white'
|
||||
}`}
|
||||
onClick={() => setShowAddForm(!showAddForm)}
|
||||
className="px-3 py-1 text-sm rounded-lg transition-colors bg-green-600 hover:bg-green-700 text-white"
|
||||
>
|
||||
{showAddForm ? '取消' : '添加分类'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showAddForm && !isUpstashStorage && (
|
||||
{showAddForm && (
|
||||
<div className='p-4 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 space-y-4'>
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
|
||||
<input
|
||||
@@ -1275,7 +1243,7 @@ const CategoryConfig = ({
|
||||
</tr>
|
||||
</thead>
|
||||
<DndContext
|
||||
sensors={isUpstashStorage ? [] : sensors}
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={handleDragEnd}
|
||||
autoScroll={false}
|
||||
@@ -1299,7 +1267,7 @@ const CategoryConfig = ({
|
||||
</div>
|
||||
|
||||
{/* 保存排序按钮 */}
|
||||
{orderChanged && !isUpstashStorage && (
|
||||
{orderChanged && (
|
||||
<div className='flex justify-end'>
|
||||
<button
|
||||
onClick={handleSaveOrder}
|
||||
@@ -1419,7 +1387,7 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig |
|
||||
<h3 className='text-xl font-semibold text-gray-900 dark:text-gray-100'>
|
||||
配置订阅
|
||||
</h3>
|
||||
<div className='text-sm text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-700 px-3 py-1.5 rounded-full'>
|
||||
<div className='text-sm text-gray-500 dark:text-gray-400 px-3 py-1.5 rounded-full'>
|
||||
最后更新: {lastCheckTime ? new Date(lastCheckTime).toLocaleString('zh-CN') : '从未更新'}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1438,10 +1406,31 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig |
|
||||
className='w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all duration-200 shadow-sm hover:border-gray-400 dark:hover:border-gray-500'
|
||||
/>
|
||||
<p className='mt-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
输入配置文件的订阅地址,支持JSON格式
|
||||
输入配置文件的订阅地址,要求 JSON 格式,且使用 Base58 编码
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 拉取配置按钮 */}
|
||||
<div className='pt-2'>
|
||||
<button
|
||||
onClick={handleFetchConfig}
|
||||
disabled={fetching || !subscriptionUrl.trim()}
|
||||
className={`w-full px-6 py-3 rounded-lg font-medium transition-all duration-200 ${fetching || !subscriptionUrl.trim()
|
||||
? 'bg-gray-300 dark:bg-gray-600 cursor-not-allowed text-gray-500 dark:text-gray-400'
|
||||
: 'bg-green-600 hover:bg-green-700 text-white shadow-sm hover:shadow-md transform hover:-translate-y-0.5'
|
||||
}`}
|
||||
>
|
||||
{fetching ? (
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
<div className='w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin'></div>
|
||||
拉取中…
|
||||
</div>
|
||||
) : (
|
||||
'拉取配置'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 自动更新开关 */}
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
@@ -1468,27 +1457,6 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig |
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 拉取配置按钮 */}
|
||||
<div className='pt-2'>
|
||||
<button
|
||||
onClick={handleFetchConfig}
|
||||
disabled={fetching || !subscriptionUrl.trim()}
|
||||
className={`w-full px-6 py-3 rounded-lg font-medium transition-all duration-200 ${fetching || !subscriptionUrl.trim()
|
||||
? 'bg-gray-300 dark:bg-gray-600 cursor-not-allowed text-gray-500 dark:text-gray-400'
|
||||
: 'bg-green-600 hover:bg-green-700 text-white shadow-sm hover:shadow-md transform hover:-translate-y-0.5'
|
||||
}`}
|
||||
>
|
||||
{fetching ? (
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
<div className='w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin'></div>
|
||||
拉取中…
|
||||
</div>
|
||||
) : (
|
||||
'拉取配置'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1521,7 +1489,7 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig |
|
||||
: 'bg-green-600 hover:bg-green-700 text-white'
|
||||
}`}
|
||||
>
|
||||
{saving ? '保存中…' : '保存配置文件'}
|
||||
{saving ? '保存中…' : '保存'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1530,7 +1498,7 @@ const ConfigFileComponent = ({ config, refreshConfig }: { config: AdminConfig |
|
||||
};
|
||||
|
||||
// 新增站点配置组件
|
||||
const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
const SiteConfigComponent = ({ config, refreshConfig }: { config: AdminConfig | null; refreshConfig: () => Promise<void> }) => {
|
||||
const [siteSettings, setSiteSettings] = useState<SiteConfig>({
|
||||
SiteName: '',
|
||||
Announcement: '',
|
||||
@@ -1595,11 +1563,6 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 检测存储类型是否为 upstash
|
||||
const isUpstashStorage =
|
||||
typeof window !== 'undefined' &&
|
||||
(window as any).RUNTIME_CONFIG?.STORAGE_TYPE === 'upstash';
|
||||
|
||||
useEffect(() => {
|
||||
if (config?.SiteConfig) {
|
||||
setSiteSettings({
|
||||
@@ -1651,22 +1614,18 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
|
||||
// 处理豆瓣数据源变化
|
||||
const handleDoubanDataSourceChange = (value: string) => {
|
||||
if (!isUpstashStorage) {
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanProxyType: value,
|
||||
}));
|
||||
}
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanProxyType: value,
|
||||
}));
|
||||
};
|
||||
|
||||
// 处理豆瓣图片代理变化
|
||||
const handleDoubanImageProxyChange = (value: string) => {
|
||||
if (!isUpstashStorage) {
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanImageProxyType: value,
|
||||
}));
|
||||
}
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanImageProxyType: value,
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存站点配置
|
||||
@@ -1685,6 +1644,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
}
|
||||
|
||||
showSuccess('保存成功, 请刷新页面');
|
||||
await refreshConfig();
|
||||
} catch (err) {
|
||||
showError(err instanceof Error ? err.message : '保存失败');
|
||||
} finally {
|
||||
@@ -1705,55 +1665,37 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
{/* 站点名称 */}
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
站点名称
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={siteSettings.SiteName}
|
||||
onChange={(e) =>
|
||||
!isUpstashStorage &&
|
||||
setSiteSettings((prev) => ({ ...prev, SiteName: e.target.value }))
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 站点公告 */}
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
站点公告
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<textarea
|
||||
value={siteSettings.Announcement}
|
||||
onChange={(e) =>
|
||||
!isUpstashStorage &&
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
Announcement: e.target.value,
|
||||
}))
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
rows={3}
|
||||
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1761,24 +1703,16 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
<div className='space-y-3'>
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
豆瓣数据代理
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<div className='relative' data-dropdown='douban-datasource'>
|
||||
{/* 自定义下拉选择框 */}
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setIsDoubanDropdownOpen(!isDoubanDropdownOpen)}
|
||||
disabled={isUpstashStorage}
|
||||
className={`w-full px-3 py-2.5 pr-10 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 text-left ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2.5 pr-10 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 text-left"
|
||||
>
|
||||
{
|
||||
doubanDataSourceOptions.find(
|
||||
@@ -1796,7 +1730,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
</div>
|
||||
|
||||
{/* 下拉选项列表 */}
|
||||
{isDoubanDropdownOpen && !isUpstashStorage && (
|
||||
{isDoubanDropdownOpen && (
|
||||
<div className='absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg max-h-60 overflow-auto'>
|
||||
{doubanDataSourceOptions.map((option) => (
|
||||
<button
|
||||
@@ -1850,8 +1784,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
{siteSettings.DoubanProxyType === 'custom' && (
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
豆瓣代理地址
|
||||
</label>
|
||||
@@ -1860,15 +1793,12 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
placeholder='例如: https://proxy.example.com/fetch?url='
|
||||
value={siteSettings.DoubanProxy}
|
||||
onChange={(e) =>
|
||||
!isUpstashStorage &&
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanProxy: e.target.value,
|
||||
}))
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`w-full px-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 shadow-sm hover:border-gray-400 dark:hover:border-gray-500"
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
自定义代理服务器地址
|
||||
@@ -1881,15 +1811,9 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
<div className='space-y-3'>
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
豆瓣图片代理
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<div className='relative' data-dropdown='douban-image-proxy'>
|
||||
{/* 自定义下拉选择框 */}
|
||||
@@ -1900,9 +1824,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
!isDoubanImageProxyDropdownOpen
|
||||
)
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`w-full px-3 py-2.5 pr-10 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 text-left ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2.5 pr-10 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 text-left"
|
||||
>
|
||||
{
|
||||
doubanImageProxyTypeOptions.find(
|
||||
@@ -1920,7 +1842,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
</div>
|
||||
|
||||
{/* 下拉选项列表 */}
|
||||
{isDoubanImageProxyDropdownOpen && !isUpstashStorage && (
|
||||
{isDoubanImageProxyDropdownOpen && (
|
||||
<div className='absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg max-h-60 overflow-auto'>
|
||||
{doubanImageProxyTypeOptions.map((option) => (
|
||||
<button
|
||||
@@ -1974,8 +1896,7 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
{siteSettings.DoubanImageProxyType === 'custom' && (
|
||||
<div>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
豆瓣图片代理地址
|
||||
</label>
|
||||
@@ -1984,15 +1905,12 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
placeholder='例如: https://proxy.example.com/fetch?url='
|
||||
value={siteSettings.DoubanImageProxy}
|
||||
onChange={(e) =>
|
||||
!isUpstashStorage &&
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DoubanImageProxy: e.target.value,
|
||||
}))
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`w-full px-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 shadow-sm hover:border-gray-400 dark:hover:border-gray-500 ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
className="w-full px-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 shadow-sm hover:border-gray-400 dark:hover:border-gray-500"
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
自定义图片代理服务器地址
|
||||
@@ -2043,30 +1961,22 @@ const SiteConfigComponent = ({ config }: { config: AdminConfig | null }) => {
|
||||
<div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<label
|
||||
className={`block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2 ${isUpstashStorage ? 'opacity-50' : ''
|
||||
}`}
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
禁用黄色过滤器
|
||||
{isUpstashStorage && (
|
||||
<span className='ml-2 text-xs text-gray-500 dark:text-gray-400'>
|
||||
(Upstash 环境下请通过环境变量修改)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() =>
|
||||
!isUpstashStorage &&
|
||||
setSiteSettings((prev) => ({
|
||||
...prev,
|
||||
DisableYellowFilter: !prev.DisableYellowFilter,
|
||||
}))
|
||||
}
|
||||
disabled={isUpstashStorage}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${siteSettings.DisableYellowFilter
|
||||
? 'bg-green-600'
|
||||
: 'bg-gray-200 dark:bg-gray-700'
|
||||
} ${isUpstashStorage ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${siteSettings.DisableYellowFilter
|
||||
@@ -2171,6 +2081,7 @@ function AdminPageClient() {
|
||||
throw new Error(`重置失败: ${response.status}`);
|
||||
}
|
||||
showSuccess('重置成功,请刷新页面!');
|
||||
await fetchConfig();
|
||||
} catch (err) {
|
||||
showError(err instanceof Error ? err.message : '重置失败');
|
||||
}
|
||||
@@ -2249,7 +2160,7 @@ function AdminPageClient() {
|
||||
isExpanded={expandedTabs.siteConfig}
|
||||
onToggle={() => toggleTab('siteConfig')}
|
||||
>
|
||||
<SiteConfigComponent config={config} />
|
||||
<SiteConfigComponent config={config} refreshConfig={fetchConfig} />
|
||||
</CollapsibleTab>
|
||||
|
||||
<div className='space-y-4'>
|
||||
|
||||
Reference in New Issue
Block a user