Xianbao QIAN
add mr-4 for fr to align the text
2bcc20e
import React, { useState } from "react";
import { PolicyData } from "../types";
interface AIPoliciesTableProps {
policies: PolicyData[];
}
const AIPoliciesTable: React.FC<AIPoliciesTableProps> = ({ policies }) => {
const initialOpenYears = policies.reduce((acc, policy) => {
const year = new Date(policy.releaseDate).getFullYear();
acc[year] = true;
return acc;
}, {} as { [key: number]: boolean });
const [openYears, setOpenYears] = useState<{ [key: number]: boolean }>(initialOpenYears);
const toggleYear = (year: number) => {
setOpenYears((prev) => ({ ...prev, [year]: !prev[year] }));
};
const uniqueTags = Array.from(new Set(policies.flatMap(policy => policy.tags.map(tag => tag.toLowerCase())))).map(tag => tag.charAt(0).toUpperCase() + tag.slice(1));
const [selectedTags, setSelectedTags] = useState<string[]>(uniqueTags);
const handleTagChange = (tag: string) => {
if (selectedTags.includes(tag)) {
setSelectedTags(selectedTags.filter(t => t !== tag));
} else {
setSelectedTags([...selectedTags, tag]);
}
};
const filteredPolicies = selectedTags.length === 0
? policies
: policies.filter(policy => policy.tags.some(tag => selectedTags.includes(tag.charAt(0).toUpperCase() + tag.slice(1))));
const groupedPolicies = filteredPolicies.reduce((acc, policy) => {
const year = new Date(policy.releaseDate).getFullYear();
if (!acc[year]) {
acc[year] = [];
}
acc[year].push(policy);
return acc;
}, {} as { [key: number]: PolicyData[] });
const sortedYears = Object.keys(groupedPolicies)
.map(Number)
.sort((a, b) => b - a);
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', year: 'numeric' };
return date.toLocaleDateString('en-US', options);
};
return (
<div className="container mx-auto p-6">
<div className="mb-6 flex justify-center">
{uniqueTags.map(tag => (
<label key={tag} className="inline-flex items-center mr-4">
<input
type="checkbox"
className="form-checkbox h-5 w-5 text-blue-600"
checked={selectedTags.includes(tag)}
onChange={() => handleTagChange(tag)}
/>
<span className="ml-2 text-gray-700 dark:text-gray-400">{tag}</span>
</label>
))}
</div>
{sortedYears.map((year) => (
<div key={year} className="mb-12">
<button
onClick={() => toggleYear(year)}
className="text-2xl font-semibold mb-6 focus:outline-none text-gray-800 dark:text-white"
>
{year} {openYears[year] ? "▲" : "▼"}
</button>
{openYears[year] && (
<table className="w-full border-collapse table-auto shadow-lg rounded-lg">
<tbody>
{groupedPolicies[year].map((policy, index) => (
<tr
key={`${year}-${index}`}
className={`${
index % 2 === 0 ? "bg-gray-300" : "bg-gray-500"
} dark:${
index % 2 === 0 ? "bg-gray-700" : "bg-gray-900"
} border-b border-gray-200 dark:border-gray-700`}
>
<td className="py-6 px-6 text-gray-900 dark:text-white">
<div className="text-lg font-medium">{policy.zh}</div>
<div className="text-sm text-gray-500 dark:text-gray-400 mt-2">
{policy.en}
</div>
<div className="text-xs text-gray-400 dark:text-gray-500 mt-2">
{formatDate(policy.releaseDate)}
</div>
<div className="text-xs text-gray-400 dark:text-gray-500 mt-2">
{policy.tags.map(tag => tag.charAt(0).toUpperCase() + tag.slice(1)).join(', ')}
</div>
</td>
<td className="py-6 px-6 text-right">
{policy.link.zh && (
<a
href={policy.link.zh}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline dark:text-blue-400 mr-4"
>
中文
</a>
)}
{policy.link.en && (
<a
href={policy.link.en}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline dark:text-blue-400 mr-4"
>
English
</a>
)}
{policy.link.fr && (
<a
href={policy.link.fr}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline dark:text-blue-400 mr-4"
>
Français
</a>
)}
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
))}
</div>
);
};
export default AIPoliciesTable;