Skip to content

Commit

Permalink
feat: add painting sales info & status info to zoom view
Browse files Browse the repository at this point in the history
  • Loading branch information
mrzzy committed Jul 23, 2024
1 parent 6d39e8a commit 1a0ef44
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 27 deletions.
4 changes: 2 additions & 2 deletions components/gallery/thumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import SmoothImage from "@/components/ui/smooth-image"
* @param props.art Art piece to render in the gallery thumbnail
*
*/
export default function Thumbnail(props: { art: Art, onClick: () => void}) {
export default function Thumbnail(props: { art: Art, onClick: () => void }) {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
Expand All @@ -31,7 +31,7 @@ export default function Thumbnail(props: { art: Art, onClick: () => void}) {
(orientation === Orientation.Horizontal ? colSpan : 1) * colWidth;
const imgHeight = imgWidth / aspect(width, height);
return (
<div className={`group col-span-${colSpan} relative`} onClick={props.onClick}>
<div className={`group relative`} onClick={props.onClick}>
{isClient ? (
<SmoothImage
className={`object-cover group-hover:brightness-75 group-active:brightness-50 h-full`}
Expand Down
43 changes: 37 additions & 6 deletions components/gallery/zoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,65 @@ import {
DialogContent,
} from "@/components/ui/dialog";

import { Art } from "@/lib/models";
import { Art, Status } from "@/lib/models";
import ExportedImage from "next-image-export-optimizer";
import zzyLogo from "@/public/images/icons/art_mrzzy_co_logo-white.svg";
import { useWindowSize } from "@uidotdev/usehooks";
import Metadata from "@/components/ui/art-metadata";
import SmoothImage from "@/components/ui/smooth-image";
import { Button } from "../ui/button";

/**
* Renders a zoom view popup of the given Art piece
* @param props.art Art piece to render in the zoom view
* @param props.onClose Callback called when the dialog box closes
*/
export default function ZoomView(props: { art: Art, onClose: () => void }) {
const { image, title } = props.art;
const { image, title, listPrice, status } = props.art;
const isAvailable = status === Status.Available;
const { width, height } = useWindowSize();

let statusText = "Unavailable";
switch (status) {
case Status.Sold:
statusText = "Sold";
break;
case Status.Private:
statusText = "Private Collection";
break;
case Status.Available:
statusText = "Available";
break;
case Status.Exhibiting:
statusText = "Exhibiting";
}

// render sales info for when painting is available
const salesInfo = (<>
<span className="justify-self-end text-lg">S$${listPrice}</span>
<Button className="justify-self-end round bg-green">Inquire</Button>
</>);
// render painting status if otherwise not available
const statusInfo = (
<span className="justify-self-end font-bold text-slate-400">{statusText}</span>
);

return (
<Dialog modal={false} defaultOpen={true}>
<DialogContent className="bg-black text-white" onCloseAutoFocus={props.onClose}>
<Dialog defaultOpen={true}>
<DialogContent className="bg-black text-white flex flex-col" onCloseAutoFocus={props.onClose}>
<ExportedImage src={zzyLogo} alt="Home" />
<SmoothImage
src={`/images${image}`}
className={`object-contain max-h-[80vh]`}
className="object-contain flex-1 max-h-[74vh]"
alt={title}
width={width || 1280}
height={height || 1080}
/>
<Metadata art={props.art} />
<div className="flex flex-row items-center mt-4 gap-x-4">
<Metadata art={props.art} />
<div className="grow"></div>
{isAvailable ? salesInfo : statusInfo}
</div>
</DialogContent>
</Dialog>
);
Expand Down
3 changes: 2 additions & 1 deletion components/ui/art-metadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { Art } from "@/lib/models";
/**
* Render the metadata for the given art piece
* @param props.art Art piece to render metadata for.
* @param props.status Optional. If set to true will show status of the piece.
*
*/
export default function Metadata(props: { art: Art }) {
// art title
const { title, height, width, medium, madeOn } = props.art;
return (
<div>
<h1 className="font-serif font-bold text-4xl ">{title}</h1>
<h1 className="font-serif font-bold text-6xl ">{title}</h1>
<div className="text-sm my-2 justify-self-start">
<p>
{height}mm x {width} mm
Expand Down
6 changes: 3 additions & 3 deletions components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
"inline-flex items-center justify-center whitespace-nowrap text-sm font-bold transition-colors focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
Expand All @@ -21,8 +21,8 @@ const buttonVariants = cva(
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
sm: "h-9 px-3",
lg: "h-11 px-8",
icon: "h-10 w-10",
},
},
Expand Down
11 changes: 10 additions & 1 deletion lib/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Models
*/


/** Orientation of the Art piece upright. */
export enum Orientation {
Vertical = "Vertical",
Expand All @@ -17,6 +16,15 @@ export enum Channel {
Website = "Website",
}

/** Defines status states of the Art piece */
export enum Status {
Available = "Available",
Exhibiting = "Exhbiting",
Sold = "Sold",
Private = "Private", // private collection
Missing = "Missing",
}

/** Art Sales information. */
export type Sale = {
channel: Channel;
Expand All @@ -39,6 +47,7 @@ export type Art = {
cost: string;
listPrice: string;
featured: boolean;
status: Status;
framingCost: string | null;
sale: Sale | null;
exhibited: string | null;
Expand Down
6 changes: 4 additions & 2 deletions lib/parsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@

import { describe, expect, test } from "@jest/globals";
import { parseArt } from "./parsing";
import { Orientation, Status } from "./models";

describe("parseArt()", () => {
test("Parses art.csv", async () => {
const records = await parseArt();
expect(records).toHaveLength(10);
expect(records).toHaveLength(13);
expect(records[0]).toStrictEqual({
cost: "5",
exhibited: null,
featured: false,
status: Status.Available,
framingCost: null,
height: 410,
id: "1",
Expand All @@ -23,7 +25,7 @@ describe("parseArt()", () => {
location: "Luggage",
madeOn: new Date("2024-07-16T00:00:00.000Z"),
medium: "Watercolor on paper",
orientation: "Vertical",
orientation: Orientation.Vertical,
sale: null,
title: "KL Dusk",
width: 310,
Expand Down
3 changes: 2 additions & 1 deletion lib/parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ export async function parseArt(
title: raw["Title"],
medium: raw["Medium"],
location: raw["Location"],
cost: raw["Cost"],
cost: raw["Painting Cost"],
listPrice: raw["List Price"],
featured: raw["Featured"].toLowerCase() === "true" ? true : false,
status: raw["Status"],
framingCost: raw["Framing Cost"].length > 0 ? raw["Framing Cost"] : null,
sale:
raw["Sold On"].length > 0
Expand Down
25 changes: 14 additions & 11 deletions public/art.csv
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
ID,Image,Orientation,Height (mm),Width (mm),Made On,Title,Medium,Location,Cost,Framing Cost,List Price,Featured,Exhibited,Sales Channel,Sold On,Sold Price,Bought By
1,/art/1.jpg,Vertical,410,310,2024-07-16,KL Dusk,Watercolor on paper,Luggage,5,,150,FALSE,,,,,
2,/art/2.jpg,Horizontal,180,260,2024-07-16,National Mosque,Watercolor on paper,Luggage,2.5,,50,FALSE,,,,,
3,/art/3.jpg,Horizontal,310,410,2024-07-16,St. John's Intitution,Watercolor on paper,Luggage,5,,250,TRUE,,,,,
4,/art/4.jpg,Vertical,410,310,2024-07-15,Merdeka!,Watercolor on paper,Luggage,5,,175,FALSE,,,,,
5,/art/5.jpg,Horizontal,310,410,2024-07-15,Sri Maha Mariamman Temple,Watercolor on paper,Luggage,5,,250,TRUE,,,,,
6,/art/6.jpg,Horizontal,310,410,2024-07-14,Thean Hou Temple,Watercolor on paper,Luggage,5,,200,FALSE,,,,,
7,/art/7.jpg,Horizontal,270,380,2024-06-29,The Calm Before the Storm,Watercolor on paper,Home,4,,150,FALSE,,,,,
8,/art/8.jpg,Vertical,380,270,2024-07-04,Holttum Hall,Watercolor on paper,Green Pavilion @ Singapore Botanical Gardens,4,,200,TRUE,Living Story: An Interactive Exhibition,,,,
9,/art/9.jpg,Horizontal,180,260,2024-07-02,Late Afternoon Tea,Watercolor on paper,Home,2.5,,50,FALSE,,,,,
10,/art/10.jpg,Vertical,380,270,2024-07-07,River Sparkle,Watercolor on paper,Home,4,,200,TRUE,,,,,
ID,Image,Orientation,Height (mm),Width (mm),Made On,Title,Medium,Location,Painting Cost,Framing Cost,List Price,Featured,Status,Exhibited,Sales Channel,Sold On,Sold Price,Bought By
1,/art/1.jpg,Vertical,410,310,2024-07-16,KL Dusk,Watercolor on paper,Luggage,5,,150,FALSE,Available,,,,,
2,/art/2.jpg,Horizontal,180,260,2024-07-16,National Mosque,Watercolor on paper,Luggage,2.5,,50,FALSE,Available,,,,,
3,/art/3.jpg,Horizontal,310,410,2024-07-16,St. John's Institution,Watercolor on paper,Luggage,5,,250,TRUE,Available,,,,,
4,/art/4.jpg,Vertical,410,310,2024-07-15,Merdeka!,Watercolor on paper,Luggage,5,,175,FALSE,Available,,,,,
5,/art/5.jpg,Horizontal,310,410,2024-07-15,Sri Maha Mariamman Temple,Watercolor on paper,Luggage,5,,250,TRUE,Available,,,,,
6,/art/6.jpg,Horizontal,310,410,2024-07-14,Thean Hou Temple,Watercolor on paper,Luggage,5,,200,FALSE,Available,,,,,
7,/art/7.jpg,Horizontal,270,380,2024-06-29,The Calm Before the Storm,Watercolor on paper,Home,4,,150,FALSE,Available,,,,,
8,/art/8.jpg,Vertical,380,270,2024-07-04,Holttum Hall,Watercolor on paper,Green Pavilion @ Singapore Botanical Gardens,4,,200,TRUE,Exhbiting,Living Story: An Interactive Exhibition,,,,
9,/art/9.jpg,Horizontal,180,260,2024-07-02,Late Afternoon Tea,Watercolor on paper,Home,2.5,,50,FALSE,Available,,,,,
10,/art/10.jpg,Vertical,380,270,2024-07-07,River Sparkle,Watercolor on paper,Home,4,,200,TRUE,Available,,,,,
11,/art/11.jpg,Horizontal,310,410,2024-07-22,Jog by the Pier,Watercolor on paper,Luggage,4,,150,FALSE,Available,,,,,
12,/art/12.jpg,Horizontal,310,410,2024-07-23,Jing'an Temple,Watercolor on paper,Luggage,4,,200,FALSE,Available,,,,,
13,/art/13.jpg,Horizontal,310,410,2024-07-23,Hogwarts,Watercolor on paper,Luggage,4,,200,FALSE,Available,,,,,
Binary file added public/images/art/11.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 public/images/art/12.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 public/images/art/13.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const config = {
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
green: "#32AC5C",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
Expand Down

0 comments on commit 1a0ef44

Please sign in to comment.