diff --git a/frontend/src/Components/ArtPage.tsx b/frontend/src/Components/ArtPage.tsx index 2cbb7f6703ef8100683697e32b9abe942e97b608..362e2de963f9b82acc594777360ef429dd7c71ef 100644 --- a/frontend/src/Components/ArtPage.tsx +++ b/frontend/src/Components/ArtPage.tsx @@ -8,32 +8,81 @@ import Music from "./Music"; type props = { - pageId: number; // The id of the page - changePage: (arg0: boolean) => void; // A function that takes a bool and returns void + pageId: number; // The id of the page } -class ArtPage extends React.Component<props> { - - constructor(props: props) { - super(props); - } - - render() { - return ( - <div className={'artpage'}> - <FavoriteButton/> - <DropDown/> - <ExhibitionPiece artId={this.props.pageId}/> - <Music/> - <div className={'navbutton left'}> - <NavButton changePage={this.props.changePage} direction={"left"}/> - </div> - <div className={'navbutton right'}> - <NavButton changePage={this.props.changePage} direction={"right"}/> - </div> - </div> - ); - } +type options = { [key: string]: string }; // Key string dictionary with different options +type state = { + options: options; + updateOption: (arg0: string, arg1: string) => void; +}; +export const OptionsContext = React.createContext({} as state); // Context for passing down Options + +class ArtPage extends React.Component<props, state> { + + updateToggleChoice = (label: string, choice: string) => { // Called when player updates the dropdown + this.updateOptions({...this.state.options, [label]: choice}); // Updates state + this.updateSessionStorage(label, choice); // Updates storage + }; + + updateOptions = (options: options) => { // Updates the state with newly received options + this.setState(current => ({ + ...current, + options + })) + }; + + updateSessionStorage = (label: string, choice: string) => { + const pageId = this.props.pageId.toString(); + const choices = sessionStorage.getItem(pageId); // Previously stored options. Saved as string + if (choices != null) { // We have stored something previously + const choicesObject: object = JSON.parse(choices); // Convert string to object + let choicesObjectStringified : string = JSON.stringify({...choicesObject, [label]: choice}); + sessionStorage.setItem(pageId, choicesObjectStringified); // Update choices + } else + sessionStorage.setItem(pageId, JSON.stringify({...this.state.options, [label]: choice})); + }; + + componentDidUpdate(prevProps: Readonly<props>, prevState: Readonly<state>): void { + const {pageId} = this.props; // No toString as it compares with prevState + if (prevProps.pageId !== pageId) { // We have changed page. Must update the options + const savedOptions = sessionStorage.getItem(pageId.toString()); + if (savedOptions !== null) { // Stored something previously + const savedOptionsObject = JSON.parse(savedOptions); // Convert string to object + this.updateOptions(savedOptionsObject); + } else { + this.updateOptions({...this.options}); + } + } + } + + options = { + "sound": "", + "background": "one", + "font": "calibri" + }; + state = { + options: {...this.options}, + updateOption: this.updateToggleChoice + }; + + render() { + return ( + <div className={`artpage background-${this.state.options.background} font-${this.state.options.font}`}> + <FavoriteButton pageId={this.props.pageId}/> + <OptionsContext.Provider value={this.state}> + <DropDown/> + </OptionsContext.Provider> + <ExhibitionPiece artId={this.props.pageId}/> + <div className={'navbutton left'}> + <NavButton direction={"left"}/> + </div> + <div className={'navbutton right'}> + <NavButton direction={"right"}/> + </div> + </div> + ); + } } export default ArtPage; \ No newline at end of file diff --git a/frontend/src/Components/DropDown.tsx b/frontend/src/Components/DropDown.tsx index 9d76a14e2d21ddffd3b11d52c10013be89b6c0d7..35e087a797fc2129652c893abab2706995e4c06a 100644 --- a/frontend/src/Components/DropDown.tsx +++ b/frontend/src/Components/DropDown.tsx @@ -1,54 +1,40 @@ -import React, { useState } from 'react'; +import React, {useState} from 'react'; import '../Style/DropDown.css'; -import DropDownToggle from './DropDownToggle'; - -type props = {} - -const DropDown = (props: props) => { - const [clicked, setClicked] = useState(false); - - const OneOptions = [1, 2, 3, 4]; - const TwoOptions = ['Happy', 'Sombre', 'Peaceful']; - const ThreeOptions = ["Upbeat", "Downbeat"]; - - const option1Method = (value: string) => { - console.log(value); // Temporary. Should alter something later - }; - - const option2Method = (value: string) => { - console.log(value); - }; - - const option3Method = (value: string) => { - console.log(value); - }; - - const determineRender = () => { - if (clicked) return ( - <div className={'dropdown-menu'}> - <DropDownToggle - optionLabel={"Background "} - options={OneOptions} - parentFunction={option1Method} - /> - <DropDownToggle - optionLabel={"Mood "} - options={TwoOptions} - parentFunction={option2Method} - /> - <DropDownToggle - optionLabel={"Music "} - options={ThreeOptions} - parentFunction={option3Method} - /> - </div> - ); - }; - - return (<div className={'dropdown'}> - <span className={'settings-icon'} onClick={() => setClicked(!clicked)}/> - {determineRender()} - </div>); +import DropDownSelect from './DropDownSelect'; + +const DropDown = () => { + const [clicked, setClicked] = useState(false); + + const BackgroundOptions = ["One", "Two", "Three", "Four"]; + const FontOptions = ['Calibri', 'Arial', 'Sans']; + const MusicOptions = ["Upbeat", "Downbeat"]; + + const determineRender = () => { + if (clicked) return ( + <div className={"dropdown-menu"}> + <span className={'cross-icon'} onClick={() => setClicked(!clicked)}/> + <div className={'dropdowns'}> + <DropDownSelect + optionLabel={"Background"} + options={BackgroundOptions} + /> + <DropDownSelect + optionLabel={"Font"} + options={FontOptions} + /> + <DropDownSelect + optionLabel={"Sound"} + options={MusicOptions} + /> + </div> + </div> + ); + return <span className={'settings-icon'} onClick={() => setClicked(!clicked)}/> + }; + + return (<div className={'dropdown'}> + {determineRender()} + </div>); }; export default DropDown; \ No newline at end of file diff --git a/frontend/src/Components/DropDownSelect.tsx b/frontend/src/Components/DropDownSelect.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ff0339a54aac8b1d0140e21b12942468c0a865dc --- /dev/null +++ b/frontend/src/Components/DropDownSelect.tsx @@ -0,0 +1,37 @@ +import React, {useContext, useState} from 'react'; +import {OptionsContext} from "./ArtPage"; + +type props = { + options: Array<string>; // Depends on if the user is choosing strings or numbers + optionLabel: "Background" | "Sound" | "Font"; +}; + +const DropDownSelect = (props: props) => { + const context = useContext(OptionsContext); // Uses context defined in ArtPage + const currentlySelected: string = context.options[props.optionLabel.toLowerCase()]; + const [value, setValue] = useState(currentlySelected); // The currently submitted element + + const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => { // Called whenever user changes choice + event.preventDefault(); // To prevent default HTML behavior + const val = event.currentTarget.value; + setValue(val); // Update the value with the newly selected one + context.updateOption(props.optionLabel.toLowerCase(), val.toLowerCase()); // Calls the function of the parent with the submitted value + }; + + const renderOptions = () => { // To render a varying amount of options + return props.options.map(opt => <option value={opt} key={opt}>{opt}</option>); + }; + + return (<div className={'dropdown-toggle'}> + <form> + <label> + {props.optionLabel} + <select value={value} onChange={handleChange}> + {renderOptions()} + </select> + </label> + </form> + </div>); +}; + +export default DropDownSelect; \ No newline at end of file diff --git a/frontend/src/Components/DropDownToggle.tsx b/frontend/src/Components/DropDownToggle.tsx deleted file mode 100644 index 9738d4d716feecbadf53b5bd68b7fa83f5bd0c3d..0000000000000000000000000000000000000000 --- a/frontend/src/Components/DropDownToggle.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { FormEvent, useState } from 'react'; - -type props = { - parentFunction: (arg0: string) => void; - options: Array<string | number>; // Depends on if the user is choosing strings or numbers - optionLabel: string; -} - -const DropDownToggle = (props: props) => { - const [value, setValue] = useState(''); // The currently submitted element - - const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => { // Called whenever user changes choice - event.preventDefault(); // To prevent default HTML behavior - setValue(event.currentTarget.value); // Update the value with the newly selected one - }; - - const handleSubmit = (event: FormEvent) => { // Called once the form is submitted using the button - event.preventDefault(); // To prevent default HTML behavior - props.parentFunction(value); // Calls the function of the parent with the submitted value - }; - - const renderOptions = () => { // To render a varying amount of options - return props.options.map(opt => <option value={opt} key={opt}>{opt}</option>); - }; - - return (<div className={'drop-down-toggle'}> - <form onSubmit={handleSubmit}> - <label> - {props.optionLabel} - <select value={value} onChange={handleChange}> - {renderOptions()} - </select> - </label> - <input type={'submit'} value={'Submit'}/> - </form> - </div>); -}; - -export default DropDownToggle; \ No newline at end of file diff --git a/frontend/src/Components/ExhibitionPiece.tsx b/frontend/src/Components/ExhibitionPiece.tsx index 9718f2b022a40b7f603d6f91a591cefb9264d141..f0cd503e2ee133708d3af9616907d20a5931def4 100644 --- a/frontend/src/Components/ExhibitionPiece.tsx +++ b/frontend/src/Components/ExhibitionPiece.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import usePoetry from './usePoetry'; import SVGs from '../SVGs'; @@ -11,14 +11,14 @@ const ExhibitionPiece = (props: props) => { const renderPoems = () => { if (poem != null) - return poem.map(line => <p>{line}</p>) + return poem.map(line => <p>{line}</p>); return <p>Loading...</p> - } + }; return ( <div className={'exhibition-piece'}> - <div className={"title"}> - {title} + <div className={"exhibition-piece-title"}> + <h1>{title}</h1> </div> <div className={"author"}> {author} @@ -33,4 +33,4 @@ const ExhibitionPiece = (props: props) => { ); }; -export default ExhibitionPiece; \ No newline at end of file +export default ExhibitionPiece; diff --git a/frontend/src/Components/FavoriteButton.tsx b/frontend/src/Components/FavoriteButton.tsx index c926277353263a8bd0265d4213396e86c2d57404..8b61b7fd729886159e632db8db164fb3f415002a 100644 --- a/frontend/src/Components/FavoriteButton.tsx +++ b/frontend/src/Components/FavoriteButton.tsx @@ -1,7 +1,37 @@ -import React from 'react'; +import React, {useEffect, useState} from 'react'; +import active from '../Media/favorite-active.png'; +import inactive from '../Media/favorite.png'; -const FavoriteButton = () => { - return <div>FavoriteButton</div> +type props = { + pageId: number; } +const FavoriteButton = (props: props) => { + const localStorage = window.localStorage; // Retrieve the local storage + const pageId = props.pageId.toString(); // Needs to be string for local storage + // Retrieve whether or not the current page is a favorite stored locally + const initVal = localStorage.getItem(pageId) === 'true'; + const [isFavorite, setIsFavorite] = useState(initVal); + + useEffect(() => { // Runs whenever we change page. Check if current page is favorite + const favorite = localStorage.getItem(pageId) === 'true'; + setIsFavorite(favorite); // Update the displayed favorite + }, [pageId]); + + const toggleFavorite = () => { // Whenever user clicks the button + const newValue = (!isFavorite).toString(); // Invert the current choice + localStorage.setItem(pageId, newValue); // Update the storage + setIsFavorite(newValue === 'true'); // Update the state + }; + + return (<div className={"favorite-button"}> + <img + src={isFavorite ? active : inactive} + alt={"favorite-active"} + style={{width: '4rem', height: '4rem'}} + onClick={toggleFavorite} + /> + </div>) +}; + export default FavoriteButton; \ No newline at end of file diff --git a/frontend/src/Components/FavoriteLink.tsx b/frontend/src/Components/FavoriteLink.tsx new file mode 100644 index 0000000000000000000000000000000000000000..89ea88a2199be2489d5d620375dd8f0d0f082c0a --- /dev/null +++ b/frontend/src/Components/FavoriteLink.tsx @@ -0,0 +1,15 @@ +import React, {useContext} from "react"; +import {PageContext} from "./MainPage"; + +type props = { + id: number, +}; + +const FavoriteLink = (props: props) => { + const context = useContext(PageContext); + return (<li className={"fav-link"}> + <p onClick={() => context.setPage(props.id)}>{props.id}</p> + </li>) +}; + +export default FavoriteLink; \ No newline at end of file diff --git a/frontend/src/Components/LandingPage.tsx b/frontend/src/Components/LandingPage.tsx index 787ff253da9ef00222710907c4bd67f3c6700d2a..4645a7f940a898de4a893bad19d0d67f82f8bd92 100644 --- a/frontend/src/Components/LandingPage.tsx +++ b/frontend/src/Components/LandingPage.tsx @@ -1,47 +1,59 @@ -import React from 'react'; +import React, { ReactElement} from 'react'; import NavButton from './NavButton'; import "../Style/LandingPage.css" +import FavoriteLink from "./FavoriteLink"; +import LandingpageSvg from "./LandingpageSVG"; type props = { // Typescript definitions for the arguments received via props - changePage: (arg0: boolean) => void; // A function that takes a bool and returns void } type state = { // Typescript definitions for the state variables of the class - + favorites: Array<ReactElement>; } class LandingPage extends React.Component<props, state> { - constructor(props: props) { - super(props); // Allows access to props in other functions - } - - render() { - return ( - <div className={'landing-page'}> - <h1 className={'title'}> Welcome to the gallery!</h1> - - <div className={'welcome-svg'}> - <svg className={"SVG"} xmlns="http://www.w3.org/2000/svg" height="400" width="400"> - <polygon points="325,250 150,325 75,250 " fill="blue" fill-opacity="0.5"></polygon> - <polygon points="150,325 325,150 75,150 " fill="red" fill-opacity="0.5"></polygon> - <polygon points="325,250 250,75 75,150 " fill="green" fill-opacity="0.5"></polygon> - <polygon points="150,325 325,250 75,250 " fill="pink" fill-opacity="0.5"></polygon> - <polygon points="75,150 250,325 150,325 " fill="yellow" fill-opacity="0.5"></polygon> - <polygon points="150,75 75,250 250,325 " fill="orange" fill-opacity="0.5"></polygon> - </svg> - </div> - <p className={'welcome-p'}>Welcome to this interactive gallery! In here you will find unique art pieces, consisting of a quote and SVG. If you turn up your volume you may hear some wonderful tunes to accompony you during the viewing. You can change settings to get your desired look! You can also save these settings for future appretiation of the art pieces. - </p> - <div className={'navbutton left'}> - <NavButton direction={"left"} changePage={this.props.changePage} /> - </div> - <div className={'navbutton right'}> - <NavButton direction={"right"} changePage={this.props.changePage} /> - </div> - </div> - ); - } + constructor(props: props) { + super(props); // Allows access to props in other functions + this.state = {favorites: []} + } + + + + componentDidMount(): void { + const favs = []; + for (let i = 1; i < 12; i++) { + const favorite = window.localStorage.getItem(i.toString()) === 'true'; + if (favorite) favs.push(<FavoriteLink id={i}/>); + } + this.setState({favorites: favs}) + } + + render() { + return ( + <div className={'landing-page'}> + <h1 className={'title'}> Welcome to the gallery!</h1> + <div className={'welcome-svg'}> + <LandingpageSvg /> + </div> + <p className={'welcome-p'}>Welcome to this interactive gallery! In here you will find unique art pieces, + consisting of a quote and SVG. If you turn up your volume you may hear some wonderful tunes to + accompony you during the viewing. You can change settings to get your desired look! You can also + save these settings for future appretiation of the art pieces. + </p> + <div className={'favorites'}> + <p>Favorites</p> + <ul>{this.state.favorites}</ul> + </div> + <div className={'navbutton left'}> + <NavButton direction={"left"}/> + </div> + <div className={'navbutton right'}> + <NavButton direction={"right"}/> + </div> + </div> + ); + } } export default LandingPage; diff --git a/frontend/src/Components/LandingpageSVG.tsx b/frontend/src/Components/LandingpageSVG.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a7d8e168ae488a1a0527bb97f8238aad331e4821 --- /dev/null +++ b/frontend/src/Components/LandingpageSVG.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +const LandingpageSVG = () => { + + const SVGpoints = ["150,75", "250,75", "325,150", "325,250", "250,325", "150,325", "75,250", "75,150"]; + + const pickPoints = () => { + let points = [] + while(points.length < 3) { + let x = SVGpoints[Math.floor(Math.random() * SVGpoints.length)]; + while(points.indexOf(x) !== -1) { + x = SVGpoints[Math.floor(Math.random() * SVGpoints.length)]; + } + points.push(x); + } + return points.join(' '); + } + + return( + <div className={'welcome-svg'}> + <svg id="SVG" xmlns="http://www.w3.org/2000/svg" height="400" width="400"> + <polygon points={pickPoints()} fill="blue" fill-opacity="0.5" /> + <polygon points={pickPoints()} fill="red" fill-opacity="0.5" /> + <polygon points={pickPoints()} fill="green" fill-opacity="0.5" /> + <polygon points={pickPoints()} fill="yellow" fill-opacity="0.5" /> + <polygon points={pickPoints()} fill="pink" fill-opacity="0.5" /> + <polygon points={pickPoints()} fill="orange" fill-opacity="0.5" /> + </svg> + </div> + ); + +} + +export default LandingpageSVG; + + diff --git a/frontend/src/Components/MainPage.tsx b/frontend/src/Components/MainPage.tsx index 43122bae3feed75da9140623954f8f13d37f86a8..e2a55d661a74a458ca444e15bbd325d9a411f084 100644 --- a/frontend/src/Components/MainPage.tsx +++ b/frontend/src/Components/MainPage.tsx @@ -1,44 +1,56 @@ import React from 'react'; import '../Style/MainPage.css'; -import ExhibitionPiece from './ExhibitionPiece'; import LandingPage from './LandingPage'; import ArtPage from './ArtPage'; -type props = { - -} +type props = {} type state = { - currentPage: number, - totalPages: number + currentPage: number, + totalPages: number } +export const PageContext = React.createContext({ + changePage: (arg0: boolean) => { + }, setPage: (arg0: number) => { + } +}); + class MainPage extends React.Component<props, state> { - state = { currentPage: 1, totalPages: 11 }; // Index of which page to render. 0 is the landing page - - determineRender() { // Decides what page will be rendered - return this.state.currentPage == 0 ? <LandingPage changePage={this.changePage}/> : - <ArtPage changePage={this.changePage} pageId={this.state.currentPage}/>; - } - - changePage = (increment: boolean) => { - const newPage = increment ? this.state.currentPage + 1 : this.state.currentPage - 1; - this.setState({ currentPage: newPage % this.state.totalPages }); // Go to the new page or loop around if you've hit last page - } - - render() { - return ( - <div className={'main-page'}> - <div className={'header'}> - Header - </div> - <div className={'body'}> - {this.determineRender()} - </div> - </div> - ); - } + state = {currentPage: 1, totalPages: 11}; // Index of which page to render. 0 is the landing page + + determineRender() { // Decides what page will be rendered + return this.state.currentPage === 0 ? <LandingPage/> : + <ArtPage pageId={this.state.currentPage}/>; + } + + changePage = (increment: boolean) => { + const newPage = increment ? this.state.currentPage + 1 : this.state.currentPage - 1; + if (newPage === -1) + this.setState({currentPage: this.state.totalPages - 1}); // Negative modulo not supported + else + this.setState({currentPage: newPage % this.state.totalPages}); // Go to the new page or loop around if you've hit last page + }; + + setPage = (pageId: number) => { + this.setState({currentPage: pageId}); + }; + + render() { + return ( + <div className={'main-page'}> + <div className={'body'}> + <PageContext.Provider value={{ + changePage: this.changePage, + setPage: this.setPage, + }}> + {this.determineRender()} + </PageContext.Provider> + </div> + </div> + ); + } } -export default MainPage; \ No newline at end of file +export default MainPage; diff --git a/frontend/src/Components/NavButton.tsx b/frontend/src/Components/NavButton.tsx index 91ce8945d41d3613c79cfd432507a4b32fc764ce..c80a4a655b55d511bbd5bf8502e7d65c15a9384f 100644 --- a/frontend/src/Components/NavButton.tsx +++ b/frontend/src/Components/NavButton.tsx @@ -1,20 +1,29 @@ -import React from 'react'; +import React, {useContext} from 'react'; +import {PageContext} from "./MainPage"; +import leftarrow from "../Media/left-arrow.png"; +import rightarrow from "../Media/right-arrow.png"; type props = { - changePage: (arg0: boolean) => void; direction: string; } const NavButton = (props: props) => { + const context = useContext(PageContext); + console.log(context); const onClick = () => { - const increment: boolean = props.direction == "right"; - props.changePage(increment); - } + const increment: boolean = props.direction === "right"; + context.changePage(increment); + }; return ( - <button onClick={onClick}>{props.direction}</button> + <img + src={props.direction === "right" ? rightarrow : leftarrow} + alt={props.direction} + style={{ width: '4rem', height: '4rem' }} + onClick={onClick} + /> ) }; -export default NavButton; \ No newline at end of file +export default NavButton; diff --git a/frontend/src/Components/usePoetry.tsx b/frontend/src/Components/usePoetry.tsx index b87c2cb216e0a5183226476921cf54612f7db1c7..16c76029b31289d39fec88790ebc7efbd838d7ab 100644 --- a/frontend/src/Components/usePoetry.tsx +++ b/frontend/src/Components/usePoetry.tsx @@ -11,14 +11,14 @@ const poets = [ "Robert Burns", "Edward Thomas", "Richard Crashaw", -] +]; type dataResponse = { title: string; author: string; lines: Array<string>; linecount: number; -} +}; const usePoetry = (poetId: number) => { // Custom hook for retrieving poetry. Enter id and it will retrieve the corresponding poem const [poem, setPoem] = useState<Array<string> | null>(null); // The poem itself. Initialized as null @@ -26,6 +26,9 @@ const usePoetry = (poetId: number) => { // Custom hook for retrieving poetry. En const [author, setAuthor] = useState("Loading..."); useEffect(() => { // Will run every time the Id changes + setPoem(["Loading..."]); + setTitle("Loading..."); + setAuthor("Loading..."); fetch(`https://poetrydb.org/author,poemcount,linecount/${poets[poetId]};1;4`) // GET request to poetryDb .then((response) => response.json()) // Convert response to json .then((data: Array<dataResponse>) => { @@ -36,5 +39,5 @@ const usePoetry = (poetId: number) => { // Custom hook for retrieving poetry. En }, [poetId]); return [title, poem, author] as const; -} +}; export default usePoetry; \ No newline at end of file diff --git a/frontend/src/Media/cross-icon.png b/frontend/src/Media/cross-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5c4e37d417b4a97c0cc0156e73730c14730bb4 Binary files /dev/null and b/frontend/src/Media/cross-icon.png differ diff --git a/frontend/src/Media/favorite-active.png b/frontend/src/Media/favorite-active.png new file mode 100644 index 0000000000000000000000000000000000000000..1d1f0bbb7a43e1985a963298ba6437afe672aafd Binary files /dev/null and b/frontend/src/Media/favorite-active.png differ diff --git a/frontend/src/Media/favorite.png b/frontend/src/Media/favorite.png new file mode 100644 index 0000000000000000000000000000000000000000..146ccb11107c11d4cc2defd5034964ecbd9f6193 Binary files /dev/null and b/frontend/src/Media/favorite.png differ diff --git a/frontend/src/Media/left-arrow.png b/frontend/src/Media/left-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..4b01afd0f7165095251c072072e07ea59671d357 Binary files /dev/null and b/frontend/src/Media/left-arrow.png differ diff --git a/frontend/src/Media/right-arrow.png b/frontend/src/Media/right-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..91c3d80fc3340c26c907ffb1d5c85c328af86c9a Binary files /dev/null and b/frontend/src/Media/right-arrow.png differ diff --git a/frontend/src/Style/ArtPage.css b/frontend/src/Style/ArtPage.css index f8c2bdc556e8c6220eeb25286a0580f965e7808a..11cc67c9f158c07a1a80855aacb576ea8d162997 100644 --- a/frontend/src/Style/ArtPage.css +++ b/frontend/src/Style/ArtPage.css @@ -1,12 +1,16 @@ .artpage { display: grid; grid-template-columns: 1fr 2fr 1fr; - grid-template-rows: 1fr 10fr 1fr; + grid-template-rows: 1fr 11fr; height: 100vh; + grid-template-areas: + "favorite . dropdown" + "left exhibition right"; } .exhibition-piece { display: flex; + grid-area: exhibition; grid-row: 2 / 3; grid-column: 2 / 3; align-items: center; @@ -14,7 +18,17 @@ flex-direction: column; } +.exhibition-piece-title { + text-align: center; +} + +svg { + margin-top: 5%; + border: 1px solid black; +} + .dropdown { + grid-area: dropdown; grid-row: 1 / 2; grid-column: 3 / 4; display: flex; @@ -23,17 +37,53 @@ margin-top: 1rem; } -.navbutton { - grid-row: 3 / 4; - display: flex; +.favorite-button { + grid-area: favorite; + margin-left: 2rem; + margin-top: 1rem; +} + +.background-one { + background-color: rgb(175, 213, 170); +} + +.background-two { + background-color: rgb(108, 178, 209); +} + +.background-three { + background-color: rgb(254, 200, 216); +} + +.background-four { + background-color: rgb(255, 223, 211); +} + +.font-arial { + font-family: Arial, serif; +} + +.font-calibri { + font-family: Calibri, serif; +} + +.font-sans { + font-family: "Comic Sans MS", serif; } + .navbutton.left { - grid-column: 1 / 2; - flex-direction: row-reverse; + grid-area: left; margin-right: 10rem; } .navbutton.right { - grid-column: 3 / 4; + grid-area: right; margin-left: 10rem; -} \ No newline at end of file +} + +.navbutton button { + font-size: large; + width: 5rem; + height: 2rem; + margin-bottom: 3rem; +} diff --git a/frontend/src/Style/DropDown.css b/frontend/src/Style/DropDown.css index b316eb39a834efdc69d41681a3d244aa6be43b91..c5f9bb2aa41b71934f1cf508ec6616ca7c0075ad 100644 --- a/frontend/src/Style/DropDown.css +++ b/frontend/src/Style/DropDown.css @@ -4,4 +4,42 @@ background-size: contain; width: 3rem; height: 3rem; +} + +.cross-icon { + align-self: flex-end; + background-image: url("../Media/cross-icon.png"); + background-position: center; + background-size: contain; + background-repeat: no-repeat; + width: 3rem; + height: 3rem; +} + +.dropdown { + font-family: initial; +} + +.dropdown-menu { + display: flex; + flex-direction: column; + position: fixed; + background-color: whitesmoke; +} + +.dropdown-toggle { + margin: 1rem 1rem 1.5rem; + font-size: large; +} + +label { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.dropdown-toggle select { + width: 5rem; + margin-left: 1rem; + font-size: smaller; } \ No newline at end of file diff --git a/frontend/src/Style/FavoriteLink.css b/frontend/src/Style/FavoriteLink.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/frontend/src/Style/LandingPage.css b/frontend/src/Style/LandingPage.css index 01757af4697963edf8626ab0b41665a1cfac63de..7695dfb2d6487dc89c9a39975fdf2442420aad44 100644 --- a/frontend/src/Style/LandingPage.css +++ b/frontend/src/Style/LandingPage.css @@ -1,13 +1,12 @@ .landing-page { - display: grid; - grid-template-columns: 1fr 2fr 1fr; - grid-template-rows: 1fr 1fr 1fr 1fr 1fr; - gap: 0px 0px; - grid-template-areas: - ". Title ." - ". welcome-svg ." - ". welcome-svg ." - "navbutton-left welcome-p navbutton-right"; + display: grid; + grid-template-columns: 1fr 2fr 1fr; + grid-template-rows: 1fr 10fr 1fr; + height: 100vh; + grid-template-areas: + ". Title ." + "left welcomesvg right" + ". welcomep ." ; } .title { @@ -17,12 +16,18 @@ } .welcome-svg { - grid-area: welcome-svg; + grid-area: welcomesvg; place-self: center; } +.favorites { + grid-area: welcomep; + padding-top: 7rem; + padding-left: 3rem; +} + .welcome-p { - grid-area: welcome-p; + grid-area: welcomep; text-align: left; margin: 25px 50px 100px; font-family: Arial, Helvetica, sans-serif; @@ -30,9 +35,17 @@ } .navbutton.left { - grid-area: navbutton-left; + grid-area: left; + place-self: center; + position: fixed; + top: 50%; + left: 5%; } .navbutton.right { - grid-area: navbutton-right; + grid-area: right; + place-self: center; + position: fixed; + top: 50%; + right: 5%; } diff --git a/frontend/src/__tests__/ArtPage.snapshot.test.tsx b/frontend/src/__tests__/ArtPage.snapshot.test.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f7af028636aea7eba6f28c1bdc78dbe462746025 --- /dev/null +++ b/frontend/src/__tests__/ArtPage.snapshot.test.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ArtPage from "../Components/ArtPage" +import renderer from 'react-test-renderer' + +it('renders correctly', () => { + const tree = renderer + .create(<ArtPage pageId={0} />) + .toJSON(); + expect(tree).toMatchSnapshot() +}) diff --git a/frontend/src/__tests__/__snapshots__/ArtPage.snapshot.test.tsx.snap b/frontend/src/__tests__/__snapshots__/ArtPage.snapshot.test.tsx.snap new file mode 100644 index 0000000000000000000000000000000000000000..592527d7501650b9f012010f8eedf5baf7f2f4f3 --- /dev/null +++ b/frontend/src/__tests__/__snapshots__/ArtPage.snapshot.test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +<div + className="artpage background-one font-calibri" +> + <div + className="favorite-button" + > + <img + alt="favorite-active" + onClick={[Function]} + src="favorite.png" + style={ + Object { + "height": "4rem", + "width": "4rem", + } + } + /> + </div> + <div + className="dropdown" + > + <span + className="settings-icon" + onClick={[Function]} + /> + </div> + <div + className="exhibition-piece" + > + <div + className="exhibition-piece-title" + > + <h1> + Loading... + </h1> + </div> + <div + className="author" + > + Loading... + </div> + <div + className="svg-artwork" + /> + <div + className="poem" + > + <p> + Loading... + </p> + </div> + </div> + <div + className="navbutton left" + > + <img + onClick={[Function]} + src="left-arrow.png" + style={ + Object { + "height": "4rem", + "width": "4rem", + } + } + /> + </div> + <div + className="navbutton right" + > + <img + onClick={[Function]} + src="right-arrow.png" + style={ + Object { + "height": "4rem", + "width": "4rem", + } + } + /> + </div> +</div> +`;