HaoAws/components/TDKConfigManager.tsx

231 lines
8.9 KiB
TypeScript
Raw Normal View History

2025-09-16 16:37:48 +08:00
'use client';
import { Locale } from '@/lib/i18n';
import { getSEOData, SEOData } from '@/lib/seo';
import { useEffect, useState } from 'react';
interface TDKConfigManagerProps {
locale: Locale;
page: string;
onSave?: (data: SEOData) => void;
className?: string;
}
export default function TDKConfigManager({
locale,
page,
onSave,
className = '',
}: TDKConfigManagerProps) {
const [seoData, setSeoData] = useState<SEOData>({
title: '',
description: '',
keywords: [],
});
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [newKeyword, setNewKeyword] = useState('');
useEffect(() => {
const loadSEOData = async () => {
try {
setLoading(true);
const data = await getSEOData(locale, page);
setSeoData(data);
} catch (error) {
console.error('Failed to load SEO data:', error);
} finally {
setLoading(false);
}
};
loadSEOData();
}, [locale, page]);
const handleSave = async () => {
if (onSave) {
setSaving(true);
try {
await onSave(seoData);
alert(
locale === 'zh-CN'
? '保存成功!'
: locale === 'zh-TW'
? '儲存成功!'
: 'Saved successfully!',
);
} catch (error) {
alert(
locale === 'zh-CN'
? '保存失败!'
: locale === 'zh-TW'
? '儲存失敗!'
: 'Save failed!',
);
} finally {
setSaving(false);
}
}
};
const addKeyword = () => {
if (newKeyword.trim() && !seoData.keywords.includes(newKeyword.trim())) {
setSeoData({
...seoData,
keywords: [...seoData.keywords, newKeyword.trim()],
});
setNewKeyword('');
}
};
const removeKeyword = (index: number) => {
setSeoData({
...seoData,
keywords: seoData.keywords.filter((_, i) => i !== index),
});
};
if (loading) {
return (
<div className={`animate-pulse ${className}`}>
<div className="space-y-4">
<div className="h-4 bg-gray-200 rounded"></div>
<div className="h-20 bg-gray-200 rounded"></div>
<div className="h-4 bg-gray-200 rounded"></div>
</div>
</div>
);
}
return (
<div className={`tdk-config-manager ${className}`}>
<h3 className="text-lg font-semibold mb-4">
{locale === 'zh-CN'
? 'TDK配置管理'
: locale === 'zh-TW'
? 'TDK配置管理'
: 'TDK Configuration'}
</h3>
<div className="space-y-4">
{/* Title */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
{locale === 'zh-CN' ? '标题' : locale === 'zh-TW' ? '標題' : 'Title'}
</label>
<input
type="text"
value={seoData.title}
onChange={(e) => setSeoData({ ...seoData, title: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder={
locale === 'zh-CN'
? '输入页面标题'
: locale === 'zh-TW'
? '輸入頁面標題'
: 'Enter page title'
}
/>
<div className="text-xs text-gray-500 mt-1">
{seoData.title.length}/60{' '}
{locale === 'zh-CN' ? '字符' : locale === 'zh-TW' ? '字元' : 'characters'}
</div>
</div>
{/* Description */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
{locale === 'zh-CN' ? '描述' : locale === 'zh-TW' ? '描述' : 'Description'}
</label>
<textarea
value={seoData.description}
onChange={(e) => setSeoData({ ...seoData, description: e.target.value })}
rows={3}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder={
locale === 'zh-CN'
? '输入页面描述'
: locale === 'zh-TW'
? '輸入頁面描述'
: 'Enter page description'
}
/>
<div className="text-xs text-gray-500 mt-1">
{seoData.description.length}/160{' '}
{locale === 'zh-CN' ? '字符' : locale === 'zh-TW' ? '字元' : 'characters'}
</div>
</div>
{/* Keywords */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
{locale === 'zh-CN' ? '关键词' : locale === 'zh-TW' ? '關鍵詞' : 'Keywords'}
</label>
<div className="flex gap-2 mb-2">
<input
type="text"
value={newKeyword}
onChange={(e) => setNewKeyword(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addKeyword()}
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder={
locale === 'zh-CN'
? '添加关键词'
: locale === 'zh-TW'
? '新增關鍵詞'
: 'Add keyword'
}
/>
<button
onClick={addKeyword}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
{locale === 'zh-CN' ? '添加' : locale === 'zh-TW' ? '新增' : 'Add'}
</button>
</div>
<div className="flex flex-wrap gap-2">
{seoData.keywords.map((keyword, index) => (
<span
key={index}
className="inline-flex items-center gap-1 bg-blue-100 text-blue-800 text-sm px-2 py-1 rounded"
>
{keyword}
<button
onClick={() => removeKeyword(index)}
className="text-blue-600 hover:text-blue-800"
>
×
</button>
</span>
))}
</div>
</div>
{/* Save Button */}
{onSave && (
<button
onClick={handleSave}
disabled={saving}
className="w-full px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 disabled:opacity-50"
>
{saving
? locale === 'zh-CN'
? '保存中...'
: locale === 'zh-TW'
? '儲存中...'
: 'Saving...'
: locale === 'zh-CN'
? '保存配置'
: locale === 'zh-TW'
? '儲存配置'
: 'Save Configuration'}
</button>
)}
</div>
</div>
);
}