Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import ArtworkDetailPage from "./pages/ArtworkDetailPage";
import GalleryPage from "./pages/GalleryPage";
import Footer from "./components/Footer";
import ProtectedRoute from "./components/ProtectedRoute";
import { useThemeStore } from "./store/themeStore";

function App() {
const isDarkMode = useThemeStore((state) => state.isDarkMode);
// No footers for Login and CreateAccount Pages
const { pathname } = useLocation();
const showFooter = pathname !== "/login" && pathname !== "/create-account";

return (
<div className="flex min-h-dvh flex-col">
<div className={`flex min-h-dvh flex-col transition-colors duration-300 ${isDarkMode ? "dark bg-[#171615] text-[#f3f0ea] [color-scheme:dark]" : "bg-white text-[#292624] [color-scheme:light]"}`}>
<main>
<Routes>
<Route path="/" element={<HomePage />} />
Expand Down
Binary file added frontend/src/assets/hero3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/src/assets/hero4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions frontend/src/components/AddToGalleryModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function AddToGalleryModal({
role="dialog"
aria-modal="true"
aria-labelledby="add-to-gallery-title"
className="w-full max-w-md rounded-2xl bg-white p-6 shadow-lg"
className="w-full max-w-md rounded-2xl bg-white p-6 shadow-lg dark:bg-[#242321] dark:text-[#f3f0ea]"
>
<div className="flex items-center justify-between">
<h2 id="add-to-gallery-title" className="font-serif text-2xl">
Expand All @@ -144,16 +144,16 @@ export default function AddToGalleryModal({
type="button"
onClick={onClose}
aria-label="Close"
className="text-2xl text-gray-500 hover:text-black"
className="text-2xl text-gray-500 hover:text-black dark:text-gray-300 dark:hover:text-white"
>
×
</button>
</div>

{loading ? (
<p className="mt-6 text-gray-500">Loading galleries...</p>
<p className="mt-6 text-gray-500 dark:text-gray-400">Loading galleries...</p>
) : galleries.length === 0 ? (
<p className="mt-6 text-gray-500">
<p className="mt-6 text-gray-500 dark:text-gray-400">
You have not created any galleries yet.
</p>
) : (
Expand All @@ -163,7 +163,7 @@ export default function AddToGalleryModal({
key={gallery.id}
type="button"
onClick={() => void handleAddToGallery(gallery.id)}
className="rounded-lg border border-gray-200 px-4 py-3 text-left transition hover:bg-gray-100"
className="rounded-lg border border-gray-200 px-4 py-3 text-left transition hover:bg-gray-100 dark:border-[#504b46] dark:hover:bg-[#35322e]"
>
{gallery.title}
</button>
Expand Down
50 changes: 26 additions & 24 deletions frontend/src/components/ArtworkCard.css
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
.artwork-card {
min-width: 0;
padding: 16px;
border: 1px solid #dedede;
border-radius: 4px;
background: #fff;
color: #171717;
text-align: left;
}
@layer components {
.artwork-card {
min-width: 0;
padding: 16px;
border: 1px solid #dedede;
border-radius: 4px;
background: #fff;
color: #171717;
text-align: left;
}

.artwork-card__image,
.artwork-card__placeholder {
display: block;
width: 100%;
aspect-ratio: 4 / 5;
}
.artwork-card__image,
.artwork-card__placeholder {
display: block;
width: 100%;
aspect-ratio: 4 / 5;
}

.artwork-card__image {
object-fit: contain;
background: #f5f4f1;
}
.artwork-card__image {
object-fit: contain;
background: #f5f4f1;
}

.artwork-card__placeholder {
display: grid;
place-items: center;
background: #f5f4f1;
color: #595959;
.artwork-card__placeholder {
display: grid;
place-items: center;
background: #f5f4f1;
color: #595959;
}
}

.artwork-card__title {
Expand Down
58 changes: 45 additions & 13 deletions frontend/src/components/ArtworkCard.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
import { useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { Plus } from "lucide-react";
import type { Artwork } from "../types/Artwork";
import { useAuthStore } from "../store/authStore";
import AddToGalleryModal from "./AddToGalleryModal";
import "./ArtworkCard.css";

type ArtworkCardProps = {
artwork: Artwork;
showGalleryAction?: boolean;
};

function ArtworkImage({ src, alt }: { src: string; alt: string }) {
const [hasError, setHasError] = useState(false);

if (hasError) {
return <div className="artwork-card__placeholder">Image unavailable</div>;
return <div className="artwork-card__placeholder dark:bg-[#302e2a] dark:text-gray-300">Image unavailable</div>;
}

return (
<img
className="artwork-card__image"
src={src}
alt={alt}
loading="lazy"
onError={() => setHasError(true)}
/>
<div className="overflow-hidden">
<img
className="artwork-card__image bg-[#f5f4f1] transition-transform duration-300 ease-out group-hover:scale-[1.03] motion-reduce:transition-none dark:bg-[#302e2a]"
src={src}
alt={alt}
loading="lazy"
onError={() => setHasError(true)}
/>
</div>
);
}

export default function ArtworkCard({ artwork }: ArtworkCardProps) {
export default function ArtworkCard({ artwork, showGalleryAction = true }: ArtworkCardProps) {
const artist = artwork.artist_display?.trim() || "Unknown artist";
const location = useLocation();
const navigate = useNavigate();
const isLoggedIn = useAuthStore((state) => Boolean(state.token));
const [showGalleryModal, setShowGalleryModal] = useState(false);

// Made with AI help.
function rememberCataloguePosition() {
Expand All @@ -41,10 +50,11 @@ export default function ArtworkCard({ artwork }: ArtworkCardProps) {
}

return (
<article className="artwork-card">
<article className="artwork-card relative border-[#dedede] bg-white text-[#171717] dark:border-[#47433e] dark:bg-[#22211f] dark:text-[#f3f0ea]">
<Link
to={`/artworks/${artwork.id}`}
state={{ from: `${location.pathname}${location.search}`, scrollY: window.scrollY }}
className="group block"
state={{ from: `${location.pathname}${location.search}` }}
onClick={rememberCataloguePosition}
>
{artwork.image_url ? (
Expand All @@ -54,12 +64,34 @@ export default function ArtworkCard({ artwork }: ArtworkCardProps) {
alt={artwork.image_url || `${artwork.title} by ${artist}`}
/>
) : (
<div className="artwork-card__placeholder">Image unavailable</div>
<div className="artwork-card__placeholder dark:bg-[#302e2a] dark:text-gray-300">Image unavailable</div>
)}

<h3 className="artwork-card__title">{artwork.title}</h3>
<p className="artwork-card__artist">{artist}</p>
</Link>

{showGalleryAction && (
<button
type="button"
aria-label={isLoggedIn ? `Add ${artwork.title} to a gallery` : "Sign in to add this artwork to a gallery"}
title={isLoggedIn ? "Add to gallery" : "Sign in to add to a gallery"}
onClick={() => {
if (isLoggedIn) setShowGalleryModal(true);
else navigate("/login");
}}
className="absolute right-5 top-5 z-10 grid h-10 w-10 cursor-pointer place-items-center rounded-full border border-gray-300 bg-white/95 text-gray-700 shadow-sm transition hover:border-gray-500 hover:bg-white hover:text-black focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-700 dark:border-[#5b554e] dark:bg-[#292724]/95 dark:text-gray-200 dark:hover:border-gray-400 dark:hover:bg-[#35322e] dark:hover:text-white"
>
<Plus size={21} strokeWidth={1.7} aria-hidden="true" />
</button>
)}

{showGalleryAction && showGalleryModal && (
<AddToGalleryModal
artworkId={artwork.id}
onClose={() => setShowGalleryModal(false)}
/>
)}
</article>
);
}
4 changes: 3 additions & 1 deletion frontend/src/components/ArtworkGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import "./ArtworkGrid.css";
type ArtworkGridProps = {
artworks: Artwork[];
renderAction?: (artwork: Artwork) => ReactNode;
showGalleryActions?: boolean;
};

export default function ArtworkGrid({
artworks,
renderAction,
showGalleryActions = true,
}: ArtworkGridProps) {
if (artworks.length === 0) {
return <p>No artworks to display.</p>;
Expand All @@ -20,7 +22,7 @@ export default function ArtworkGrid({
<ul className="artwork-grid" aria-label="Artwork results" role="list">
{artworks.map((artwork) => (
<li key={artwork.id} className="relative">
<ArtworkCard artwork={artwork} />
<ArtworkCard artwork={artwork} showGalleryAction={showGalleryActions} />
{renderAction?.(artwork)}
</li>
))}
Expand Down
Loading