Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 186 additions & 17 deletions app/brokenArtifacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import artifactDb from "@/db.json";

const BrokenArtifacts = () => {
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [isTransitioning, setIsTransitioning] = useState(false);
const itemsPerPage = 10;

const filteredArtifacts = useMemo(() => {
return Object.entries(artifactDb.brokenArtifacts)
Expand All @@ -26,9 +29,96 @@ const BrokenArtifacts = () => {
});
}, [searchQuery]);

// Reset to first page when search changes
useMemo(() => {
setCurrentPage(1);
}, [searchQuery]);

const totalPages = Math.ceil(filteredArtifacts.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentArtifacts = filteredArtifacts.slice(startIndex, endIndex);

const handlePageChange = (page: number) => {
if (page === currentPage || isTransitioning) return;

setIsTransitioning(true);

// Add a small delay to allow fade out animation
setTimeout(() => {
setCurrentPage(page);
// Reset transition state after content changes
setTimeout(() => {
setIsTransitioning(false);
}, 50);
}, 150);
};

const renderPaginationButtons = () => {
if (totalPages <= 1) return null;

const buttons = [];
const maxVisiblePages = 5;

let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);

if (endPage - startPage + 1 < maxVisiblePages) {
startPage = Math.max(1, endPage - maxVisiblePages + 1);
}

// Previous button
if (currentPage > 1) {
buttons.push(
<button
key="prev"
onClick={() => handlePageChange(currentPage - 1)}
disabled={isTransitioning}
className="px-3 py-1 text-sm bg-zinc-800 hover:bg-zinc-700 text-white rounded transition-all duration-200 hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed"
>
</button>
);
}

// Page numbers
for (let i = startPage; i <= endPage; i++) {
buttons.push(
<button
key={i}
onClick={() => handlePageChange(i)}
disabled={isTransitioning}
className={`px-3 py-1 text-sm rounded transition-all duration-200 hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed ${
i === currentPage
? "bg-blue-600 text-white shadow-lg"
: "bg-zinc-800 hover:bg-zinc-700 text-white"
}`}
>
{i}
</button>
);
}

// Next button
if (currentPage < totalPages) {
buttons.push(
<button
key="next"
onClick={() => handlePageChange(currentPage + 1)}
disabled={isTransitioning}
className="px-3 py-1 text-sm bg-zinc-800 hover:bg-zinc-700 text-white rounded transition-all duration-200 hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed"
>
</button>
);
}

return buttons;
};

return (
<div>
<div className="border border-zinc-800 p-3 mb-3 bg-zinc-950 rounded flex gap-3 items-center">
<div className="border border-zinc-800 p-3 mb-4 bg-zinc-950 rounded flex gap-3 items-center">
<svg fill="#bbb" height="15px" width="15px" viewBox="0 0 488.4 488.4">
<g>
<g>
Expand All @@ -52,10 +142,26 @@ const BrokenArtifacts = () => {
/>
</div>

{!filteredArtifacts.length ? (
<div className="border border-zinc-800 p-2 mb-3 bg-zinc-900 rounded cursor-pointer">
<code className="leading-5">
<span className="text-xs font-sans bg-green-600 p-1 px-1 mr-1 font-bold rounded border border-opacity-30 border-zinc-900 whitespace-nowrap">
{/* Results summary */}
{searchQuery && (
<div className="mb-3 text-xs text-gray-400 transition-opacity duration-300">
{filteredArtifacts.length > 0
? `Found ${filteredArtifacts.length} result${filteredArtifacts.length !== 1 ? 's' : ''}`
: 'No results found'
}
</div>
)}

{!searchQuery && filteredArtifacts.length > 0 && (
<div className="mb-3 text-xs text-gray-400 transition-opacity duration-300">
Showing {startIndex + 1}-{Math.min(endIndex, filteredArtifacts.length)} of {filteredArtifacts.length} artifacts
</div>
)}

{!filteredArtifacts.length && searchQuery ? (
<div className="border border-zinc-800 p-3 mb-4 bg-zinc-900 rounded animate-fade-in">
<div className="flex items-start gap-2">
<span className="text-xs font-sans bg-green-600 p-1 px-2 font-bold rounded border border-opacity-30 border-zinc-900 whitespace-nowrap flex-shrink-0">
OK
</span>
<span className="text-sm font-sans break-words">
Expand All @@ -65,23 +171,86 @@ const BrokenArtifacts = () => {
</strong>{" "}
has not had any reported issues.
</span>
</code>
</div>
</div>
) : (
filteredArtifacts.map(([key, value]) => (
<div
key={key}
className="border border-zinc-800 p-2 mb-3 bg-zinc-900 rounded cursor-pointer"
<>
<div
className={`space-y-2 mb-4 transition-all duration-300 ${
isTransitioning
? 'opacity-0 transform translate-y-2'
: 'opacity-100 transform translate-y-0'
}`}
style={{ minHeight: '400px' }}
>
<code className="leading-5">
<span className="text-xs font-sans bg-red-500 p-1 px-1 mr-1 font-bold rounded border border-opacity-30 border-zinc-900 whitespace-nowrap">
{key}
</span>
<span className="text-sm font-sans break-words">{value}</span>
</code>
{currentArtifacts.map(([key, value], index) => (
<div
key={key}
className="border border-zinc-800 p-3 bg-zinc-900 rounded hover:bg-zinc-800 transition-all duration-200 hover:scale-[1.01] hover:shadow-lg animate-slide-in"
style={{
animationDelay: `${index * 50}ms`,
animationFillMode: 'both'
}}
>
<div className="flex items-start gap-2">
<span className="text-xs font-sans bg-red-500 p-1 px-2 font-bold rounded border border-opacity-30 border-zinc-900 whitespace-nowrap flex-shrink-0">
{key}
</span>
<span className="text-sm font-sans break-words leading-relaxed">
{value}
</span>
</div>
</div>
))}
</div>
))

{/* Pagination */}
{totalPages > 1 && (
<div className="flex justify-center items-center gap-2 mt-6">
{renderPaginationButtons()}
</div>
)}

{/* Page info */}
{totalPages > 1 && (
<div className="text-center text-xs text-gray-400 mt-3 transition-opacity duration-300">
Page {currentPage} of {totalPages}
</div>
)}
</>
)}

<style jsx>{`
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

@keyframes slide-in {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}

.animate-fade-in {
animation: fade-in 0.4s ease-out;
}

.animate-slide-in {
animation: slide-in 0.4s ease-out;
}
`}</style>
</div>
);
};
Expand Down