From d2cc29d22203cfea0adc61ceaa72ba936070045a Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Mon, 4 Jan 2021 02:29:27 +0300 Subject: Updates HeaderBar Changes header bar component to accept a description, and render it properly on different screens. Additionally adds a button to return to the home page. Updates tests. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- src/components/HeaderBar/index.tsx | 131 ++++++++++++++++++++++++++----------- src/components/HeaderBar/logo.svg | 3 + 2 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 src/components/HeaderBar/logo.svg (limited to 'src/components') diff --git a/src/components/HeaderBar/index.tsx b/src/components/HeaderBar/index.tsx index dfe3957..439851d 100644 --- a/src/components/HeaderBar/index.tsx +++ b/src/components/HeaderBar/index.tsx @@ -1,59 +1,110 @@ /** @jsx jsx */ -import { css, jsx } from "@emotion/react"; +import { jsx, css } from "@emotion/react"; import Header1 from "./header_1.svg"; import Header2 from "./header_2.svg"; +import Logo from "./logo.svg"; + +import { Link } from "react-router-dom"; interface HeaderBarProps { - title?: string + title?: string + description?: string } const headerImageStyles = css` -z-index: -1; -top: 0; -position: absolute; -width: 100%; -transition: height 1s; + * { + z-index: -1; + top: 0; + position: absolute; + width: 100%; + transition: height 1s; + } +`; + +const headerTextStyles = css` + transition: margin 1s; + font-family: "Uni Sans", "Hind", "Arial", sans-serif; + + margin: 0 2rem 10rem 2rem; + + .title { + font-size: 3vmax; + margin-bottom: 0; + } + + .description { + font-size: 1.5vmax; + } + + .title, .description { + transition: font-size 1s; + } + + @media (max-width: 480px) { + margin-top: 7rem; + text-align: center; + + .title { + font-size: 5vmax; + } + + .description { + font-size: 2vmax; + } + } +`; + +const homeButtonStyles = css` + svg { + transform: scale(0.25); + transition: top 300ms, transform 300ms; + + @media (max-width: 480px) { + transform: scale(0.15); + } + } + + * { + position: absolute; + top: -10rem; + right: 1rem; + + z-index: 0; + transform-origin: right; + + @media (max-width: 700px) { + top: -11.5rem; + } + + @media (max-width: 480px) { + top: -12.5rem; + } + } `; -function HeaderBar({ title }: HeaderBarProps): JSX.Element { +function HeaderBar({ title, description }: HeaderBarProps): JSX.Element { if (!title) { title = "Python Discord Forms"; } - - return
+ + return (
- - +
+ + +
+ +
+

{title}

+

{description}

+
+ + + +
-

- {title} -

-
; + ); } export default HeaderBar; diff --git a/src/components/HeaderBar/logo.svg b/src/components/HeaderBar/logo.svg new file mode 100644 index 0000000..e7f43fc --- /dev/null +++ b/src/components/HeaderBar/logo.svg @@ -0,0 +1,3 @@ + +image/svg+xml + -- cgit v1.2.3 From c8046900fd94baa5264e15a527c24346be024b73 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Mon, 4 Jan 2021 02:33:35 +0300 Subject: Implements Scroll Button Adds a scroll to top button to the landing page, and form pages to make navigation easier on long pages. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- src/components/ScrollToTop.tsx | 87 ++++++++++++++++++++++++++++++++++++++++++ src/pages/LandingPage.tsx | 7 ++-- 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/components/ScrollToTop.tsx (limited to 'src/components') diff --git a/src/components/ScrollToTop.tsx b/src/components/ScrollToTop.tsx new file mode 100644 index 0000000..6af938d --- /dev/null +++ b/src/components/ScrollToTop.tsx @@ -0,0 +1,87 @@ +/** @jsx jsx */ +import { jsx, css } from "@emotion/react"; +import React from "react"; + +const styles = css` + width: 2.5rem; + height: 2.5rem; + + position: fixed; + bottom: 3rem; + right: 3rem; + + background-color: #7289DA; /* Blurple */ + border-radius: 50%; + + opacity: 0; + transition: opacity 300ms; + + :after { + display: inline-block; + content: ""; + + position: fixed; + bottom: 3.5rem; + right: 3.65rem; + + border: solid whitesmoke; + border-width: 0.35rem 0.35rem 0 0; + padding: 0.4rem; + + transform: rotate(-45deg); + } + + @media (max-width: 800px) { + bottom: 1.5rem; + right: 1.5rem; + + :after { + bottom: 2rem; + right: 2.15rem; + } + } +`; + +let last_ref: React.RefObject; + +class ScrollToTop extends React.Component { + constructor(props: Record) { + super(props); + last_ref = React.createRef(); + } + + handleScroll(): void { + if (!last_ref.current) return; + + if (window.pageYOffset > 250) { + last_ref.current.style.opacity = "1"; + } else { + last_ref.current.style.opacity = "0"; + } + } + + componentDidMount(): void { + // Register event handler + window.addEventListener("scroll", this.handleScroll, {passive: true}); + } + + componentDidUpdate(): void { + // Hide previous iterations, and register handler for current one + if (last_ref.current) { + last_ref.current.style.opacity = "0"; + } + + window.addEventListener("scroll", this.handleScroll, {passive: true}); + } + + componentWillUnmount(): void { + // Unregister handler + window.removeEventListener("scroll", this.handleScroll); + } + + render(): JSX.Element { + return
window.scrollTo({top: 0, behavior: "smooth"})}/>; + } +} + +export default ScrollToTop; diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 124bbcf..af968ad 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -4,10 +4,11 @@ import { useEffect, useState } from "react"; import HeaderBar from "../components/HeaderBar"; import FormListing from "../components/FormListing"; - -import { getForms, Form } from "../api/forms"; import OAuth2Button from "../components/OAuth2Button"; import Loading from "../components/Loading"; +import ScrollToTop from "../components/ScrollToTop"; + +import { getForms, Form } from "../api/forms"; function LandingPage(): JSX.Element { const [forms, setForms] = useState(); @@ -25,8 +26,8 @@ function LandingPage(): JSX.Element { return
+
-
Date: Mon, 4 Jan 2021 03:57:10 +0300 Subject: Implements Input Types Adds functionality and JSX for all input types. Adds a dispatcher that can pick and return the needed element. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- src/components/InputTypes/Checkbox.tsx | 22 ++++++++++ src/components/InputTypes/Code.tsx | 11 +++++ src/components/InputTypes/Radio.tsx | 18 +++++++++ src/components/InputTypes/Range.tsx | 52 ++++++++++++++++++++++++ src/components/InputTypes/Select.tsx | 60 ++++++++++++++++++++++++++++ src/components/InputTypes/ShortText.tsx | 11 +++++ src/components/InputTypes/TextArea.tsx | 11 +++++ src/components/InputTypes/index.tsx | 71 +++++++++++++++++++++++++++++++++ 8 files changed, 256 insertions(+) create mode 100644 src/components/InputTypes/Checkbox.tsx create mode 100644 src/components/InputTypes/Code.tsx create mode 100644 src/components/InputTypes/Radio.tsx create mode 100644 src/components/InputTypes/Range.tsx create mode 100644 src/components/InputTypes/Select.tsx create mode 100644 src/components/InputTypes/ShortText.tsx create mode 100644 src/components/InputTypes/TextArea.tsx create mode 100644 src/components/InputTypes/index.tsx (limited to 'src/components') diff --git a/src/components/InputTypes/Checkbox.tsx b/src/components/InputTypes/Checkbox.tsx new file mode 100644 index 0000000..ed02b83 --- /dev/null +++ b/src/components/InputTypes/Checkbox.tsx @@ -0,0 +1,22 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; +import React, { ChangeEvent } from "react"; + +interface CheckboxProps { + index: number, + option: string, + handler: (event: ChangeEvent) => void +} + +export default function Checkbox(props: CheckboxProps): JSX.Element { + return ( + + ); +} diff --git a/src/components/InputTypes/Code.tsx b/src/components/InputTypes/Code.tsx new file mode 100644 index 0000000..51ca98d --- /dev/null +++ b/src/components/InputTypes/Code.tsx @@ -0,0 +1,11 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; +import React, { ChangeEvent } from "react"; + +interface CodeProps { + handler: (event: ChangeEvent) => void +} + +export default function Code(props: CodeProps): JSX.Element { + return ; +} diff --git a/src/components/InputTypes/Radio.tsx b/src/components/InputTypes/Radio.tsx new file mode 100644 index 0000000..81f8375 --- /dev/null +++ b/src/components/InputTypes/Radio.tsx @@ -0,0 +1,18 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; +import React, { ChangeEvent } from "react"; + +interface RadioProps { + option: string, + question_id: string, + handler: (event: ChangeEvent) => void +} + +export default function Radio(props: RadioProps): JSX.Element { + return ( + + ); +} diff --git a/src/components/InputTypes/Range.tsx b/src/components/InputTypes/Range.tsx new file mode 100644 index 0000000..a0260ad --- /dev/null +++ b/src/components/InputTypes/Range.tsx @@ -0,0 +1,52 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; +import React from "react"; + +interface RangeProps { + question_id: string, + options: Array, + state_dict: Map +} + +let last_selection: Element; + +interface handler_props { + state_dict: Map, + ref: React.RefObject +} + +function handler(this: handler_props): void { + if (last_selection) { + last_selection.classList.toggle("selected"); + } + + const dot: Element = this.ref.current!.lastElementChild!; // eslint-disable-line + dot.classList.toggle("selected"); + + last_selection = dot; + + const value: string = this.ref.current!.textContent!; //eslint-disable-line + this.state_dict.set("value", value); +} + +export default function Range(props: RangeProps): JSX.Element { + const range = props.options.map((option, index) => { + const ref: React.RefObject = React.createRef(); + return ( +