kanban-app/frontend/src/pages/BoardWikis.tsx

159 lines
5.7 KiB
TypeScript
Raw Normal View History

2026-03-22 11:52:33 +00:00
import { useParams, Link, useNavigate } from 'react-router-dom';
import { WidePageLayout } from '../components/WidePageLayout';
import RichTextContent from '../components/RichTextContent';
import useWikis from '../hooks/useWikis';
import type { Wiki } from '../types/epic';
import PlusIcon from '../components/icons/PlusIcon';
import Edit2Icon from '../components/icons/Edit2Icon';
import Trash2Icon from '../components/icons/Trash2Icon';
export function BoardWikis() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { wikis, deleteWiki } = useWikis(id || '0');
const handleDeleteWiki = async (wikiId: number, wikiName: string) => {
if (confirm(`Are you sure you want to delete wiki "${wikiName}"?`)) {
try {
await deleteWiki(wikiId);
} catch {
// Error is handled by the hook
}
}
};
return (
<div className="space-y-6">
<WidePageLayout>
<div className="flex items-center justify-between">
<div>
<Link
to={`/boards/${id}`}
className="text-gray-400 hover:text-white transition-colors text-sm"
>
Back to Board
</Link>
<h1 className="text-3xl font-bold text-white mt-2">Wikis</h1>
<p className="text-gray-400 mt-1">
Manage and view wikis for this board ({wikis.length} wikis)
</p>
</div>
<Link
to={`/boards/${id}/wikis/new`}
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition-colors"
>
<PlusIcon className="w-4 h-4" />
Create Wiki
</Link>
</div>
</WidePageLayout>
<WidePageLayout>
{wikis.length === 0 ? (
<div className="bg-gray-800 rounded-lg p-8 border border-gray-700">
<div className="text-center py-12">
<div className="text-6xl mb-4">📚</div>
<h2 className="text-xl font-bold text-white mb-2">No Wikis Yet</h2>
<p className="text-gray-400 mb-6">
Create your first wiki to start documenting your knowledge.
</p>
<Link
to={`/boards/${id}/wikis/new`}
className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg inline-flex items-center gap-2 transition-colors"
>
<PlusIcon className="w-4 h-4" />
Create First Wiki
</Link>
</div>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{wikis.map((wiki) => (
<WikiCard
key={wiki.id}
wiki={wiki}
onClick={() => navigate(`/boards/${id}/wikis/${wiki.id}`)}
onDelete={() => handleDeleteWiki(wiki.id, wiki.name)}
onEdit={() => navigate(`/boards/${id}/wikis/${wiki.id}/edit`)}
/>
))}
</div>
)}
</WidePageLayout>
</div>
);
}
interface WikiCardProps {
wiki: Wiki;
onClick: () => void;
onDelete: () => void;
onEdit: () => void;
}
function WikiCard({ wiki, onClick, onDelete, onEdit }: WikiCardProps) {
return (
<div
className="bg-gray-800 rounded-lg border border-gray-700 hover:border-gray-600 transition-all cursor-pointer overflow-hidden group"
onClick={onClick}
>
<div className="p-4">
{/* Header with actions */}
<div className="flex items-start justify-between mb-2">
<h3 className="text-lg font-semibold text-white flex-1">{wiki.name}</h3>
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
<button
onClick={(e) => {
e.stopPropagation();
onEdit();
}}
className="text-gray-400 hover:text-white transition-colors p-1"
title="Edit wiki"
>
<Edit2Icon className="w-4 h-4" />
</button>
<button
onClick={(e) => {
e.stopPropagation();
onDelete();
}}
className="text-gray-400 hover:text-red-400 transition-colors p-1"
title="Delete wiki"
>
<Trash2Icon className="w-4 h-4" />
</button>
</div>
</div>
{/* Summary */}
{wiki.summary && <p className="text-gray-400 text-sm mb-3 line-clamp-2">{wiki.summary}</p>}
{/* Rich text content preview */}
{wiki.content && Array.isArray(wiki.content) && wiki.content.length > 0 && (
<div className="mb-3 max-h-[120px] overflow-hidden relative">
<RichTextContent
content={wiki.content}
className="text-sm text-gray-400 line-clamp-3"
/>
{/* Fade overlay at bottom */}
<div className="absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-gray-800 to-transparent pointer-events-none" />
</div>
)}
{/* Footer with metadata */}
<div className="flex items-center justify-between text-xs text-gray-500 mt-3 pt-3 border-t border-gray-700">
<div className="flex items-center gap-4">
{wiki.category && (
<span className="px-2 py-1 bg-gray-700 text-gray-400 rounded">{wiki.category}</span>
)}
{wiki.tags && wiki.tags.length > 0 && <span>{wiki.tags.length} tag(s)</span>}
</div>
{wiki.updated_at && <span>{new Date(wiki.updated_at).toLocaleDateString()}</span>}
</div>
</div>
</div>
);
}
export default BoardWikis;