From cfeb937819b64b4b242cf83ecbe5b6f2ddc361a8 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Tue, 5 Nov 2024 14:55:42 +0200 Subject: [PATCH 1/8] #56 made nav bar mobile friendly --- package.json | 1 + pnpm-lock.yaml | 75 +++++++++++++++++++ src/app/_components/header.tsx | 36 ++++++---- src/components/slide-in-menu.tsx | 120 +++++++++++++++++++++++++++++++ src/components/ui/button.tsx | 2 +- 5 files changed, 219 insertions(+), 15 deletions(-) create mode 100644 src/components/slide-in-menu.tsx diff --git a/package.json b/package.json index 81448ea..b1943b7 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.1", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-navigation-menu": "^1.2.1", "@radix-ui/react-slot": "^1.1.0", "@t3-oss/env-nextjs": "^0.10.1", "@tanstack/react-query": "^5.50.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c509405..ca796eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@radix-ui/react-label': specifier: ^2.1.0 version: 2.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-navigation-menu': + specifier: ^1.2.1 + version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.12)(react@18.3.1) @@ -1854,6 +1857,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-navigation-menu@1.2.1': + resolution: {integrity: sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-popper@1.2.0': resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: @@ -1964,6 +1980,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-previous@1.1.0': + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-rect@1.1.0': resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: @@ -1982,6 +2007,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-visually-hidden@1.1.0': + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} @@ -8098,6 +8136,28 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 + '@radix-ui/react-navigation-menu@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8195,6 +8255,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: '@radix-ui/rect': 1.1.0 @@ -8209,6 +8275,15 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@radix-ui/rect@1.1.0': {} '@remix-run/router@1.5.0': {} diff --git a/src/app/_components/header.tsx b/src/app/_components/header.tsx index 9f2a5df..6436147 100644 --- a/src/app/_components/header.tsx +++ b/src/app/_components/header.tsx @@ -2,18 +2,20 @@ import Link from "next/link"; import Image from "next/image"; -import React from "react"; +import React, { useState } from "react"; +import SlideInMenu from "~/components/slide-in-menu"; const Header = () => { + const [isMenuOpen] = useState(false); + return ( <> <header className="w-full bg-background_dark text-text-dark relative overflow-hidden h-28"> - <div className="relative flex justify-between items-center h-full"> - {/* blue background with responsive width */} + <div className="relative flex justify-between items-center h-full px-4 sm:px-8"> <div className=" absolute inset-y-0 left-0 - w-3/5 + w-4/5 sm:w-1/2 lg:w-[32%] bg-[#2C5696] @@ -24,7 +26,7 @@ const Header = () => { " ></div> - <a href="/" className="relative z-10 flex items-center pl-8 ml-28"> + <a href="/" className="relative z-10 flex items-center pl-4 sm:pl-8"> <Image src="/logos/UT_website_logo_white_est.svg" alt="Logo" @@ -33,35 +35,41 @@ const Header = () => { /> </a> - <div className="relative z-10 flex items-center pr-8 space-x-6"> - <button className="hover:text-primary-dark text-text-dark text-lg">ENG</button> - <button className="hover:text-primary-dark text-text-dark text-lg">EST</button> - <button className="bg-primary-dark text-white px-4 py-2 rounded hover:bg-primary-dark_hover"> + <div className="relative z-10 flex items-center space-x-4 sm:space-x-6"> + <button className="hover:text-primary-dark text-text-dark text-lg hidden sm:block">ENG</button> + <button className="hover:text-primary-dark text-text-dark text-lg hidden sm:block">EST</button> + <div className="block sm:hidden"> + <SlideInMenu /> + </div> + <button className="bg-primary-dark text-white px-4 py-2 rounded hover:bg-primary-dark_hover hidden sm:block"> Log In </button> </div> </div> </header> - <nav className="w-full bg-background text-text-dark overflow-hidden h-16 flex justify-center items-center space-x-32"> + <nav className={`w-full bg-background text-text-dark overflow-hidden ${isMenuOpen ? 'block' : 'hidden'} mt-4 sm:flex justify-center items-center space-x-0 sm:space-x-32`}> <Link href="/"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696]"> + <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> All exhibitions </span> </Link> <Link href="/dashboard"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696]"> + <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> Dashboard </span> </Link> <Link href="/archive"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696]"> + <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> Archive </span> </Link> + <button className="bg-primary-dark text-white px-4 py-2 rounded hover:bg-primary-dark_hover block sm:hidden mt-2"> + Log In + </button> </nav> </> ); }; -export default Header; +export default Header; \ No newline at end of file diff --git a/src/components/slide-in-menu.tsx b/src/components/slide-in-menu.tsx new file mode 100644 index 0000000..32725a0 --- /dev/null +++ b/src/components/slide-in-menu.tsx @@ -0,0 +1,120 @@ +'use client' + +import { useState, useEffect } from 'react' +import { Menu, X, LogIn } from 'lucide-react' +import { Button } from "~/components/ui/button" +import { Input } from "~/components/ui/input" +import { Label } from "~/components/ui/label" +import Link from "next/link" + +export default function Component() { + const [isOpen, setIsOpen] = useState(false) + const [selectedLanguage, setSelectedLanguage] = useState('ENG') + + useEffect(() => { + const handleEscape = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + setIsOpen(false) + } + } + + document.addEventListener('keydown', handleEscape) + return () => document.removeEventListener('keydown', handleEscape) + }, []) + + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden' + } else { + document.body.style.overflow = '' + } + + return () => { + document.body.style.overflow = '' + } + }, [isOpen]) + + return ( + <> + <Button + variant="default" + className="sticky top-8 right-4 z-50 text-2xl" + onClick={() => setIsOpen(true)}> + âک° + <span className="sr-only">Open menu</span> + </Button> + + {isOpen && ( + <div + className="fixed inset-0 bg-black bg-opacity-50 z-40" + onClick={() => setIsOpen(false)} + /> + )} + + <div + className={`fixed top-0 right-0 h-full w-[70vw] sm:w-[400px] bg-background p-6 overflow-y-auto transition-transform duration-300 ease-in-out z-50 ${ + isOpen ? 'translate-x-0' : 'translate-x-full' + }`} + > + <Button + variant="ghost" + size="icon" + onClick={() => setIsOpen(false)} + className="absolute right-4 top-4" + > + <X className="h-4 w-4" /> + <span className="sr-only">Close</span> + </Button> + + <h2 className="text-2xl font-bold mb-6">Menu</h2> + + <div className="space-y-4"> + <div className="space-y-2"> + <Label htmlFor="email">Email</Label> + <Input id="email" type="email" placeholder="m@example.com" /> + </div> + <div className="space-y-2"> + <Label htmlFor="password">Password</Label> + <Input id="password" type="password" /> + </div> + <Button className="w-full bg-primary-dark text-white"> + <LogIn className="mr-2 h-4 w-4 " /> Log In + </Button> + </div> + + <div className="mt-8 space-y-2"> + <Link href="/" className="block border-t border-b border-gray-300 py-2"> + All exhibitions + </Link> + <Link href="/dashboard" className="block border-gray-300"> + Dashboard + </Link> + <Link href="/archive" className="block border-t border-b border-gray-300 py-2"> + Archive + </Link> + </div> + + <div className="mt-8 absolute bottom-6 w-full"> + <div className="flex space-x-4"> + <h3 className="text-lg font-semibold">Language:</h3> + <div className="space-x-2"> + <button + className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'ENG' ? 'underline' : ''}`} + onClick={() => setSelectedLanguage('ENG')} + > + ENG + </button> + <span className="text-text-dark">|</span> + <button + className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'EST' ? 'underline' : ''}`} + onClick={() => setSelectedLanguage('EST')} + > + EST + </button> + </div> + </div> + </div> + </div> + </> + ) +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 3eb6759..55e463e 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -10,7 +10,7 @@ const buttonVariants = cva( variants: { variant: { default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", + "bg-primary-default text-primary-foreground hover:bg-primary", destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", outline: -- GitLab From 8c0eb1cd680adad5d1dfe89f4ac7a65e0ce91693 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Tue, 5 Nov 2024 16:45:24 +0200 Subject: [PATCH 2/8] #56 refactoring the dashboard view --- .../exhibition-dashboard-cards.tsx | 105 +++++------------- src/app/_components/exhibition-section.tsx | 19 +--- src/app/dashboard/page.tsx | 34 +----- src/hooks/responsive-visible-drafts.ts | 35 ++++++ 4 files changed, 70 insertions(+), 123 deletions(-) create mode 100644 src/hooks/responsive-visible-drafts.ts diff --git a/src/app/_components/exhibition-dashboard-cards.tsx b/src/app/_components/exhibition-dashboard-cards.tsx index e39f168..40652f8 100644 --- a/src/app/_components/exhibition-dashboard-cards.tsx +++ b/src/app/_components/exhibition-dashboard-cards.tsx @@ -4,7 +4,7 @@ import React, { useState } from "react"; import Image from "next/image"; import dynamic from "next/dynamic"; import { useRouter } from "next/navigation"; -import { Cog } from "lucide-react"; +import { Settings } from "lucide-react"; import { configurations } from "~/constants/config"; import { useDeleteExhibition, @@ -13,32 +13,17 @@ import { } from "~/hooks/exhibition-actions"; import { type Exhibition } from "~/app/_types/exhibition"; -const DropdownMenu = dynamic(() => - import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenu), -); -const DropdownMenuTrigger = dynamic(() => - import("~/components/ui/dropdown-menu").then( - (mod) => mod.DropdownMenuTrigger, - ), -); -const DropdownMenuContent = dynamic(() => - import("~/components/ui/dropdown-menu").then( - (mod) => mod.DropdownMenuContent, - ), -); -const DropdownMenuItem = dynamic(() => - import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenuItem), -); +const DropdownMenu = dynamic(() => import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenu)); +const DropdownMenuTrigger = dynamic(() => import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenuTrigger)); +const DropdownMenuContent = dynamic(() => import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenuContent)); +const DropdownMenuItem = dynamic(() => import("~/components/ui/dropdown-menu").then((mod) => mod.DropdownMenuItem)); interface ExhibitionCardProps { exhibition: Exhibition; onClick: (id: number) => void; } -export default function ExhibitionCard({ - exhibition, - onClick, -}: ExhibitionCardProps) { +export default function ExhibitionCard({ exhibition, onClick }: ExhibitionCardProps) { const [isMenuOpen, setIsMenuOpen] = useState(false); const router = useRouter(); @@ -48,49 +33,34 @@ export default function ExhibitionCard({ const handleEdit = (e: React.MouseEvent) => { e.stopPropagation(); - if (exhibition.id) { - router.push(`/dashboard/${exhibition.id}`); - setIsMenuOpen(false); - } + router.push(`/dashboard/${exhibition.id}`); + setIsMenuOpen(false); }; const handleChangePublishedState = (e: React.MouseEvent) => { e.stopPropagation(); - if (exhibition.id) { - if (exhibition.isPublished) { - if ( - window.confirm( - "Are you sure you want to move this exhibition back to drafts?", - ) - ) { - unpublishExhibition.mutate({ id: exhibition.id }); - } - } else { - if ( - window.confirm("Are you sure you want to publish this exhibition?") - ) { - publishExhibition.mutate({ id: exhibition.id }); - } + if (exhibition.isPublished) { + if (window.confirm("Are you sure you want to move this exhibition back to drafts?")) { + unpublishExhibition.mutate({ id: exhibition.id }); + } + } else { + if (window.confirm("Are you sure you want to publish this exhibition?")) { + publishExhibition.mutate({ id: exhibition.id }); } - setIsMenuOpen(false); } + setIsMenuOpen(false); }; const handleDelete = (e: React.MouseEvent) => { e.stopPropagation(); - if ( - exhibition.id && - window.confirm("Are you sure you want to delete this exhibition?") - ) { + if (window.confirm("Are you sure you want to delete this exhibition?")) { deleteExhibition.mutate({ id: exhibition.id }); setIsMenuOpen(false); } }; - const truncateDescription = (text: string, maxLength: number) => { - if (text.length <= maxLength) return text; - return text.slice(0, maxLength) + "..."; - }; + const truncateDescription = (text: string, maxLength: number) => + text.length <= maxLength ? text : `${text.slice(0, maxLength)}...`; return ( <div className="mt-8"> @@ -101,27 +71,17 @@ export default function ExhibitionCard({ <div className="flex w-full"> <div className="relative h-32 w-32 flex-shrink-0 overflow-hidden rounded-md bg-gray-200"> <Image - src={ - exhibition.coverImageUrl ?? - configurations.DEFAULT_COVER_IMAGE_URL - } + src={exhibition.coverImageUrl ?? configurations.DEFAULT_COVER_IMAGE_URL} alt={exhibition.name ?? "Exhibition"} layout="fill" objectFit="cover" /> </div> <div className="mt-2 flex flex-grow flex-col justify-between overflow-hidden pl-3"> - <div> - <h2 className="text-dark truncate text-xl font-semibold"> - {exhibition.name} - </h2> - <p className="mt-1 text-sm text-text-dark"> - {truncateDescription( - exhibition.description ?? "", - configurations.MAX_DESCRIPTION_LENGTH, - )} - </p> - </div> + <h2 className="text-dark truncate text-xl font-semibold">{exhibition.name}</h2> + <p className="mt-1 text-sm text-text-dark"> + {truncateDescription(exhibition.description ?? "", configurations.MAX_DESCRIPTION_LENGTH)} + </p> </div> </div> @@ -133,26 +93,17 @@ export default function ExhibitionCard({ data-testid="card-options-button" onClick={(e) => e.stopPropagation()} > - <Cog className="h-5 w-5" /> + <Settings className="h-5 w-5" /> </button> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-36 bg-white"> - <DropdownMenuItem - onClick={handleEdit} - className="hover:font-semibold" - > + <DropdownMenuItem onClick={handleEdit} className="hover:font-semibold"> Edit </DropdownMenuItem> - <DropdownMenuItem - onClick={handleChangePublishedState} - className="hover:font-semibold" - > + <DropdownMenuItem onClick={handleChangePublishedState} className="hover:font-semibold"> {exhibition.isPublished ? "Unpublish" : "Publish"} </DropdownMenuItem> - <DropdownMenuItem - onClick={handleDelete} - className="text-red-600 hover:font-semibold hover:text-red-600" - > + <DropdownMenuItem onClick={handleDelete} className="text-red-600 hover:font-semibold"> Delete </DropdownMenuItem> </DropdownMenuContent> diff --git a/src/app/_components/exhibition-section.tsx b/src/app/_components/exhibition-section.tsx index 6af549e..69d12d8 100644 --- a/src/app/_components/exhibition-section.tsx +++ b/src/app/_components/exhibition-section.tsx @@ -33,8 +33,7 @@ const ExhibitionSection = ({ const [currentPage, setCurrentPage] = useState(1); useEffect(() => { - const page = parseInt(searchParams?.get("page") ?? "1", 10); - setCurrentPage(page); + setCurrentPage(parseInt(searchParams?.get("page") ?? "1", 10)); }, [searchParams]); const totalPages = Math.ceil(exhibitions.length / configurations.EXHIBITIONS_PER_PAGE); @@ -42,15 +41,8 @@ const ExhibitionSection = ({ const indexOfFirstExhibition = indexOfLastExhibition - configurations.EXHIBITIONS_PER_PAGE; const currentExhibitions = exhibitions.slice(indexOfFirstExhibition, indexOfLastExhibition); - const handlePageChange = (newPage: number) => { - router.push(`?page=${newPage}`); - }; - const handleViewAll = () => { - if (viewAllPath) { - router.push(viewAllPath); - } - }; + const handleViewAll = () => viewAllPath && router.push(viewAllPath); return ( <div className="mb-10"> @@ -63,9 +55,8 @@ const ExhibitionSection = ({ </button> )} <h1 className="text-2xl font-bold text-accent">{title}</h1> - <div className="relative"> - <ExhibitionList exhibitions={currentExhibitions} onExhibitionClick={onExhibitionClick}/> + <ExhibitionList exhibitions={currentExhibitions} onExhibitionClick={onExhibitionClick} /> {showFadeEffect && currentExhibitions.length === maxVisibleItems && ( <div className="absolute top-0 right-0 h-full w-1/4 bg-gradient-to-l from-white to-transparent pointer-events-none"></div> )} @@ -77,9 +68,7 @@ const ExhibitionSection = ({ </div> )} </div> - {showPagination && ( - <PaginationControls currentPage={currentPage} totalPages={totalPages} /> - )} + {showPagination && <PaginationControls currentPage={currentPage} totalPages={totalPages} />} </div> ); }; diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 1eb15b4..f04f43c 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -7,13 +7,14 @@ import type { Exhibition } from "../_types/exhibition"; import ExhibitionSection from "../_components/exhibition-section"; import CreateExhibitionModal from "../_components/create-exhibition-modal"; import MessageBanner from "../_components/message-banner"; +import useResponsiveVisibleDrafts from "~/hooks/responsive-visible-drafts"; const ExhibitionPageContent = () => { const router = useRouter(); const [drafts, setDrafts] = useState<Exhibition[]>([]); const [publishedExhibitions, setPublishedExhibitions] = useState<Exhibition[]>([]); const [isCreateExhibitionModalOpen, setIsCreateExhibitionModalOpen] = useState(false); - const [visibleDrafts, setVisibleDrafts] = useState(getInitialVisibleDrafts()); + const visibleDrafts = useResponsiveVisibleDrafts(); const { data, error, isLoading } = api.exhibition.getAll.useQuery(); @@ -24,35 +25,6 @@ const ExhibitionPageContent = () => { } }, [data]); - useEffect(() => { - const updateVisibleDrafts = () => { - if (window.innerWidth < 768) { - setVisibleDrafts(1); - } else if (window.innerWidth < 1200) { - setVisibleDrafts(2); - } else if (window.innerWidth < 1536) { - setVisibleDrafts(3); - } else { - setVisibleDrafts(4); - } - }; - - window.addEventListener("resize", updateVisibleDrafts); - updateVisibleDrafts(); - - return () => window.removeEventListener("resize", updateVisibleDrafts); - }, []); - - function getInitialVisibleDrafts() { - if (typeof window !== "undefined") { - if (window.innerWidth < 768) return 1; - if (window.innerWidth < 1200) return 2; - if (window.innerWidth < 1536) return 3; - return 4; - } - return 4; - } - const handleExhibitionClick = (id: number) => { router.push(`/dashboard/${id}`); }; @@ -110,4 +82,4 @@ const ExhibitionsPage = () => ( </Suspense> ); -export default ExhibitionsPage; +export default ExhibitionsPage; \ No newline at end of file diff --git a/src/hooks/responsive-visible-drafts.ts b/src/hooks/responsive-visible-drafts.ts new file mode 100644 index 0000000..51fe8bb --- /dev/null +++ b/src/hooks/responsive-visible-drafts.ts @@ -0,0 +1,35 @@ +"use client"; + +import { useState, useEffect } from "react"; + +const useResponsiveVisibleDrafts = () => { + const [visibleDrafts, setVisibleDrafts] = useState(getInitialVisibleDrafts()); + + useEffect(() => { + const updateVisibleDrafts = () => { + if (window.innerWidth < 768) setVisibleDrafts(1); + else if (window.innerWidth < 1200) setVisibleDrafts(2); + else if (window.innerWidth < 1536) setVisibleDrafts(3); + else setVisibleDrafts(4); + }; + + window.addEventListener("resize", updateVisibleDrafts); + updateVisibleDrafts(); + + return () => window.removeEventListener("resize", updateVisibleDrafts); + }, []); + + function getInitialVisibleDrafts() { + if (typeof window !== "undefined") { + if (window.innerWidth < 768) return 1; + if (window.innerWidth < 1200) return 2; + if (window.innerWidth < 1536) return 3; + return 4; + } + return 4; + } + + return visibleDrafts; +}; + +export default useResponsiveVisibleDrafts; -- GitLab From aa9ad4821ef89c6ec956dac979e7a4b9f167bd62 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Tue, 5 Nov 2024 17:16:39 +0200 Subject: [PATCH 3/8] #56 add test for creating exhibtion --- cypress/e2e/dashboard.cy.ts | 33 +++++++++++++++---- .../exhibition-dashboard-cards.tsx | 7 ++-- src/app/dashboard/drafts/page.tsx | 2 +- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/cypress/e2e/dashboard.cy.ts b/cypress/e2e/dashboard.cy.ts index 8f52325..f2ca12f 100644 --- a/cypress/e2e/dashboard.cy.ts +++ b/cypress/e2e/dashboard.cy.ts @@ -1,26 +1,47 @@ describe('Dashboard Page', () => { + const selectors = { + dashboardHeading: 'h1:contains("Dashboard")', + newExhibitionButton: 'button:contains("New Exhibition")', + createButton: 'button:contains("Create")', + viewAllButton: '[data-testid="view-all-button"]', + cardOptionsButton: '[data-testid="card-options-button"]', + editOption: 'Edit', + exhibitionTitleInput: 'input[placeholder="Enter exhibition title"]', + exhibitionDescriptionInput: 'textarea[placeholder="Enter exhibition description"]', + exhibitionCard: (title: string) => `[data-testid="exhibition-card"]:contains("${title}")`, + }; + beforeEach(() => { cy.visit('/dashboard'); }); it('should display the Dashboard heading', () => { - cy.contains('Dashboard').should('be.visible'); + cy.get(selectors.dashboardHeading).should('be.visible'); }); it('should open the Create Exhibition Modal', () => { - cy.get('button').contains('New Exhibition').click(); - cy.get('Button').contains('Create').should('be.visible'); + cy.get(selectors.newExhibitionButton).click(); + cy.get(selectors.createButton).should('be.visible'); }); it('should navigate to the drafts page by clicking the arrow', () => { - cy.get('[data-testid="view-all-button"]').click(); + cy.get(selectors.viewAllButton).click(); cy.url().should('include', '/dashboard/drafts'); }); it('should click the gear icon on a published exhibition card', () => { - cy.get('[data-testid="card-options-button"]').first().click(); - cy.contains('Edit').should('be.visible'); + cy.get(selectors.cardOptionsButton).first().click(); + cy.contains(selectors.editOption).should('be.visible'); cy.log('Verified that the gear icon is clickable'); }); + it('should create a new exhibition and verify its display on the dashboard', () => { + const exhibitionTitle = 'New Test Exhibition'; + const exhibitionDescription = 'This is a description for the new exhibition.'; + cy.get(selectors.newExhibitionButton).click(); + cy.get(selectors.exhibitionTitleInput).type(exhibitionTitle); + cy.get(selectors.exhibitionDescriptionInput).type(exhibitionDescription); + cy.get(selectors.createButton).click(); + cy.get(selectors.exhibitionCard(exhibitionTitle)).should('be.visible'); + }); }); \ No newline at end of file diff --git a/src/app/_components/exhibition-dashboard-cards.tsx b/src/app/_components/exhibition-dashboard-cards.tsx index 40652f8..acc01dd 100644 --- a/src/app/_components/exhibition-dashboard-cards.tsx +++ b/src/app/_components/exhibition-dashboard-cards.tsx @@ -22,7 +22,6 @@ interface ExhibitionCardProps { exhibition: Exhibition; onClick: (id: number) => void; } - export default function ExhibitionCard({ exhibition, onClick }: ExhibitionCardProps) { const [isMenuOpen, setIsMenuOpen] = useState(false); const router = useRouter(); @@ -65,6 +64,7 @@ export default function ExhibitionCard({ exhibition, onClick }: ExhibitionCardPr return ( <div className="mt-8"> <div + data-testid="exhibition-card" className="relative flex h-48 w-full cursor-pointer overflow-hidden rounded-lg bg-background_dark p-4 md:w-[320px]" onClick={() => onClick(exhibition.id)} > @@ -77,8 +77,8 @@ export default function ExhibitionCard({ exhibition, onClick }: ExhibitionCardPr objectFit="cover" /> </div> - <div className="mt-2 flex flex-grow flex-col justify-between overflow-hidden pl-3"> - <h2 className="text-dark truncate text-xl font-semibold">{exhibition.name}</h2> + <div className="flex flex-grow flex-col justify-start pl-3 pr-2"> + <h2 className="text-dark truncate text-l font-semibold pt-4">{exhibition.name}</h2> <p className="mt-1 text-sm text-text-dark"> {truncateDescription(exhibition.description ?? "", configurations.MAX_DESCRIPTION_LENGTH)} </p> @@ -113,6 +113,7 @@ export default function ExhibitionCard({ exhibition, onClick }: ExhibitionCardPr ); } + export function ExhibitionList({ exhibitions, onExhibitionClick, diff --git a/src/app/dashboard/drafts/page.tsx b/src/app/dashboard/drafts/page.tsx index 74883dc..af68381 100644 --- a/src/app/dashboard/drafts/page.tsx +++ b/src/app/dashboard/drafts/page.tsx @@ -33,7 +33,7 @@ const DraftsPage = () => { <div className="text-text-dark min-h-screen pl-32 pr-12 relative"> <button onClick={handleBackToDashboard} - className="absolute text-4xl text-black rounded-md hover:text-gray-500 transition duration-300" + className="absolute text-4xl text-black rounded-md hover:text-gray-500 transition duration-300 mt-5" style={{ top: '-100px', left: '16px' }} > ⬠-- GitLab From 0f66b46a33d5fed5877d9778a20cee07a187ecb2 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Wed, 6 Nov 2024 12:55:04 +0200 Subject: [PATCH 4/8] #56 fixing columns on laptop --- src/app/_components/exhibition-dashboard-cards.tsx | 2 +- src/app/_components/exhibition-visitor-cards.tsx | 6 ++---- src/hooks/responsive-visible-drafts.ts | 9 +++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/app/_components/exhibition-dashboard-cards.tsx b/src/app/_components/exhibition-dashboard-cards.tsx index acc01dd..c484bf1 100644 --- a/src/app/_components/exhibition-dashboard-cards.tsx +++ b/src/app/_components/exhibition-dashboard-cards.tsx @@ -122,7 +122,7 @@ export function ExhibitionList({ onExhibitionClick: (id: number) => void; }) { return ( - <div className="l:grid-cols-2 grid grid-cols-1 gap-4 xl:grid-cols-3 2xl:grid-cols-4"> + <div className="lg:grid-cols-2 grid grid-cols-1 gap-4 xl:grid-cols-3 2xl:grid-cols-4"> {exhibitions.map((exhibition) => ( <ExhibitionCard key={exhibition.id} diff --git a/src/app/_components/exhibition-visitor-cards.tsx b/src/app/_components/exhibition-visitor-cards.tsx index c9df736..c0e7dc9 100644 --- a/src/app/_components/exhibition-visitor-cards.tsx +++ b/src/app/_components/exhibition-visitor-cards.tsx @@ -16,7 +16,7 @@ interface ExhibitionListProps { const ExhibitionList: React.FC<ExhibitionListProps> = ({ exhibitions, onExhibitionClick }: ExhibitionListProps) => { return ( - <div className="grid grid-cols-1 l:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-3 gap-20"> + <div className="grid grid-cols-1 gap-20 lg:grid-cols-2 2xl:grid-cols-3"> {exhibitions.map((exhibition) => ( <ExhibitionCard key={exhibition.id} @@ -71,6 +71,4 @@ const ExhibitionCard: React.FC<ExhibitionCardProps> = ({ exhibition, onClick }) ); }; - - -export { ExhibitionList, ExhibitionCard }; \ No newline at end of file +export { ExhibitionList, ExhibitionCard }; diff --git a/src/hooks/responsive-visible-drafts.ts b/src/hooks/responsive-visible-drafts.ts index 51fe8bb..9cd1779 100644 --- a/src/hooks/responsive-visible-drafts.ts +++ b/src/hooks/responsive-visible-drafts.ts @@ -7,8 +7,8 @@ const useResponsiveVisibleDrafts = () => { useEffect(() => { const updateVisibleDrafts = () => { - if (window.innerWidth < 768) setVisibleDrafts(1); - else if (window.innerWidth < 1200) setVisibleDrafts(2); + if (window.innerWidth < 1024) setVisibleDrafts(1); + else if (window.innerWidth < 1280) setVisibleDrafts(2); else if (window.innerWidth < 1536) setVisibleDrafts(3); else setVisibleDrafts(4); }; @@ -21,8 +21,8 @@ const useResponsiveVisibleDrafts = () => { function getInitialVisibleDrafts() { if (typeof window !== "undefined") { - if (window.innerWidth < 768) return 1; - if (window.innerWidth < 1200) return 2; + if (window.innerWidth < 1024) return 1; + if (window.innerWidth < 1280) return 2; if (window.innerWidth < 1536) return 3; return 4; } @@ -33,3 +33,4 @@ const useResponsiveVisibleDrafts = () => { }; export default useResponsiveVisibleDrafts; + -- GitLab From 2897140bde356947a22f9476e3d8984ad2e697cc Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Mon, 11 Nov 2024 17:32:15 +0200 Subject: [PATCH 5/8] #56 Made dashboard mobile friendly --- components.json | 2 +- package.json | 3 +- pnpm-lock.yaml | 75 ------------------- .../exhibition-dashboard-cards.tsx | 3 +- src/app/_components/exhibition-section.tsx | 10 +-- src/app/_components/header.tsx | 4 +- src/app/dashboard/drafts/page.tsx | 23 +++--- src/app/dashboard/page.tsx | 2 +- src/components/slide-in-menu.tsx | 9 ++- src/hooks/responsive-visible-drafts.ts | 8 +- 10 files changed, 32 insertions(+), 107 deletions(-) diff --git a/components.json b/components.json index d272e24..299c982 100644 --- a/components.json +++ b/components.json @@ -6,7 +6,7 @@ "tailwind": { "config": "tailwind.config.ts", "css": "src/styles/globals.css", - "baseColor": "neutral", + "baseColor": "slate", "cssVariables": true, "prefix": "" }, diff --git a/package.json b/package.json index 7c70d25..d252bff 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.1", "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-navigation-menu": "^1.2.1", "@radix-ui/react-slot": "^1.1.0", "@t3-oss/env-nextjs": "^0.10.1", "@tanstack/react-query": "^5.50.0", @@ -87,4 +86,4 @@ "initVersion": "7.37.0" }, "packageManager": "pnpm@9.11.0" -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45a00b3..d2cab9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,9 +44,6 @@ importers: '@radix-ui/react-label': specifier: ^2.1.0 version: 2.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-navigation-menu': - specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.12)(react@18.3.1) @@ -1869,19 +1866,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-navigation-menu@1.2.1': - resolution: {integrity: sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-popper@1.2.0': resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: @@ -1992,15 +1976,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-previous@1.1.0': - resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-rect@1.1.0': resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: @@ -2019,19 +1994,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-visually-hidden@1.1.0': - resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} @@ -8183,28 +8145,6 @@ snapshots: '@types/react': 18.3.12 '@types/react-dom': 18.3.1 - '@radix-ui/react-navigation-menu@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.12)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.12 - '@types/react-dom': 18.3.1 - '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8302,12 +8242,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 - '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.12)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.12 - '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.12)(react@18.3.1)': dependencies: '@radix-ui/rect': 1.1.0 @@ -8322,15 +8256,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.12 - '@types/react-dom': 18.3.1 - '@radix-ui/rect@1.1.0': {} '@remix-run/router@1.5.0': {} diff --git a/src/app/_components/exhibition-dashboard-cards.tsx b/src/app/_components/exhibition-dashboard-cards.tsx index d74af31..2493ad0 100644 --- a/src/app/_components/exhibition-dashboard-cards.tsx +++ b/src/app/_components/exhibition-dashboard-cards.tsx @@ -140,7 +140,7 @@ export function ExhibitionList({ onExhibitionClick: (id: number) => void; }) { return ( - <div className="lg:grid-cols-2 grid grid-cols-1 gap-4 xl:grid-cols-3 2xl:grid-cols-4"> + <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8"> {exhibitions.map((exhibition) => ( <ExhibitionCard key={exhibition.id} @@ -149,5 +149,6 @@ export function ExhibitionList({ /> ))} </div> + ); } \ No newline at end of file diff --git a/src/app/_components/exhibition-section.tsx b/src/app/_components/exhibition-section.tsx index 597dc92..2448d53 100644 --- a/src/app/_components/exhibition-section.tsx +++ b/src/app/_components/exhibition-section.tsx @@ -41,7 +41,6 @@ const ExhibitionSection = ({ const indexOfFirstExhibition = indexOfLastExhibition - configurations.EXHIBITIONS_PER_PAGE; const currentExhibitions = exhibitions.slice(indexOfFirstExhibition, indexOfLastExhibition); - const handleViewAll = () => viewAllPath && router.push(viewAllPath); return ( @@ -55,16 +54,16 @@ const ExhibitionSection = ({ </button> )} <h1 className="text-2xl font-bold text-neutral">{title}</h1> - + <div className="relative"> <ExhibitionList exhibitions={currentExhibitions} onExhibitionClick={onExhibitionClick} /> {showFadeEffect && currentExhibitions.length === maxVisibleItems && ( <div className="absolute top-0 right-0 h-full w-1/4 bg-gradient-to-l from-white to-transparent pointer-events-none"></div> )} {viewAllPath && ( - <div className="absolute top-1/2 right-8 transform -translate-y-1/2"> - <button onClick={handleViewAll} className="text-black px-4 py-2 flex items-center group" data-testid="view-all-button"> - <span className="ml-2 text-4xl">م€‰</span> + <div className="absolute top-1/2 right-0 transform -translate-y-1/2"> + <button onClick={handleViewAll} className="text-black flex items-center group" data-testid="view-all-button"> + <span className="text-4xl">م€‰</span> </button> </div> )} @@ -75,3 +74,4 @@ const ExhibitionSection = ({ }; export default ExhibitionSection; + diff --git a/src/app/_components/header.tsx b/src/app/_components/header.tsx index 6436147..dc11609 100644 --- a/src/app/_components/header.tsx +++ b/src/app/_components/header.tsx @@ -64,9 +64,7 @@ const Header = () => { Archive </span> </Link> - <button className="bg-primary-dark text-white px-4 py-2 rounded hover:bg-primary-dark_hover block sm:hidden mt-2"> - Log In - </button> + </nav> </> ); diff --git a/src/app/dashboard/drafts/page.tsx b/src/app/dashboard/drafts/page.tsx index 1c1234e..eb11c3b 100644 --- a/src/app/dashboard/drafts/page.tsx +++ b/src/app/dashboard/drafts/page.tsx @@ -30,20 +30,21 @@ const DraftsPage = () => { return ( <Suspense fallback={<div>Loading...</div>}> - <div className="text-text-dark min-h-screen pl-32 pr-12 relative"> - <button - onClick={handleBackToDashboard} - className="absolute text-4xl text-black rounded-md hover:text-gray-500 transition duration-300 mt-5" - style={{ top: '-100px', left: '16px' }} - > - ⬠- </button> - <h1 className="text-3xl font-bold mb-4 text-accent mt-12">Drafts</h1> + <div className="text-text-dark min-h-screen px-4 sm:px-12 relative"> + <div className="flex items-center mt-12"> + <button + onClick={handleBackToDashboard} + className="text-4xl text-black rounded-md hover:text-gray-500 transition duration-300 mr-4 mb-10" + > + ⬠+ </button> + <h1 className="text-3xl font-bold text-dark mb-10">Drafts</h1> + </div> {isCreateExhibitionModalOpen && ( <CreateExhibitionModal onClose={() => setIsCreateExhibitionModalOpen(false)} /> )} <ExhibitionSection - title="Drafts" + title="" exhibitions={drafts} onExhibitionClick={handleExhibitionClick} showPagination @@ -54,4 +55,4 @@ const DraftsPage = () => { ); }; -export default DraftsPage; +export default DraftsPage; \ No newline at end of file diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 1e1389d..17f2ece 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -73,7 +73,7 @@ const ExhibitionPageContent = () => { const ExhibitionsPage = () => ( <Suspense fallback={<div>Loading search parameters...</div>}> - <div className="text-text-dark min-h-screen pl-32 pr-12 py-8"> + <div className="text-text-dark min-h-screen px-4 sm:px-12 py-8"> <ExhibitionPageContent /> </div> </Suspense> diff --git a/src/components/slide-in-menu.tsx b/src/components/slide-in-menu.tsx index 32725a0..7248c1c 100644 --- a/src/components/slide-in-menu.tsx +++ b/src/components/slide-in-menu.tsx @@ -38,7 +38,7 @@ export default function Component() { <> <Button variant="default" - className="sticky top-8 right-4 z-50 text-2xl" + className="sticky top-8 right-4 z-50 text-2xl text-gray-600" onClick={() => setIsOpen(true)}> âک° <span className="sr-only">Open menu</span> @@ -94,19 +94,19 @@ export default function Component() { </Link> </div> - <div className="mt-8 absolute bottom-6 w-full"> + <div className="mt-8 w-full"> <div className="flex space-x-4"> <h3 className="text-lg font-semibold">Language:</h3> <div className="space-x-2"> <button - className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'ENG' ? 'underline' : ''}`} + className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'ENG' ? 'font-bold' : ''}`} onClick={() => setSelectedLanguage('ENG')} > ENG </button> <span className="text-text-dark">|</span> <button - className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'EST' ? 'underline' : ''}`} + className={`hover:text-primary-dark text-text-dark text-lg ${selectedLanguage === 'EST' ? 'font-bold' : ''}`} onClick={() => setSelectedLanguage('EST')} > EST @@ -118,3 +118,4 @@ export default function Component() { </> ) } + diff --git a/src/hooks/responsive-visible-drafts.ts b/src/hooks/responsive-visible-drafts.ts index 9cd1779..dd3847d 100644 --- a/src/hooks/responsive-visible-drafts.ts +++ b/src/hooks/responsive-visible-drafts.ts @@ -7,9 +7,9 @@ const useResponsiveVisibleDrafts = () => { useEffect(() => { const updateVisibleDrafts = () => { - if (window.innerWidth < 1024) setVisibleDrafts(1); + if (window.innerWidth < 768) setVisibleDrafts(1); else if (window.innerWidth < 1280) setVisibleDrafts(2); - else if (window.innerWidth < 1536) setVisibleDrafts(3); + else if (window.innerWidth < 1280) setVisibleDrafts(3); else setVisibleDrafts(4); }; @@ -21,9 +21,9 @@ const useResponsiveVisibleDrafts = () => { function getInitialVisibleDrafts() { if (typeof window !== "undefined") { - if (window.innerWidth < 1024) return 1; + if (window.innerWidth < 768) return 1; if (window.innerWidth < 1280) return 2; - if (window.innerWidth < 1536) return 3; + if (window.innerWidth < 1280) return 3; return 4; } return 4; -- GitLab From 2425cfbab146f70d42e02c12682e63af0621ade9 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Mon, 11 Nov 2024 17:42:05 +0200 Subject: [PATCH 6/8] #56 Fixed the fade effect --- .../_components/exhibition-dashboard-cards.tsx | 2 +- src/app/_components/exhibition-section.tsx | 6 ++++-- src/hooks/responsive-visible-drafts.ts | 18 ++++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/app/_components/exhibition-dashboard-cards.tsx b/src/app/_components/exhibition-dashboard-cards.tsx index 2493ad0..286da0b 100644 --- a/src/app/_components/exhibition-dashboard-cards.tsx +++ b/src/app/_components/exhibition-dashboard-cards.tsx @@ -140,7 +140,7 @@ export function ExhibitionList({ onExhibitionClick: (id: number) => void; }) { return ( - <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8"> + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4 gap-8"> {exhibitions.map((exhibition) => ( <ExhibitionCard key={exhibition.id} diff --git a/src/app/_components/exhibition-section.tsx b/src/app/_components/exhibition-section.tsx index 2448d53..7948d22 100644 --- a/src/app/_components/exhibition-section.tsx +++ b/src/app/_components/exhibition-section.tsx @@ -58,12 +58,14 @@ const ExhibitionSection = ({ <div className="relative"> <ExhibitionList exhibitions={currentExhibitions} onExhibitionClick={onExhibitionClick} /> {showFadeEffect && currentExhibitions.length === maxVisibleItems && ( - <div className="absolute top-0 right-0 h-full w-1/4 bg-gradient-to-l from-white to-transparent pointer-events-none"></div> + <div className="absolute top-0 right-[-50px] h-full w-1/4 bg-gradient-to-l from-white to-transparent pointer-events-none"></div> )} + + {viewAllPath && ( <div className="absolute top-1/2 right-0 transform -translate-y-1/2"> <button onClick={handleViewAll} className="text-black flex items-center group" data-testid="view-all-button"> - <span className="text-4xl">م€‰</span> + <span className="text-4xl"> م€‰</span> </button> </div> )} diff --git a/src/hooks/responsive-visible-drafts.ts b/src/hooks/responsive-visible-drafts.ts index dd3847d..dd15007 100644 --- a/src/hooks/responsive-visible-drafts.ts +++ b/src/hooks/responsive-visible-drafts.ts @@ -7,10 +7,11 @@ const useResponsiveVisibleDrafts = () => { useEffect(() => { const updateVisibleDrafts = () => { - if (window.innerWidth < 768) setVisibleDrafts(1); - else if (window.innerWidth < 1280) setVisibleDrafts(2); - else if (window.innerWidth < 1280) setVisibleDrafts(3); - else setVisibleDrafts(4); + if (window.innerWidth < 768) setVisibleDrafts(1); // sm: 1 column + else if (window.innerWidth < 1024) setVisibleDrafts(2); // md: 2 columns + else if (window.innerWidth < 1280) setVisibleDrafts(3); // lg: 3 columns + else if (window.innerWidth < 1536) setVisibleDrafts(3); // xl: 3 columns + else setVisibleDrafts(4); // 2xl: 4 columns }; window.addEventListener("resize", updateVisibleDrafts); @@ -21,10 +22,11 @@ const useResponsiveVisibleDrafts = () => { function getInitialVisibleDrafts() { if (typeof window !== "undefined") { - if (window.innerWidth < 768) return 1; - if (window.innerWidth < 1280) return 2; - if (window.innerWidth < 1280) return 3; - return 4; + if (window.innerWidth < 768) return 1; // sm: 1 column + if (window.innerWidth < 1024) return 2; // md: 2 columns + if (window.innerWidth < 1280) return 3; // lg: 3 columns + if (window.innerWidth < 1536) return 3; // xl: 3 columns + return 4; // 2xl: 4 columns } return 4; } -- GitLab From ccaf52a340d90fbec7c2292c5f3f7c27ef49953d Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Mon, 11 Nov 2024 17:44:49 +0200 Subject: [PATCH 7/8] #56 fix wiggly header --- src/app/_components/header.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/_components/header.tsx b/src/app/_components/header.tsx index dc11609..70b37e5 100644 --- a/src/app/_components/header.tsx +++ b/src/app/_components/header.tsx @@ -50,22 +50,26 @@ const Header = () => { <nav className={`w-full bg-background text-text-dark overflow-hidden ${isMenuOpen ? 'block' : 'hidden'} mt-4 sm:flex justify-center items-center space-x-0 sm:space-x-32`}> <Link href="/"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> + <span className="relative cursor-pointer text-text-dark text-lg block sm:inline-block group"> All exhibitions + <span className="absolute left-0 bottom-0 w-full h-[2px] bg-[#2C5696] scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span> </span> </Link> <Link href="/dashboard"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> + <span className="relative cursor-pointer text-text-dark text-lg block sm:inline-block group"> Dashboard + <span className="absolute left-0 bottom-0 w-full h-[2px] bg-[#2C5696] scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span> </span> </Link> <Link href="/archive"> - <span className="hover:text-primary-dark cursor-pointer text-text-dark text-lg hover:border-b-2 hover:border-[#2C5696] block sm:inline-block"> + <span className="relative cursor-pointer text-text-dark text-lg block sm:inline-block group"> Archive + <span className="absolute left-0 bottom-0 w-full h-[2px] bg-[#2C5696] scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span> </span> </Link> - </nav> + + </> ); }; -- GitLab From c3640f0b970579ec039d59121f48759b7cd774d5 Mon Sep 17 00:00:00 2001 From: Eliisabet <eliisabet.kaasik@gmail.com> Date: Mon, 11 Nov 2024 18:19:34 +0200 Subject: [PATCH 8/8] #56 now shows "new exhibition" even if the database is empty --- src/app/dashboard/page.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 17f2ece..aa74d8b 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -36,6 +36,13 @@ const ExhibitionPageContent = () => { <h1 className="text-3xl font-bold mb-2 text-neutral">Dashboard</h1> <h2 className="text-xl mb-6 text-gray-500">Manage Exhibitions</h2> + <button + onClick={() => setIsCreateExhibitionModalOpen(true)} + className="bg-primary-dark text-text-light px-4 py-2 rounded-md hover:bg-primary-dark_hover transition duration-300 mb-4" + > + New Exhibition + </button> + {isCreateExhibitionModalOpen && ( <CreateExhibitionModal onClose={() => setIsCreateExhibitionModalOpen(false)} /> )} -- GitLab