HaoAws/components/TDKConfigManager.tsx
2025-09-16 16:37:48 +08:00

231 lines
8.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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>
);
}