Remove DaisyUI and replace with standard Tailwind classes - Replace btn-primary with bg-blue-600 hover:bg-blue-700 - Replace badge classes with custom Tailwind badge styling - Replace checkbox-primary with standard checkbox styling - Replace text-primary with text-blue-600 - Replace card classes with custom styling - Update ProductCard component styling

This commit is contained in:
2025-06-30 20:47:49 -04:00
parent b2ada8d81e
commit 926df49f4c
8 changed files with 192 additions and 54 deletions

View File

@@ -17,7 +17,7 @@ export default function ForgotPasswordPage() {
<h1 className="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Forgot your password?</h1>
<p className="mb-6 text-gray-600 dark:text-gray-300 text-sm">
Enter your email address and we'll send you a link to reset your password.<br/>
<span className="text-primary font-semibold">(This feature is not yet implemented.)</span>
<span className="text-blue-600 font-semibold">(This feature is not yet implemented.)</span>
</p>
<form onSubmit={handleSubmit} className="space-y-4">
<input
@@ -31,14 +31,14 @@ export default function ForgotPasswordPage() {
/>
<button
type="submit"
className="w-full btn btn-primary"
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium text-sm py-2 px-4 rounded-md transition-colors"
disabled={submitted}
>
{submitted ? 'Check your email' : 'Send reset link'}
</button>
</form>
<div className="mt-6 text-center">
<Link href="/account/login" className="text-primary-600 hover:underline text-sm">Back to login</Link>
<Link href="/account/login" className="text-blue-600 hover:underline text-sm">Back to login</Link>
</div>
</div>
</div>

View File

@@ -55,7 +55,7 @@ export default function LoginPage() {
<h2 className="mt-6 text-3xl font-extrabold text-gray-900 dark:text-white">Sign in to your account</h2>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
Or{' '}
<Link href="/account/register" className="font-medium text-primary-600 hover:text-primary-500">
<Link href="/account/register" className="font-medium text-blue-600 hover:text-blue-500">
Sign Up For Free
</Link>
</p>
@@ -109,7 +109,7 @@ export default function LoginPage() {
id="remember-me"
name="remember-me"
type="checkbox"
className="checkbox checkbox-primary"
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
disabled={loading}
/>
<label htmlFor="remember-me" className="ml-2 block text-sm text-gray-900 dark:text-gray-300">
@@ -118,7 +118,7 @@ export default function LoginPage() {
</div>
<div className="text-sm">
<Link href="/account/forgot-password" className="font-medium text-primary-600 hover:text-primary-500">
<Link href="/account/forgot-password" className="font-medium text-blue-600 hover:text-blue-500">
Forgot your password?
</Link>
</div>
@@ -127,7 +127,7 @@ export default function LoginPage() {
<div>
<button
type="submit"
className="w-full btn btn-primary text-white font-medium text-sm py-2 px-4 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium text-sm py-2 px-4 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
disabled={loading}
>
{loading ? 'Signing in...' : 'Sign in'}

View File

@@ -79,14 +79,14 @@ export default function RegisterPage() {
{error && <div className="text-red-600 text-sm">{error}</div>}
<button
type="submit"
className="w-full btn btn-primary text-white font-medium text-sm py-2 px-4 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium text-sm py-2 px-4 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
disabled={loading}
>
{loading ? 'Creating account...' : 'Create Account'}
</button>
</form>
<div className="mt-6 text-center">
<Link href="/account/login" className="text-primary-600 hover:underline text-sm">Already have an account? Sign in</Link>
<Link href="/account/login" className="text-blue-600 hover:underline text-sm">Already have an account? Sign in</Link>
</div>
</div>
</div>

View File

@@ -725,7 +725,7 @@ export default function BuildPage() {
) : (
<Link
href={`/parts?category=${encodeURIComponent(getProductCategoryForComponent(component.name))}`}
className="btn btn-primary btn-sm"
className="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded-md text-sm font-medium transition-colors"
>
Find Parts
</Link>

View File

@@ -34,7 +34,7 @@ export default function LandingPage() {
<div className="mt-10 flex items-top gap-x-6">
<Link
href="/build"
className="btn btn-primary text-base font-semibold px-6"
className="bg-blue-600 hover:bg-blue-700 text-white text-base font-semibold px-6 py-3 rounded-md transition-colors"
>
Get Building
</Link>

View File

@@ -227,6 +227,123 @@ const getMatchingComponentName = (productCategory: string): string => {
return categoryToComponentType[productCategory] || '';
};
// Pagination Component
const Pagination = ({
currentPage,
totalPages,
onPageChange,
itemsPerPage,
onItemsPerPageChange,
totalItems,
startIndex,
endIndex
}: {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
itemsPerPage: number;
onItemsPerPageChange: (items: number) => void;
totalItems: number;
startIndex: number;
endIndex: number;
}) => {
const getPageNumbers = () => {
const pages = [];
const maxVisiblePages = 5;
if (totalPages <= maxVisiblePages) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
if (currentPage <= 3) {
for (let i = 1; i <= 4; i++) {
pages.push(i);
}
pages.push('...');
pages.push(totalPages);
} else if (currentPage >= totalPages - 2) {
pages.push(1);
pages.push('...');
for (let i = totalPages - 3; i <= totalPages; i++) {
pages.push(i);
}
} else {
pages.push(1);
pages.push('...');
for (let i = currentPage - 1; i <= currentPage + 1; i++) {
pages.push(i);
}
pages.push('...');
pages.push(totalPages);
}
}
return pages;
};
return (
<div className="flex flex-col sm:flex-row justify-between items-center gap-4 py-4 px-6 bg-white border-t border-zinc-200">
{/* Items per page selector */}
<div className="flex items-center gap-2 text-sm text-zinc-600">
<span>Show:</span>
<select
value={itemsPerPage}
onChange={(e) => onItemsPerPageChange(Number(e.target.value))}
className="border border-zinc-300 rounded px-2 py-1 text-sm"
>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
<option value={100}>100</option>
</select>
<span>per page</span>
</div>
{/* Page info */}
<div className="text-sm text-zinc-600">
Showing {startIndex + 1} to {Math.min(endIndex, totalItems)} of {totalItems} results
</div>
{/* Pagination controls */}
<div className="flex items-center gap-1">
<button
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
className="px-3 py-1 text-sm border border-zinc-300 rounded hover:bg-zinc-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
Previous
</button>
{getPageNumbers().map((page, index) => (
<button
key={index}
onClick={() => typeof page === 'number' ? onPageChange(page) : null}
disabled={page === '...'}
className={`px-3 py-1 text-sm border rounded ${
page === currentPage
? 'bg-primary-600 text-white border-primary-600'
: page === '...'
? 'border-zinc-300 text-zinc-400 cursor-default'
: 'border-zinc-300 hover:bg-zinc-50'
}`}
>
{page}
</button>
))}
<button
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
className="px-3 py-1 text-sm border border-zinc-300 rounded hover:bg-zinc-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
Next
</button>
</div>
</div>
);
};
export default function Home() {
const searchParams = useSearchParams();
const router = useRouter();
@@ -247,6 +364,10 @@ export default function Home() {
const [viewMode, setViewMode] = useState<'table' | 'cards'>('table');
const [addedPartIds, setAddedPartIds] = useState<string[]>([]);
const [isSearchExpanded, setIsSearchExpanded] = useState(false);
// Pagination state
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(20);
const selectPartForComponent = useBuildStore((state) => state.selectPartForComponent);
const selectedParts = useBuildStore((state) => state.selectedParts);
const removePartForComponent = useBuildStore((state) => state.removePartForComponent);
@@ -386,6 +507,17 @@ export default function Home() {
}
});
// Pagination logic
const totalPages = Math.ceil(sortedParts.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const paginatedParts = sortedParts.slice(startIndex, endIndex);
// Reset to first page when filters change
useEffect(() => {
setCurrentPage(1);
}, [selectedCategoryId, selectedSubcategoryId, selectedBrand, selectedVendor, searchTerm, priceRange, selectedRestriction, sortField, sortDirection]);
const handleSort = (field: SortField) => {
if (sortField === field) {
setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
@@ -648,7 +780,7 @@ export default function Home() {
{/* View Toggle and Results Count */}
<div className="flex justify-between items-center mb-6">
<div className="text-sm text-zinc-700">
{loading ? 'Loading...' : `Showing ${sortedParts.length} of ${products.length} parts`}
{loading ? 'Loading...' : `Showing ${startIndex + 1}-${Math.min(endIndex, sortedParts.length)} of ${sortedParts.length} parts`}
{hasActiveFilters && !loading && (
<span className="ml-2 text-primary-600">
(filtered)
@@ -707,7 +839,7 @@ export default function Home() {
</tr>
</thead>
<tbody className="bg-white divide-y divide-zinc-200">
{sortedParts.map((part) => (
{paginatedParts.map((part) => (
<tr key={part.id} className="hover:bg-zinc-50 transition-colors">
<td className="px-0 py-2 flex items-center gap-2 align-top">
<div className="w-12 h-12 flex-shrink-0 rounded bg-zinc-100 overflow-hidden flex items-center justify-center border border-zinc-200">
@@ -782,26 +914,30 @@ export default function Home() {
</table>
</div>
{/* Table Footer */}
<div className="bg-zinc-50 px-6 py-3 border-t border-zinc-200">
<div className="flex items-center justify-between">
<div className="text-sm text-zinc-700">
Showing {sortedParts.length} of {products.length} parts
{hasActiveFilters && (
<span className="ml-2 text-primary-600">
(filtered)
</span>
)}
</div>
</div>
</div>
</div>
)}
{/* Pagination */}
{totalPages > 1 && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={setCurrentPage}
itemsPerPage={itemsPerPage}
onItemsPerPageChange={(items) => {
setItemsPerPage(items);
setCurrentPage(1); // Reset to first page when changing items per page
}}
totalItems={sortedParts.length}
startIndex={startIndex}
endIndex={endIndex}
/>
)}
{/* Card View */}
{viewMode === 'cards' && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{sortedParts.map((part) => (
{paginatedParts.map((part) => (
<ProductCard key={part.id} product={part} onAdd={() => handleAdd(part)} added={addedPartIds.includes(part.id)} />
))}
</div>