11import React , { useState } from 'react' ;
2- import { Shield , Github , Save , CheckCircle , Database , ExternalLink , AlertTriangle , Layers , User , Settings as SettingsIcon } from 'lucide-react' ;
2+ import { Shield , Github , Save , CheckCircle , Database , ExternalLink , AlertTriangle , Layers , User , Settings as SettingsIcon , Globe } from 'lucide-react' ;
33import { GitHubConfig , Profile } from '../types' ;
44import { motion } from 'framer-motion' ;
55import { useLanguage } from '../App' ;
@@ -25,8 +25,14 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
2525 const [ avatar , setAvatar ] = useState ( profile . avatar ) ;
2626 const [ githubUrl , setGithubUrl ] = useState ( profile . socials . github || '' ) ;
2727
28+ // 站点设置
29+ const [ siteName , setSiteName ] = useState ( profile . siteSettings ?. siteName || '' ) ;
30+ const [ siteIcon , setSiteIcon ] = useState ( profile . siteSettings ?. siteIcon || '' ) ;
31+ const [ siteDescription , setSiteDescription ] = useState ( profile . siteSettings ?. siteDescription || '' ) ;
32+
2833 const [ savingConfig , setSavingConfig ] = useState ( false ) ;
2934 const [ savingProfile , setSavingProfile ] = useState ( false ) ;
35+ const [ savingSiteSettings , setSavingSiteSettings ] = useState ( false ) ;
3036
3137 // 保存GitHub配置(仅保存token,repository信息从config.json读取)
3238 const handleSaveConfig = async ( ) => {
@@ -63,6 +69,23 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
6369 }
6470 } ;
6571
72+ // 保存站点设置
73+ const handleSaveSiteSettings = async ( ) => {
74+ setSavingSiteSettings ( true ) ;
75+ try {
76+ await onSaveProfile ( {
77+ ...profile ,
78+ siteSettings : {
79+ siteName,
80+ siteIcon,
81+ siteDescription
82+ }
83+ } ) ;
84+ } finally {
85+ setSavingSiteSettings ( false ) ;
86+ }
87+ } ;
88+
6689 return (
6790 < div className = "max-w-5xl mx-auto pb-20 md:pb-0" >
6891 { /* 桌面端顶部 */ }
@@ -77,7 +100,7 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
77100 < div className = "flex gap-3" >
78101 < button
79102 onClick = { handleSaveConfig }
80- disabled = { savingConfig || savingProfile }
103+ disabled = { savingConfig || savingProfile || savingSiteSettings }
81104 className = "flex items-center justify-center px-6 py-4 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-[1.5rem] font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
82105 >
83106 { savingConfig ? (
@@ -89,7 +112,7 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
89112 </ button >
90113 < button
91114 onClick = { handleSaveProfile }
92- disabled = { savingConfig || savingProfile }
115+ disabled = { savingConfig || savingProfile || savingSiteSettings }
93116 className = "flex items-center justify-center px-6 py-4 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-[1.5rem] font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
94117 >
95118 { savingProfile ? (
@@ -99,6 +122,18 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
99122 ) }
100123 { savingProfile ? t . settings . saving : t . settings . saveProfile }
101124 </ button >
125+ < button
126+ onClick = { handleSaveSiteSettings }
127+ disabled = { savingConfig || savingProfile || savingSiteSettings }
128+ className = "flex items-center justify-center px-6 py-4 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-[1.5rem] font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
129+ >
130+ { savingSiteSettings ? (
131+ < div className = "w-5 h-5 border-2 border-indigo-600 dark:text-indigo-400 border-t-transparent rounded-full animate-spin mr-2" > </ div >
132+ ) : (
133+ < Globe size = { 18 } className = "mr-2" />
134+ ) }
135+ { savingSiteSettings ? t . settings . saving : t . settings . saveSiteSettings }
136+ </ button >
102137 </ div >
103138 </ div >
104139
@@ -239,6 +274,59 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
239274 </ div >
240275 </ div >
241276 </ motion . section >
277+
278+ { /* 站点设置 */ }
279+ < motion . section
280+ initial = { { opacity : 0 , y : 20 } }
281+ animate = { { opacity : 1 , y : 0 } }
282+ transition = { { delay : 0.2 } }
283+ className = "bg-white dark:bg-gray-800 p-4 md:p-10 rounded-xl md:rounded-[3rem] shadow-sm border border-gray-100 dark:border-gray-700"
284+ >
285+ < div className = "flex items-center space-x-3 mb-5 md:mb-10" >
286+ < div className = "p-2 md:p-3 bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-xl md:rounded-2xl" >
287+ < Globe size = { 20 } className = "md:w-6 md:h-6" />
288+ </ div >
289+ < div >
290+ < h2 className = "text-lg md:text-2xl font-black text-gray-900 dark:text-gray-100 tracking-tight" > { t . settings . siteSettings } </ h2 >
291+ < p className = "text-xs text-gray-400 dark:text-gray-500 font-bold uppercase tracking-widest mt-0.5" > { t . settings . siteSettingsDesc } </ p >
292+ </ div >
293+ </ div >
294+
295+ < div className = "space-y-4 md:space-y-8" >
296+ < div >
297+ < label className = "block text-xs md:text-sm font-black text-gray-900 dark:text-gray-100 uppercase tracking-widest mb-2 md:mb-3" > { t . settings . siteName } </ label >
298+ < input
299+ type = "text"
300+ value = { siteName }
301+ onChange = { ( e ) => setSiteName ( e . target . value ) }
302+ placeholder = "例如:我的个人博客"
303+ className = "w-full px-3 md:px-5 py-2.5 md:py-4 bg-gray-50 dark:bg-gray-700 border border-gray-100 dark:border-gray-600 text-gray-900 dark:text-gray-100 rounded-lg md:rounded-2xl focus:ring-2 md:focus:ring-4 focus:ring-indigo-50 dark:focus:ring-indigo-900/30 outline-none transition-all font-bold"
304+ />
305+ </ div >
306+ < div >
307+ < label className = "block text-xs md:text-sm font-black text-gray-900 dark:text-gray-100 uppercase tracking-widest mb-2 md:mb-3" > { t . settings . siteIcon } </ label >
308+ < input
309+ type = "text"
310+ value = { siteIcon }
311+ onChange = { ( e ) => setSiteIcon ( e . target . value ) }
312+ placeholder = "https://example.com/favicon.ico"
313+ className = "w-full px-3 md:px-5 py-2.5 md:py-4 bg-gray-50 dark:bg-gray-700 border border-gray-100 dark:border-gray-600 text-gray-900 dark:text-gray-100 rounded-lg md:rounded-2xl focus:ring-2 md:focus:ring-4 focus:ring-indigo-50 dark:focus:ring-indigo-900/30 outline-none transition-all"
314+ />
315+ < p className = "mt-2 text-[10px] text-gray-400 dark:text-gray-500 font-bold uppercase tracking-widest italic" > { t . settings . siteIconHint } </ p >
316+ </ div >
317+ < div >
318+ < label className = "block text-xs md:text-sm font-black text-gray-900 dark:text-gray-100 uppercase tracking-widest mb-2 md:mb-3" > { t . settings . siteDescription } </ label >
319+ < textarea
320+ value = { siteDescription }
321+ onChange = { ( e ) => setSiteDescription ( e . target . value ) }
322+ rows = { 3 }
323+ placeholder = "例如:分享技术、生活与思考的个人博客"
324+ className = "w-full px-3 md:px-5 py-2.5 md:py-4 bg-gray-50 dark:bg-gray-700 border border-gray-100 dark:border-gray-600 text-gray-900 dark:text-gray-100 rounded-lg md:rounded-2xl focus:ring-2 md:focus:ring-4 focus:ring-indigo-50 dark:focus:ring-indigo-900/30 outline-none resize-none transition-all font-medium leading-relaxed"
325+ />
326+ < p className = "mt-2 text-[10px] text-gray-400 dark:text-gray-500 font-bold uppercase tracking-widest italic" > { t . settings . siteDescriptionHint } </ p >
327+ </ div >
328+ </ div >
329+ </ motion . section >
242330 </ div >
243331
244332 < aside className = "space-y-4 md:space-y-8" >
@@ -278,7 +366,7 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
278366 < div className = "flex gap-2" >
279367 < button
280368 onClick = { handleSaveConfig }
281- disabled = { savingConfig || savingProfile }
369+ disabled = { savingConfig || savingProfile || savingSiteSettings }
282370 className = "flex-1 flex items-center justify-center px-4 py-3 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-xl font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
283371 >
284372 { savingConfig ? (
@@ -295,7 +383,7 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
295383 </ button >
296384 < button
297385 onClick = { handleSaveProfile }
298- disabled = { savingConfig || savingProfile }
386+ disabled = { savingConfig || savingProfile || savingSiteSettings }
299387 className = "flex-1 flex items-center justify-center px-4 py-3 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-xl font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
300388 >
301389 { savingProfile ? (
@@ -310,6 +398,23 @@ const Settings: React.FC<SettingsProps> = ({ config, profile, onSaveConfig, onSa
310398 </ >
311399 ) }
312400 </ button >
401+ < button
402+ onClick = { handleSaveSiteSettings }
403+ disabled = { savingConfig || savingProfile || savingSiteSettings }
404+ className = "flex-1 flex items-center justify-center px-4 py-3 border-2 border-indigo-300 dark:border-indigo-700 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 rounded-xl font-black hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-all active:scale-95 disabled:opacity-50 uppercase tracking-widest text-xs"
405+ >
406+ { savingSiteSettings ? (
407+ < >
408+ < div className = "w-4 h-4 border-2 border-indigo-600 dark:text-indigo-400 border-t-transparent rounded-full animate-spin mr-2" > </ div >
409+ { t . settings . saving }
410+ </ >
411+ ) : (
412+ < >
413+ < Globe size = { 16 } className = "mr-1.5" />
414+ { t . settings . saveSiteSettings }
415+ </ >
416+ ) }
417+ </ button >
313418 </ div >
314419 </ motion . div >
315420 </ div >
0 commit comments