From a2dbcb90c6b7400eff033cb0975e724ec6b353c6 Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 2 Sep 2022 21:53:05 -0400 Subject: [PATCH] Add Quotation Carousel (#36) Made without visx, because that was easier. Closes #10. Co-authored-by: Amy Wang Reviewed-on: https://git.csclub.uwaterloo.ca/www/cs-2022-class-profile/pulls/36 Reviewed-by: j285he --- components/QuotationCarousel.module.css | 124 ++++++++++++++++++++++ components/QuotationCarousel.tsx | 130 ++++++++++++++++++++++++ data/mocks.ts | 12 +++ pages/_app.css | 5 +- pages/playground.module.css | 8 ++ pages/playground.tsx | 22 +++- 6 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 components/QuotationCarousel.module.css create mode 100644 components/QuotationCarousel.tsx diff --git a/components/QuotationCarousel.module.css b/components/QuotationCarousel.module.css new file mode 100644 index 0000000..40241da --- /dev/null +++ b/components/QuotationCarousel.module.css @@ -0,0 +1,124 @@ +.carousel { + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + gap: calc(8rem / 16); +} + +.circle { + position: absolute; + top: 30%; + right: 52%; + z-index: -1; + + background-color: var(--tertiary-background); + clip-path: circle(); +} + +.right.circle { + top: unset; + right: unset; + bottom: 30%; + left: 52%; +} + +.carouselButton { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + padding: calc(16rem / 16); + height: min-content; + + background: none; + border: none; + + cursor: pointer; +} + +.arrow { + position: relative; + width: calc(20rem / 16); + height: calc(40rem / 16); + + transition: 0.2s; +} + +.previous.arrow { + transform: rotate(180deg); +} + +.carouselButton:hover > .arrow { + translate: calc(4rem / 16); +} + +.carouselButton:hover > .previous.arrow { + translate: calc(-4rem / 16); +} + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: stretch; + gap: calc(16rem / 16); + + min-height: inherit; + height: 100%; + width: 100%; + padding: calc(30rem / 16); + + background-color: var(--translucent-accent); + border: calc(2rem / 16) solid var(--primary-text); + border-radius: calc(12rem / 16); + box-shadow: 0 calc(1rem / 16) calc(10rem / 16) var(--primary-accent); +} + +.card ul { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + position: relative; + width: 100%; + margin: 0; + padding: 0; + flex-grow: 1; +} + +.card li { + position: absolute; + left: 0; + right: 0; + margin: 0; + padding: 0; + list-style: none; + + visibility: visible; + opacity: 1; + transition: 0.1s; +} + +.card li.hidden { + visibility: hidden; + opacity: 0; +} + +.card p { + margin: 0 calc(16rem / 16); + font-weight: bold; + text-align: center; +} + +.quotationMark { + width: calc(20rem / 16); + height: calc(20rem / 16); +} + +.right.quotationMark { + transform: rotate(180deg); + align-self: end; +} diff --git a/components/QuotationCarousel.tsx b/components/QuotationCarousel.tsx new file mode 100644 index 0000000..fed81a7 --- /dev/null +++ b/components/QuotationCarousel.tsx @@ -0,0 +1,130 @@ +import React, { useState } from "react"; +import { Color } from "utils/Color"; + +import styles from "./QuotationCarousel.module.css"; + +interface QuotationCarouselProps { + data: string[]; + /** Width of the entire carousel including the buttons, in px. */ + width?: number; + /** Minimum height of the carousel, in px. */ + height?: number; + /** Diameter of the background circles, in px. Set to 0 for no circles. */ + circleDiameter?: number; + className?: string; +} + +interface CarouselButtonProps { + onClick: () => void; + isPrevious?: boolean; +} + +export function QuotationCarousel(props: QuotationCarouselProps) { + const { + data, + width = 600, + height = 100, + circleDiameter = 120, + className, + } = props; + + const [activeIdx, setActiveIdx] = useState(0); + + function showNextCard() { + setActiveIdx((activeIdx + 1) % data.length); + } + + function showPreviousCard() { + setActiveIdx((activeIdx - 1 + data.length) % data.length); + } + + return ( +
+ + + +
+ +
    + {data.map((quote, idx) => ( +
  • +

    {quote}

    +
  • + ))} +
+ +
+ +
+ ); +} + +function Circle({ + className, + diameter, +}: { + className: string; + diameter: number; +}) { + return ( +
+ ); +} + +function CarouselButton({ isPrevious, onClick }: CarouselButtonProps) { + return ( + + ); +} + +function QuotationMark({ className }: { className: string }) { + return ( + + + + ); +} diff --git a/data/mocks.ts b/data/mocks.ts index 162f5aa..3631cd6 100644 --- a/data/mocks.ts +++ b/data/mocks.ts @@ -64,3 +64,15 @@ export const moreMockCategoricalData = [ { key: "Ada", value: 2.21 }, { key: "Dart", value: 2.21 }, ]; + +export const mockQuoteData = [ + "The quick brown fox jumps over the lazy dog.", + "Sphinx of black quartz, judge my vow!", + "Pack my box with five dozen liquor jugs.", +]; + +export const mockQuoteDataLong = [ + "Here, have some quotes of varying lengths, and see how they look.", + "Hello, world!", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in enim neque. Sed sit amet convallis tellus. Integer condimentum a felis id gravida. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nullam metus libero, sagittis in consectetur in, scelerisque sed sapien. Nullam ut feugiat sapien. Praesent dictum ac ipsum ac lacinia.", +]; diff --git a/pages/_app.css b/pages/_app.css index 30aea2c..8c5d52f 100644 --- a/pages/_app.css +++ b/pages/_app.css @@ -20,6 +20,7 @@ body { --light--primary-accent-light: var(--orange); --light--primary-accent-lighter: #FFBC9F; --light--secondary-accent: #E55F98; + --light--translucent-accent: rgba(255, 231, 231, 0.75); --light--secondary-accent-light: #FEA0C8; --light--primary-heading: #D02B53; --light--primary-text: #483B35; @@ -37,6 +38,7 @@ body { --dark--primary-accent-lighter: var(--lighter-pink); --dark--secondary-accent: var(--orange); --dark--secondary-accent-light: var(--light-orange); + --dark--translucent-accent: rgba(239, 131, 157, 0.75); --dark--primary-heading: #FFC48D; --dark--secondary-heading: var(--pink); --dark--link: var(--pink); @@ -54,6 +56,7 @@ body { --primary-accent-lighter: var(--dark--primary-accent-lighter); --secondary-accent: var(--dark--secondary-accent); --secondary-accent-light: var(--dark--secondary-accent-light); + --translucent-accent: var(--dark--translucent-accent); --primary-heading: var(--dark--primary-heading); --secondary-heading: var(--dark--secondary-heading); --link: var(--dark--link); @@ -117,4 +120,4 @@ p { --card-background: var(--dark--card-background); --label: var(--dark--label); } -} \ No newline at end of file +} diff --git a/pages/playground.module.css b/pages/playground.module.css index a7aefd8..97f5eac 100644 --- a/pages/playground.module.css +++ b/pages/playground.module.css @@ -5,3 +5,11 @@ .barGraphDemo { border: calc(1rem / 16) solid black; } + +.quotationCarouselDemo { + display: flex; + flex-direction: column; + align-items: center; + gap: calc(48rem / 16); + margin: calc(32rem / 16); +} diff --git a/pages/playground.tsx b/pages/playground.tsx index 5707edb..1ff00bb 100644 --- a/pages/playground.tsx +++ b/pages/playground.tsx @@ -1,7 +1,14 @@ import { BarGraphHorizontal, BarGraphVertical } from "components/BarGraph"; -import { mockCategoricalData, moreMockCategoricalData } from "data/mocks"; +import { + mockCategoricalData, + moreMockCategoricalData, + mockQuoteData, + mockQuoteDataLong, +} from "data/mocks"; import React from "react"; +import { QuotationCarousel } from "@/components/QuotationCarousel"; + import { ColorPalette } from "../components/ColorPalette"; import { WordCloud } from "../components/WordCloud"; @@ -59,6 +66,19 @@ export default function Home() { value: word.value, }))} /> + +

+ {""} +

+
+ + +
); }