diff --git a/server/my_sql/create_tables.sql b/server/my_sql/create_tables.sql index 4dcfd7b..eb2660a 100644 --- a/server/my_sql/create_tables.sql +++ b/server/my_sql/create_tables.sql @@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS plants ( long_description TEXT, author TEXT, last_modified DATE, - display_image TEXT, + display_images TEXT, plant_type TEXT, published BOOLEAN, PRIMARY KEY (id) diff --git a/website/src/components/credits.tsx b/website/src/components/credits.tsx index 7bad112..8f1065e 100644 --- a/website/src/components/credits.tsx +++ b/website/src/components/credits.tsx @@ -81,7 +81,7 @@ export function CreditedImage({url, alt, credits, colour = "gray"}: CreditedImag src={url} alt={alt} fill - style={{objectFit: "contain"}} + style={{objectFit: "cover"}} />

{credits}

diff --git a/website/src/components/image.tsx b/website/src/components/image.tsx new file mode 100644 index 0000000..9b85ff4 --- /dev/null +++ b/website/src/components/image.tsx @@ -0,0 +1,66 @@ +import React, { useState } from "react" +import styles from "@/styles/components/image.module.css" +import {ModalImage} from "@/components/modal"; +import {CreditedImage} from "@/components/credits"; +import {images} from "next/dist/build/webpack/config/blocks/images"; + + +export interface ImageArrayProps { + images: {url: string, name: string, credits: string, description: string}[] + colour?: string + enableModal?: boolean +} + +export function ImageArray(props: ImageArrayProps) { + const [currentImage, setCurrentImage] = useState(0) + + // Image slide show + const nextImage = () => { + if(currentImage === props.images.length - 1) { + setCurrentImage(0) + } else { + setCurrentImage(currentImage + 1) + } + } + + const previousImage = () => { + if(currentImage === 0) { + setCurrentImage(props.images.length - 1) + } else { + setCurrentImage(currentImage - 1) + } + } + + return( + <> +
+ {props.enableModal ? + + + + : + + } +
+ {props.images.length > 1 && +
+ +
+ {props.images.map((image, index) => { + return
+ +
+ } + + ) + +} \ No newline at end of file diff --git a/website/src/components/plant_sections.tsx b/website/src/components/plant_sections.tsx index 3f8ffa9..168b7c3 100644 --- a/website/src/components/plant_sections.tsx +++ b/website/src/components/plant_sections.tsx @@ -31,6 +31,7 @@ import {IconDefinition} from "@fortawesome/fontawesome-svg-core"; import {CreditedImage} from "@/components/credits"; import {ModalImage} from "@/components/modal"; import {getPostImage} from "@/lib/data"; +import {ImageArray} from "@/components/image"; interface AutoSectionProps{ section: any @@ -82,7 +83,6 @@ interface EdibleSectionProps{ * @param {EdibleSectionData} props.section - The section data. * @param {boolean} props.isLeft - Whether the image should be on the left or right side of the page. * - * @see {@link AdvancedTextArea} - The advanced text area component. * * @returns {JSX.Element} The rendered section component. */ @@ -93,16 +93,26 @@ export function EdibleSection({section, isLeft} : EdibleSectionProps){ const preparationRef = useRef(null) const hasImage = section.images.length > 0 - const imageURI = hasImage ? getPostImage(section.images[0]) : "/media/images/default_noImage.png" - const imageAlt = hasImage ? section.images[0].post_title : "No Image" - const imageCredits = hasImage ? section.images[0].post_user_id.toString() : "" + const images = hasImage ? + section.images.map((image: any) => { + return { + url: getPostImage(image), + name: image.post_title, + credits: image.post_user_id.toString(), + description: image.post_title + } + }) + : [{ + url: "/media/images/default_noImage.png", + name: "No Image", + credits: "", + description: "" + }] const imageDiv = ( <>
- - - +
) @@ -165,16 +175,26 @@ export function MedicalSection({section, isLeft} : MedicalSectionProps){ // TODO COMPONETIZE THIS const hasImage = section.images.length > 0 - const imageURI = hasImage ? getPostImage(section.images[0]) : "/media/images/default_noImage.png" - const imageAlt = hasImage ? section.images[0].post_title : "No Image" - const imageCredits = hasImage ? section.images[0].post_user_id.toString() : "" + const images = hasImage ? + section.images.map((image: any) => { + return { + url: getPostImage(image), + name: image.post_title, + credits: image.post_user_id.toString(), + description: image.post_title + } + }) + : [{ + url: "/media/images/default_noImage.png", + name: "No Image", + credits: "", + description: "" + }] const imageDiv = ( <>
- - - +
) @@ -238,16 +258,26 @@ export function CraftSection({section, isLeft} : CraftSectionProps){ const additional_infoRef = useRef(null) const hasImage = section.images.length > 0 - const imageURI = hasImage ? getPostImage(section.images[0]) : "/media/images/default_noImage.png" - const imageAlt = hasImage ? section.images[0].post_title : "No Image" - const imageCredits = hasImage ? section.images[0].post_user_id.toString() : "" + const images = hasImage ? + section.images.map((image: any) => { + return { + url: getPostImage(image), + name: image.post_title, + credits: image.post_user_id.toString(), + description: image.post_title + } + }) + : [{ + url: "/media/images/default_noImage.png", + name: "No Image", + credits: "", + description: "" + }] const imageDiv = ( <>
- - - +
) diff --git a/website/src/lib/databse.ts b/website/src/lib/databse.ts index c6362be..f72a6b8 100644 --- a/website/src/lib/databse.ts +++ b/website/src/lib/databse.ts @@ -25,7 +25,7 @@ export class SQLDatabase { long_description: string; author: string; last_modified: string; - display_image: string; + display_images: string; plant_type: string; published: string; @@ -133,7 +133,7 @@ export class SQLDatabase { this.long_description = "long_description"; this.author = "author"; this.last_modified = "last_modified"; - this.display_image = "display_image"; + this.display_images = "display_images"; this.plant_type = "plant_type"; this.published = "published" diff --git a/website/src/lib/plant_data.ts b/website/src/lib/plant_data.ts index 050cb56..4d5795f 100644 --- a/website/src/lib/plant_data.ts +++ b/website/src/lib/plant_data.ts @@ -21,7 +21,7 @@ export interface PlantData { authorIDs: number[]; authors: UserDatabaseDetails[]; last_modified: string; - display_image: string; + display_images: PostData[]; plant_type: string; attachments: AttachmentData[]; sections: any[]; @@ -40,7 +40,7 @@ export interface PlantDataApi { long_description: string; author: string; last_modified: string; - display_image: string; + display_images: PostData[]; plant_type: string; published: boolean; months_ready_events: string[]; @@ -351,7 +351,7 @@ export function ValidPlantDataApi(apiData : PlantDataApi) : boolean { || apiData.long_description == null || apiData.author == null || apiData.last_modified == null - || apiData.display_image == null + || apiData.display_images == null || apiData.plant_type == null || apiData.months_ready_events == null || apiData.months_ready_start_months == null @@ -403,7 +403,7 @@ export function ValidPlantData(plantData : PlantData) : boolean { || plantData.long_description == null || plantData.authorIDs == null || plantData.last_modified == null - || plantData.display_image == null + || plantData.display_images == null || plantData.plant_type == null || plantData.months_ready_for_use == null || plantData.use == null @@ -439,7 +439,7 @@ export function ConvertApiIntoPlantData(apiData : PlantDataApi){ plantData.small_description = apiData.small_description; plantData.long_description = apiData.long_description; plantData.last_modified = apiData.last_modified; - plantData.display_image = apiData.display_image; + plantData.display_images = apiData.display_images; plantData.plant_type = apiData.plant_type; plantData.published = apiData.published; @@ -598,7 +598,7 @@ export function ConvertPlantDataIntoApi(plantData : PlantData){ apiData.small_description = plantData.small_description; apiData.long_description = plantData.long_description; apiData.last_modified = plantData.last_modified; - apiData.display_image = plantData.display_image; + apiData.display_images = plantData.display_images.map((image: any) => image.id).join(",") as any; apiData.plant_type = plantData.plant_type; apiData.author = plantData.authorIDs.toString() apiData.published = plantData.published; @@ -686,7 +686,7 @@ export function emptyPlantData(){ authorIDs: [], authors: [], last_modified: "", - display_image: "", + display_images: [], plant_type: "", attachments: [], sections: [], @@ -711,7 +711,7 @@ export function emptyPlantApiData(){ long_description: "", author: "", last_modified: new Date().toISOString(), - display_image: "", + display_images: [], plant_type: "", months_ready_events: [], months_ready_start_months: [], diff --git a/website/src/pages/api/files/upload.ts b/website/src/pages/api/files/upload.ts index 2183595..30a64e4 100644 --- a/website/src/pages/api/files/upload.ts +++ b/website/src/pages/api/files/upload.ts @@ -79,8 +79,8 @@ function createBackUpQuery(json: any) { let old = query query = createUpSertQuery("plants", - [tables.id, tables.preferred_name, tables.english_name, tables.maori_name, tables.latin_name, tables.location_found, tables.small_description, tables.long_description, tables.author, tables.last_modified, tables.display_image, tables.plant_type, tables.published], - [plantTable[j].id, plantTable[j].preferred_name, plantTable[j].english_name, plantTable[j].maori_name, plantTable[j].latin_name, plantTable[j].location_found, plantTable[j].small_description, plantTable[j].long_description, plantTable[j].author, plantTable[j].last_modified, plantTable[j].display_image, plantTable[j].plant_type, plantTable[j].published] + [tables.id, tables.preferred_name, tables.english_name, tables.maori_name, tables.latin_name, tables.location_found, tables.small_description, tables.long_description, tables.author, tables.last_modified, tables.display_images, tables.plant_type, tables.published], + [plantTable[j].id, plantTable[j].preferred_name, plantTable[j].english_name, plantTable[j].maori_name, plantTable[j].latin_name, plantTable[j].location_found, plantTable[j].small_description, plantTable[j].long_description, plantTable[j].author, plantTable[j].last_modified, plantTable[j].display_images, plantTable[j].plant_type, plantTable[j].published] ) // Add the old query @@ -106,7 +106,7 @@ function createBackUpQuery(json: any) { let craftTable = json.data[i]; for (let j = 0; j < craftTable.length; j++) query += createUpSertQuery("craft", - [tables.id, tables.plant_id, tables.craft_part_of_plant, tables.craft_use_identifier, tables.craft_use, tables.craft_image, tables.craft_additional_info], + [tables.id, tables.plant_id, tables.craft_part_of_plant, tables.craft_use_identifier, tables.craft_use, tables.craft_images, tables.craft_additional_info], [craftTable[j].id, craftTable[j].plant_id, craftTable[j].craft_part_of_plant, craftTable[j].craft_use_identifier, craftTable[j].craft_use, craftTable[j].craft_image, craftTable[j].craft_additional_info] ) @@ -130,7 +130,7 @@ function createBackUpQuery(json: any) { let edibleTable = json.data[i]; for (let j = 0; j < edibleTable.length; j++) query += createUpSertQuery("edible", - [tables.id, tables.plant_id, tables.edible_part_of_plant, tables.edible_use_identifier, tables.edible_image_of_part, tables.edible_nutrition, tables.edible_preparation, tables.edible_preparation_type], + [tables.id, tables.plant_id, tables.edible_part_of_plant, tables.edible_use_identifier, tables.edible_images, tables.edible_nutrition, tables.edible_preparation, tables.edible_preparation_type], [edibleTable[j].id, edibleTable[j].plant_id, edibleTable[j].edible_part_of_plant, edibleTable[j].edible_use_identifier, edibleTable[j].edible_image, edibleTable[j].edible_nutrition, edibleTable[j].edible_preparation, edibleTable[j].edible_preparation_type] ) continue; @@ -142,7 +142,7 @@ function createBackUpQuery(json: any) { let medicalTable = json.data[i]; for (let j = 0; j < medicalTable.length; j++) query += createUpSertQuery("medical", - [tables.id, tables.plant_id, tables.medical_type, tables.medical_use_identifier, tables.medical_use, tables.medical_image, tables.medical_preparation, tables.medical_restricted], + [tables.id, tables.plant_id, tables.medical_type, tables.medical_use_identifier, tables.medical_use, tables.medical_images, tables.medical_preparation, tables.medical_restricted], [medicalTable[j].id, medicalTable[j].plant_id, medicalTable[j].medical_type, medicalTable[j].medical_use_identifier, medicalTable[j].medical_use, medicalTable[j].medical_image, medicalTable[j].medical_preparation, medicalTable[j].medical_restricted] ) continue; diff --git a/website/src/pages/api/plants/download.ts b/website/src/pages/api/plants/download.ts index 085a85a..ab4967c 100644 --- a/website/src/pages/api/plants/download.ts +++ b/website/src/pages/api/plants/download.ts @@ -93,7 +93,7 @@ export async function downloadPlantData(table: any, id: any, client: any, restri plants.${tables.long_description}, plants.${tables.author}, plants.${tables.last_modified}, - plants.${tables.display_image}, + plants.${tables.display_images}, plants.${tables.plant_type}, plants.${tables.published},`; break; @@ -272,12 +272,14 @@ export async function downloadPlantData(table: any, id: any, client: any, restri data[0].medical_images = parseImageIds(data[0].medical_images); data[0].edible_images = parseImageIds(data[0].edible_images); data[0].craft_images = parseImageIds(data[0].craft_images); + data[0].display_images = parseImageId(data[0].display_images); // Remove duplicates let allPostIds: any = []; for (let i = 0; i < data[0].medical_images.length; i++) { allPostIds = allPostIds.concat(data[0].medical_images[i]); } for (let i = 0; i < data[0].edible_images.length; i++) { allPostIds = allPostIds.concat(data[0].edible_images[i]); } for (let i = 0; i < data[0].craft_images.length; i++) { allPostIds = allPostIds.concat(data[0].craft_images[i]); } + allPostIds.concat(data[0].display_images); allPostIds = allPostIds.filter((id: any, index: any) => allPostIds.indexOf(id) === index); // Make sure that allPostIds is not empty @@ -291,6 +293,7 @@ export async function downloadPlantData(table: any, id: any, client: any, restri for (let i = 0; i < data[0].medical_images.length; i++) { data[0].medical_images[i] = data[0].medical_images[i].map((id: any) => postData.find((post: any) => post.id === id)); } for (let i = 0; i < data[0].edible_images.length; i++) { data[0].edible_images[i] = data[0].edible_images[i].map((id: any) => postData.find((post: any) => post.id === id)); } for (let i = 0; i < data[0].craft_images.length; i++) { data[0].craft_images[i] = data[0].craft_images[i].map((id: any) => postData.find((post: any) => post.id === id)); } + data[0].display_images = data[0].display_images.map((id: any) => postData.find((post: any) => post.id === id)); // If the data is not empty, return the data return ["success", data]; @@ -311,4 +314,11 @@ const parseImageIds = (imageData: string) => { }) } ) +} + +const parseImageId = (imageData: string) => { + if(imageData === null || imageData == "") return []; + return imageData.split(",").map((id: string) => { + return parseInt(id.trim().split("\n")[0]) + }) } \ No newline at end of file diff --git a/website/src/pages/api/plants/upload.ts b/website/src/pages/api/plants/upload.ts index e1ca1e5..573a76d 100644 --- a/website/src/pages/api/plants/upload.ts +++ b/website/src/pages/api/plants/upload.ts @@ -41,7 +41,7 @@ export default async function handler( small_description, long_description, author, - display_image, + display_images, plant_type, months_ready_events, months_ready_start_months, @@ -101,8 +101,8 @@ export default async function handler( let query = ``; // Add the information for the plant data - query += `INSERT INTO plants (${insertQuery} ${tables.preferred_name}, ${tables.english_name}, ${tables.maori_name}, ${tables.latin_name}, ${tables.location_found}, ${tables.small_description}, ${tables.long_description}, ${tables.author}, ${tables.last_modified}, ${tables.display_image}, ${tables.plant_type}, ${tables.published}) `; - query += `VALUES (${insetQueryValues} '${preferred_name}', '${english_name}', '${maori_name}', '${latin_name}', '${location_found}', '${small_description}', '${long_description}', '${author}', ${timeFunction}(${Date.now()} / 1000.0), '${display_image}', '${plant_type}', 0) ${USE_POSTGRES ? "RETURNING id" : ""};`; + query += `INSERT INTO plants (${insertQuery} ${tables.preferred_name}, ${tables.english_name}, ${tables.maori_name}, ${tables.latin_name}, ${tables.location_found}, ${tables.small_description}, ${tables.long_description}, ${tables.author}, ${tables.last_modified}, ${tables.display_images}, ${tables.plant_type}, ${tables.published}) `; + query += `VALUES (${insetQueryValues} '${preferred_name}', '${english_name}', '${maori_name}', '${latin_name}', '${location_found}', '${small_description}', '${long_description}', '${author}', ${timeFunction}(${Date.now()} / 1000.0), '${display_images}', '${plant_type}', 0) ${USE_POSTGRES ? "RETURNING id" : ""};`; // Create a temporary table to hold the new plant id query += `DROP TABLE IF EXISTS new_plant; CREATE TEMPORARY TABLE new_plant AS ( SELECT id FROM plants ORDER BY id DESC LIMIT 1 ); ${!USE_POSTGRES ? "SELECT id FROM new_plant;" : ""}`; diff --git a/website/src/pages/plants/[id].tsx b/website/src/pages/plants/[id].tsx index 3771152..75f21ee 100644 --- a/website/src/pages/plants/[id].tsx +++ b/website/src/pages/plants/[id].tsx @@ -18,21 +18,21 @@ import {checkUserPermissions, RongoaUser} from "@/lib/users"; import {Layout} from "@/components/layout"; import {loader_data} from "@/lib/loader_data"; import PostFeed from "@/components/postfeed"; +import {getPostImage} from "@/lib/data"; +import {ImageArray} from "@/components/image"; export default function PlantPage() { // Store the plant data const [plantData, setPlantData] = React.useState(null) const [plantNames, setPlantNames] = React.useState(["Loading...", "Loading...", "Loading..."]) + const [images, setImages] = React.useState<{url: string, name: string, credits: string, description: string}[]>([]) + - // States for the images - const [currentImage, setCurrentImage] = React.useState(0) - const [mainImage, setMainImage] = React.useState("/media/images/loading.gif") - const [mainImageMetaData, setMainImageMetaData] = React.useState(null) const [showMainImage, setShowMainImage] = React.useState(false) const [isMobile, setIsMobile] = React.useState(false) - - + + // Loading const [loadingMessage, setLoadingMessage] = React.useState("") @@ -140,25 +140,6 @@ export default function PlantPage() { } }, []) - // Update content when the plant data changes - const setMainImageFromIndex = (index: number) => { - - // Get all the attachments with image type - let images = plantData?.attachments.filter((attachment) => attachment.type === "image") - - // If there are no images then return - if(!images) - return - - // If the index is out of bounds then return - if(index < 0 || index >= images.length) - return; - - // Set the current image - setMainImage(images[index].path) - setMainImageMetaData(images[index].meta as ImageMetaData) - - } // Load the data when the plant data changes useEffect(() => { @@ -169,28 +150,25 @@ export default function PlantPage() { div.innerHTML = plantData ? plantData.long_description : "Loading..."; } - // Get all the attachments with image type - let images = plantData?.attachments.filter((attachment) => attachment.type === "image") - - // Set the main image - switch (plantData?.display_image){ - - case "Default": - setMainImage("/media/images/default_noImage.png") - break; - - case "Random": - // Get a random index and set the image - if(images) - setMainImageFromIndex(Math.floor(Math.random() * images.length)) - break; + if(!plantData) return; - default: - // Find the image with the same name as the display image - if(images) - setMainImageFromIndex(images.findIndex((image) => (image.meta as ImageMetaData).name === plantData?.display_image)) - - } + const hasImage = plantData.display_images.length > 0 + const images = hasImage ? + plantData.display_images.map((image: any) => { + return { + url: getPostImage(image), + name: image.post_title, + credits: image.post_user_id.toString(), + description: image.post_title + } + }) + : [{ + url: "/media/images/default_noImage.png", + name: "No Image", + credits: "", + description: "" + }] + setImages(images) }, [plantData]); @@ -316,51 +294,8 @@ export default function PlantPage() {
-
- - {/* The main image, will be set to the first image until the users scrolls below to another one */} -
- - -
- - - - {/* The bottom images, will be set to the first 5 images, on click they will change the main image */} -
- - {/* Decrement the current image by 1 */} - - - {/* Loop through 5 creating 5 images */} - {plantData && plantData.attachments.filter((attachment, index) => index < 5 && attachment.type === "image").map((attachment, index) => ( - <> - {/* On click set the main image to the image clicked */} - - - ))} - - {/* Decrement the current image by 1 */} - -
+
diff --git a/website/src/pages/plants/create.tsx b/website/src/pages/plants/create.tsx index 78647f7..7c31d0d 100644 --- a/website/src/pages/plants/create.tsx +++ b/website/src/pages/plants/create.tsx @@ -1423,6 +1423,8 @@ export default function CreatePlant() { const [error, setError] = useState("") const [isLoading, setIsLoading] = useState(false) const [progressMessage, setProgressMessage] = useState("") + const [plantID, setPlantID] = useState() + const [showImagePopup, setShowImagePopup] = useState(false) // Imported DATA const [importedJSON, setImportedJSON] = useState(emptyPlantData()) @@ -1435,8 +1437,8 @@ export default function CreatePlant() { const [smallDescription, setSmallDescription] = useState("") const [largeDescription, setLargeDescription] = useState("") const [location, setLocation] = useState("") - const [displayImage, setDisplayImage] = useState("") const [plantType, setPlantType] = useState("") + const [mainImages, setMainImages] = useState([]) // Section Refs const dateInfoRef = useRef([]); @@ -1465,8 +1467,8 @@ export default function CreatePlant() { const handleSmallDescriptionChange = (value : string) => { setSmallDescription(value) }; const handleLargeDescriptionChange = (value : string) => { setLargeDescription(value) }; const handleLocationChange = (value : string) => { setLocation(value) }; - const handleDisplayImageChange = (value : string) => { setDisplayImage(value) }; const handlePlantTypeChange = (value : string) => { setPlantType(value) }; + const handleMainImagesChange = (value : any[]) => { setMainImages(value) }; // New Section Setters const newDateInfo = () => {dateInfoRef.current = [...dateInfoRef.current, new DateInfo()]; setRenderKeyDate(prevState => prevState + 1)} @@ -1571,13 +1573,6 @@ export default function CreatePlant() { if(elementThatNeedsFocus === null) elementThatNeedsFocus = "location"; } else { setLocationValidationState(["success", "No Error"] as [ValidationState, string]) } - // Display Image - if(displayImage === ""){ - setDisplayImageValidationState(["error", "Please select a display image"]) - isValid = false; - if(elementThatNeedsFocus === null) elementThatNeedsFocus = "display-image"; - }else { setDisplayImageValidationState(["success", "No Error"] as [ValidationState, string]) } - // Plant Type if(plantType === ""){ setPlantTypeValidationState(["error", "Please select a plant type"]) @@ -1683,7 +1678,7 @@ export default function CreatePlant() { plantOBJ.small_description = cleanInput(smallDescription) plantOBJ.long_description = cleanInput(largeDescription) plantOBJ.last_modified = new Date().toISOString() - plantOBJ.display_image = cleanInput(displayImage); + plantOBJ.display_images = mainImages; plantOBJ.plant_type = cleanInput(plantType); plantOBJ.authorIDs = []; @@ -2321,6 +2316,8 @@ export default function CreatePlant() { // Convert to a number const idNum = parseInt(id); + setPlantID(idNum) + // Check if the id is valid if(isNaN(idNum)){ setError("The id of the plant you are trying to edit is not a valid id") @@ -2481,20 +2478,6 @@ export default function CreatePlant() { /> - {/* Plant Display Image */} -
- -
- {/* Plant Type */}
+ {/* Image Selector */} + setShowImagePopup(false)} + setImages={setMainImages} + startImages={mainImages} + id={plantID} + /> + + {/* Image Displays */} +
+ +

Main Images

+

Images displayed in searches and the top of the plant page, set per section images in the sections below

+
+ + {/* Display the images */} + {mainImages.map((image: any, index: number) => { + return ( +
+
+ + {/* Load the image from the website or use the blob data from the file */} + {image.title} + +
+
+ ) + })} + + + {/* Button to select image */} + +
{/* File */}
diff --git a/website/src/styles/components/image.module.css b/website/src/styles/components/image.module.css new file mode 100644 index 0000000..1e02a71 --- /dev/null +++ b/website/src/styles/components/image.module.css @@ -0,0 +1,40 @@ +.imageContainer{ + color: #0A670A; +} + +.imageControls{ + display: flex; + justify-content: space-between; + margin-top: 10px; + padding: 10px; + position: relative; + top: -2.5%; + background: rgba(0, 0, 0, 0.3); + color: white; +} + +.imageControls button:hover{ + color: var(--main-green); +} + +.dotsContainer { + display: flex; + gap: 12px; /* Adjust the gap as needed */ +} + +.dot{ + height: 10px; + width: 10px; + background-color: #ffffff; + border-radius: 50%; + display: inline-block; + margin: auto; +} + +.dot:hover{ + background-color: var(--main-green); +} + +.dot.active{ + background-color: var(--main-green); +} \ No newline at end of file diff --git a/website/src/styles/pages/plants/id.module.css b/website/src/styles/pages/plants/id.module.css index 35236f0..5f68f35 100644 --- a/website/src/styles/pages/plants/id.module.css +++ b/website/src/styles/pages/plants/id.module.css @@ -66,9 +66,14 @@ Hide the overflow as the corners are rounded */ .plantImageContainer{ - width: 100%; + background-color: var(--secondary-gray); + width: 80%; height: 100%; + border-radius: 20px; + min-height: 600px; + position: relative; overflow: hidden; + top: 30%; } /* @@ -247,8 +252,8 @@ Center the images when there is only one column */ .plantImageContainer{ - display: grid; - justify-items: center; + width: 100%; + min-height: 200px; } /*