aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/colors.ts2
-rw-r--r--src/commonStyles.tsx39
-rw-r--r--src/components/InputTypes/Checkbox.tsx62
-rw-r--r--src/components/InputTypes/Radio.tsx4
-rw-r--r--src/components/InputTypes/Range.tsx101
-rw-r--r--src/components/InputTypes/Select.tsx109
-rw-r--r--src/components/InputTypes/ShortText.tsx3
-rw-r--r--src/components/InputTypes/TextArea.tsx14
-rw-r--r--src/components/Question.tsx61
-rw-r--r--src/components/ScrollToTop.tsx3
-rw-r--r--src/pages/FormPage.tsx168
-rw-r--r--src/pages/css/FormPage.css452
-rw-r--r--src/tests/pages/FormPage.test.tsx2
13 files changed, 498 insertions, 522 deletions
diff --git a/src/colors.ts b/src/colors.ts
index e9c74b1..52b48cb 100644
--- a/src/colors.ts
+++ b/src/colors.ts
@@ -1,8 +1,10 @@
export default {
blurple: "#7289DA",
+ darkerBlurple: "#4E609C",
darkButNotBlack: "#2C2F33",
notQuiteBlack: "#23272A",
greyple: "#99AAB5",
+ darkerGreyple: "#6E7D88",
error: "#f04747",
success: "#43b581"
};
diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
new file mode 100644
index 0000000..d47dea7
--- /dev/null
+++ b/src/commonStyles.tsx
@@ -0,0 +1,39 @@
+import { css } from "@emotion/react";
+
+const selectable = css`
+ -moz-user-select: text;
+ -webkit-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+`;
+
+const unselectable = css`
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+`;
+
+const textInputs = css`
+ display: inline-block;
+ width: min(20rem, 90%);
+ height: 100%;
+ min-height: 2rem;
+
+ background: whitesmoke;
+
+ color: black;
+ padding: 0 1rem;
+ font: inherit;
+
+ margin-bottom: 0;
+
+ border: 0.1rem solid black;
+ border-radius: 8px;
+`;
+
+export {
+ selectable,
+ unselectable,
+ textInputs
+};
diff --git a/src/components/InputTypes/Checkbox.tsx b/src/components/InputTypes/Checkbox.tsx
index ed02b83..07872d6 100644
--- a/src/components/InputTypes/Checkbox.tsx
+++ b/src/components/InputTypes/Checkbox.tsx
@@ -1,6 +1,7 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React, { ChangeEvent } from "react";
+import colors from "../../colors";
interface CheckboxProps {
index: number,
@@ -8,13 +9,66 @@ interface CheckboxProps {
handler: (event: ChangeEvent<HTMLInputElement>) => void
}
+const generalStyles = css`
+ label {
+ display: inline-block;
+ position: relative;
+ top: 0.25em;
+
+ width: 1em;
+ height: 1em;
+
+ margin: 1rem 0.5rem 0 0;
+ border: whitesmoke 0.2rem solid;
+ border-radius: 25%;
+
+ transition: background-color 300ms;
+ }
+
+ .unselected {
+ background-color: white;
+ }
+
+ .unselected:hover {
+ background-color: lightgray;
+ }
+
+ input {
+ position: absolute;
+ opacity: 0;
+ height: 0;
+ width: 0;
+ }
+
+ .checkmark {
+ position: absolute;
+ }
+`;
+
+const activeStyles = css`
+ .selected {
+ background-color: ${colors.blurple};
+ }
+
+ .selected .checkmark {
+ width: 0.30rem;
+ height: 0.60rem;
+ left: 0.25em;
+
+ border: solid white;
+ border-width: 0 0.2rem 0.2rem 0;
+
+ transform: rotate(45deg);
+ }
+`;
+
export default function Checkbox(props: CheckboxProps): JSX.Element {
return (
- <label>
- <label className="unselected_checkbox_label checkbox_label unselectable">
+ <label css={[generalStyles, activeStyles]}>
+ <label className="unselected">
<input type="checkbox" value={props.option}
name={`${("000" + props.index).slice(-4)}. ${props.option}`} onChange={props.handler}/>
- <span className="checkmark_span"/>
+ <span className="checkmark"/>
</label>
{props.option}<br/>
</label>
diff --git a/src/components/InputTypes/Radio.tsx b/src/components/InputTypes/Radio.tsx
index 81f8375..be0f60e 100644
--- a/src/components/InputTypes/Radio.tsx
+++ b/src/components/InputTypes/Radio.tsx
@@ -1,5 +1,5 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React, { ChangeEvent } from "react";
interface RadioProps {
@@ -11,7 +11,7 @@ interface RadioProps {
export default function Radio(props: RadioProps): JSX.Element {
return (
<label>
- <input type="radio" name={props.question_id} className="radio" onChange={props.handler}/>
+ <input type="radio" name={props.question_id} css={css`margin: 1rem 0.5rem 0 0;`} onChange={props.handler}/>
{props.option}<br/>
</label>
);
diff --git a/src/components/InputTypes/Range.tsx b/src/components/InputTypes/Range.tsx
index a0260ad..af46b05 100644
--- a/src/components/InputTypes/Range.tsx
+++ b/src/components/InputTypes/Range.tsx
@@ -1,6 +1,7 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React from "react";
+import colors from "../../colors";
interface RangeProps {
question_id: string,
@@ -8,13 +9,12 @@ interface RangeProps {
state_dict: Map<string, string | boolean | null>
}
-let last_selection: Element;
-
interface handler_props {
state_dict: Map<string, string | boolean | null>,
ref: React.RefObject<HTMLLabelElement>
}
+let last_selection: Element;
function handler(this: handler_props): void {
if (last_selection) {
last_selection.classList.toggle("selected");
@@ -29,23 +29,108 @@ function handler(this: handler_props): void {
this.state_dict.set("value", value);
}
+const containerStyles = css`
+ display: flex;
+ justify-content: space-between;
+ position: relative;
+ width: 100%;
+
+ @media (max-width: 800px) {
+ width: 20%;
+ display: block;
+ margin: 0 auto;
+
+ label span {
+ margin-left: 0;
+ transform: translateY(1.6rem) translateX(2rem);
+ }
+ }
+`;
+
+const optionStyles = css`
+ display: inline-block;
+ transform: translateX(-50%);
+ margin: 0 50%;
+
+ white-space: nowrap;
+
+ transition: transform 300ms;
+`;
+
+const rangeDotStyles = css`
+ .range_dot {
+ width: 0.8rem;
+ height: 0.8rem;
+ background-color: whitesmoke;
+
+ border: 0.2rem solid whitesmoke;
+ border-radius: 50%;
+
+ transition: background-color 300ms;
+ }
+
+ .range_dot.selected {
+ background-color: ${colors.blurple};
+ }
+
+ @media (max-width: 800px) {
+ .range_dot {
+ margin-bottom: 1.5rem;
+ }
+ }
+`;
+
+const sliderContainerStyles = css`
+ display: flex;
+ justify-content: center;
+ width: 100%;
+
+ position: absolute;
+ z-index: -1;
+
+ top: 2rem;
+
+ transition: all 300ms;
+
+ @media (max-width: 800px) {
+ width: 0.5rem;
+ height: 88%;
+
+ left: 0.32rem;
+
+ background: whitesmoke;
+ }
+`;
+
+const sliderStyles = css`
+ width: 98%; /* Needs to be slightly smaller than container to work on all devices */
+ height: 0.5rem;
+ background-color: whitesmoke;
+
+ transition: transform 300ms;
+
+ @media (max-width: 800px) {
+ display: none;
+ }
+`;
+
export default function Range(props: RangeProps): JSX.Element {
const range = props.options.map((option, index) => {
const ref: React.RefObject<HTMLLabelElement> = React.createRef();
return (
- <label key={index} ref={ref} onClick={handler.bind({state_dict: props.state_dict, ref: ref})}>
- <span>{option}</span>
+ <label key={index} ref={ref} css={css`width: 1rem;`} onClick={handler.bind({state_dict: props.state_dict, ref})}>
+ <span css={optionStyles}>{option}</span>
<div className="range_dot"/>
</label>
);
});
return (
- <div className="range">
+ <div css={[containerStyles, rangeDotStyles]}>
{ range }
- <div className="range_slider_container">
- <div className="range_slider"/>
+ <div css={sliderContainerStyles}>
+ <div css={sliderStyles}/>
</div>
</div>
);
diff --git a/src/components/InputTypes/Select.tsx b/src/components/InputTypes/Select.tsx
index 355f5d0..de763bf 100644
--- a/src/components/InputTypes/Select.tsx
+++ b/src/components/InputTypes/Select.tsx
@@ -1,5 +1,5 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React from "react";
interface SelectProps {
@@ -12,11 +12,86 @@ interface HandlerProps {
ref: React.RefObject<HTMLDivElement>
}
-class Select extends React.Component<SelectProps> {
- constructor(props: SelectProps) {
- super(props);
- }
+const containerStyles = css`
+ .container {
+ display: inline-block;
+ position: relative;
+
+ width: min(20rem, 90%);
+ height: 100%;
+ min-height: 2rem;
+
+ background: whitesmoke;
+
+ color: black;
+ text-align: center;
+
+ margin-bottom: 0;
+
+ border: 0.1rem solid black;
+ border-radius: 8px;
+
+ transition: border-radius 400ms;
+ }
+
+ .container.active {
+ height: auto;
+ border-radius: 8px 8px 0 0;
+ }
+`;
+
+const arrowStyles = css`
+ .arrow {
+ display: inline-block;
+ height: 0.5rem;
+ width: 0.5rem;
+
+ position: relative;
+ float: right;
+ right: 1em;
+ top: 0.7rem;
+
+ border: solid black;
+ border-width: 0 0.2rem 0.2rem 0;
+ transform: rotate(45deg);
+ transition: transform 400ms;
+ }
+
+ .active .arrow {
+ transform: translateY(40%) rotate(225deg);
+ }
+`;
+
+const optionContainer = css`
+ .option_container {
+ display: block;
+ position: absolute;
+ width: 100%;
+
+ /* Need to account for margin */
+ left: -0.1rem;
+
+ visibility: hidden;
+ opacity: 0;
+
+ background: whitesmoke;
+ overflow: hidden;
+
+ border: 0.1rem solid black;
+ border-radius: 0 0 8px 8px;
+ border-top: none;
+
+ transition: opacity 400ms, visibility 400ms;
+ }
+
+ .active .option_container {
+ visibility: visible;
+ opacity: 1;
+ }
+`;
+
+class Select extends React.Component<SelectProps> {
click_handler(this: HandlerProps, event: React.MouseEvent<HTMLDivElement, MouseEvent>): void {
if (!this.ref.current) {
return;
@@ -43,18 +118,24 @@ class Select extends React.Component<SelectProps> {
render(): JSX.Element {
const container_ref: React.RefObject<HTMLDivElement> = React.createRef();
- return (
- <div className="select_container" ref={container_ref} onClick={this.click_handler.bind({ref: container_ref, props: this.props})}>
- <span className="select_arrow"/>
- <span className="selected_option">...</span>
- <div className="select_options_container">
- <div className="select_options">
- { this.props.options.map((option, index) => <div key={index}><hr/><div id="option">{option}</div></div>) }
- </div>
+ const element: JSX.Element = (
+ <div className="container" ref={container_ref} onClick={this.click_handler.bind({ref: container_ref, props: this.props})}>
+ <span className="arrow"/>
+ <span className="selected_option" css={css`display: block; padding: 0.5rem 0;`}>...</span>
+
+ <div className="option_container">
+ { this.props.options.map((option, index) => (
+ <div css={css`:hover { background-color: lightgray; }`} key={index}>
+ <hr css={css`margin: 0 1rem;`}/>
+ <div id="option" css={css`padding: 0.75rem;`}>{option}</div>
+ </div>
+ )) }
</div>
</div>
);
+
+ return <div css={[containerStyles, arrowStyles, optionContainer]}>{ element }</div>;
}
}
-export default Select; \ No newline at end of file
+export default Select;
diff --git a/src/components/InputTypes/ShortText.tsx b/src/components/InputTypes/ShortText.tsx
index 182571a..1e38bcd 100644
--- a/src/components/InputTypes/ShortText.tsx
+++ b/src/components/InputTypes/ShortText.tsx
@@ -1,11 +1,12 @@
/** @jsx jsx */
import { jsx } from "@emotion/react";
import React, { ChangeEvent } from "react";
+import { textInputs } from "../../commonStyles";
interface ShortTextProps {
handler: (event: ChangeEvent<HTMLInputElement>) => void
}
export default function ShortText(props: ShortTextProps): JSX.Element {
- return <input type="text" className="short_text" placeholder="Enter Text..." onChange={props.handler}/>;
+ return <input type="text" css={textInputs} placeholder="Enter Text..." onChange={props.handler}/>;
}
diff --git a/src/components/InputTypes/TextArea.tsx b/src/components/InputTypes/TextArea.tsx
index 550adea..2b7a5f6 100644
--- a/src/components/InputTypes/TextArea.tsx
+++ b/src/components/InputTypes/TextArea.tsx
@@ -1,11 +1,21 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React, { ChangeEvent } from "react";
+import { textInputs } from "../../commonStyles";
interface TextAreaProps {
handler: (event: ChangeEvent<HTMLTextAreaElement>) => void
}
+const styles = css`
+ min-height: 20rem;
+ min-width: 40%;
+ width: 100%;
+ box-sizing: border-box;
+
+ padding: 1rem;
+`;
+
export default function TextArea(props: TextAreaProps): JSX.Element {
- return <textarea className="text_area" placeholder="Enter Text..." onChange={props.handler}/>;
+ return <textarea css={[textInputs, styles]} placeholder="Enter Text..." onChange={props.handler}/>;
}
diff --git a/src/components/Question.tsx b/src/components/Question.tsx
index 1c0fb31..66c1668 100644
--- a/src/components/Question.tsx
+++ b/src/components/Question.tsx
@@ -1,8 +1,9 @@
/** @jsx jsx */
-import { jsx } from "@emotion/react";
+import { jsx, css } from "@emotion/react";
import React, { ChangeEvent } from "react";
import { Question, QuestionType } from "../api/question";
+import { selectable } from "../commonStyles";
import create_input from "./InputTypes";
const _skip_normal_state: Array<QuestionType> = [
@@ -37,6 +38,7 @@ class RenderedQuestion extends React.Component<QuestionProp> {
this.props.public_state.set(target, value);
}
+ // This is here to allow dynamic selection between the general handler, and the textarea handler.
handler(_: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void {} // eslint-disable-line
normal_handler(event: ChangeEvent<HTMLInputElement>): void {
@@ -71,8 +73,8 @@ class RenderedQuestion extends React.Component<QuestionProp> {
// Toggle checkbox class
if (event.target.type == "checkbox" && event.target.parentElement !== null) {
- event.target.parentElement.classList.toggle("unselected_checkbox_label");
- event.target.parentElement.classList.toggle("selected_checkbox_label");
+ event.target.parentElement.classList.toggle("unselected");
+ event.target.parentElement.classList.toggle("selected");
}
}
@@ -109,17 +111,56 @@ class RenderedQuestion extends React.Component<QuestionProp> {
const question = this.props.question;
if (question.type === QuestionType.Section) {
- return <div>
- <h1 className="selectable">{question.name}</h1>
- { question.data["text"] ? <h3 className="selectable">{question.data["text"]}</h3> : "" }
- <hr className="section_header"/>
+ const styles = css`
+ h1 {
+ margin-bottom: 0;
+ }
+
+ h3 {
+ margin-top: 0;
+ }
+
+ h1, h3 {
+ text-align: center;
+ padding: 0 2rem;
+ }
+
+ @media (max-width: 500px) {
+ h1, h3 {
+ padding: 0;
+ }
+ }
+ `;
+
+ return <div css={styles}>
+ <h1 css={selectable}>{question.name}</h1>
+ { question.data["text"] ? <h3 css={selectable}>{question.data["text"]}</h3> : "" }
+ <hr css={css`color: gray; margin: 3rem 0;`}/>
</div>;
+
} else {
+ const requiredStarStyles = css`
+ span {
+ display: none;
+ }
+
+ .required {
+ display: inline-block;
+ position: relative;
+
+ color: red;
+
+ top: -0.2rem;
+ margin-left: 0.2rem;
+ }
+ `;
+
return <div>
- <h2 className="selectable">
- {question.name}<span id={question.required ? "required" : ""} className="required_star">*</span>
+ <h2 css={[selectable, requiredStarStyles]}>
+ {question.name}<span className={question.required ? "required" : ""}>*</span>
</h2>
- { create_input(this.props, this.handler) }<hr/>
+ { create_input(this.props, this.handler) }
+ <hr css={css`color: gray; margin: 3rem 0;`}/>
</div>;
}
}
diff --git a/src/components/ScrollToTop.tsx b/src/components/ScrollToTop.tsx
index 6af938d..4888dec 100644
--- a/src/components/ScrollToTop.tsx
+++ b/src/components/ScrollToTop.tsx
@@ -1,6 +1,7 @@
/** @jsx jsx */
import { jsx, css } from "@emotion/react";
import React from "react";
+import colors from "../colors";
const styles = css`
width: 2.5rem;
@@ -10,7 +11,7 @@ const styles = css`
bottom: 3rem;
right: 3rem;
- background-color: #7289DA; /* Blurple */
+ background-color: ${colors.blurple};
border-radius: 50%;
opacity: 0;
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index b966e84..647003f 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -11,12 +11,143 @@ import Loading from "../components/Loading";
import ScrollToTop from "../components/ScrollToTop";
import { Form, FormFeatures, getForm } from "../api/forms";
+import colors from "../colors";
+import { unselectable } from "../commonStyles";
interface PathParams {
id: string
}
+interface NavigationProps {
+ form_state: boolean // Whether the form is open or not
+}
+
+class Navigation extends React.Component<NavigationProps> {
+ containerStyles = css`
+ margin: auto;
+ width: 50%;
+
+ text-align: center;
+ font-size: 1.5rem;
+ white-space: nowrap;
+
+ > div {
+ display: inline-block;
+ margin: 2rem auto;
+ width: 50%;
+ }
+
+ @media (max-width: 850px) {
+ width: 100%;
+
+ > div {
+ display: flex;
+ justify-content: center;
+
+ margin: 0 auto;
+ }
+ }
+
+ .return_button {
+ text-align: left;
+ }
+
+ .return_button.closed {
+ text-align: center;
+ }
+ `;
+
+ separatorStyles = css`
+ height: 0;
+ display: none;
+
+ @media (max-width: 850px) {
+ display: block;
+ }
+ `;
+
+ returnStyles = css`
+ padding: 0.5rem 2rem;
+ border-radius: 8px;
+
+ color: white;
+ text-decoration: none;
+
+ background-color: ${colors.greyple};
+ transition: background-color 300ms;
+
+ :hover {
+ background-color: ${colors.darkerGreyple};
+ }
+ }
+ `;
+
+ submitStyles = css`
+ text-align: right;
+
+ button {
+ padding: 0.5rem 4rem;
+ cursor: pointer;
+
+ border: none;
+ border-radius: 8px;
+
+ color: white;
+ font: inherit;
+
+ background-color: ${colors.blurple};
+ transition: background-color 300ms;
+ }
+
+ button:hover {
+ background-color: ${colors.darkerBlurple};
+ }
+ `;
+
+ render(): JSX.Element {
+ let submit = null;
+ if (this.props.form_state) {
+ submit = (
+ <div css={this.submitStyles}>
+ <button form="form" type="submit">Submit</button>
+ </div>
+ );
+ }
+
+ return (
+ <div css={[unselectable, this.containerStyles]}>
+ <div className={ "return_button" + (this.props.form_state ? "" : " closed") }>
+ <Link to="/" css={this.returnStyles}>Return Home</Link>
+ </div>
+ <br css={this.separatorStyles}/>
+ { submit }
+ </div>
+ );
+ }
+}
+
+const formStyles = css`
+ margin: auto;
+ width: 50%;
+
+ @media (max-width: 800px) {
+ /* Make form larger on mobile and tablet screens */
+ width: 80%;
+ }
+`;
+
+const closedHeaderStyles = css`
+ margin-bottom: 2rem;
+ padding: 1rem 4rem;
+ border-radius: 8px;
+
+ text-align: center;
+ font-size: 1.5rem;
+
+ background-color: ${colors.error};
+`;
+
function FormPage(): JSX.Element {
const { id } = useParams<PathParams>();
@@ -33,7 +164,7 @@ function FormPage(): JSX.Element {
}
const questions = form.questions.map((question, index) => {
- return <RenderedQuestion question={question} public_state={new Map()} key={index}/>;
+ return <RenderedQuestion question={question} public_state={new Map()} key={index + Date.now()}/>;
});
function handleSubmit(event: SyntheticEvent) {
@@ -53,39 +184,22 @@ function FormPage(): JSX.Element {
const open: boolean = form.features.includes(FormFeatures.Open);
let closed_header = null;
- let submit = null;
-
- if (open) {
- submit = (
- <div className="submit_form">
- <button form="form" type="submit">Submit</button>
- </div>
- );
- } else {
- closed_header = (
- <div className="closed_header">
- <div>This form is now closed. You will not be able to submit your response.</div>
- </div>
- );
+ if (!open) {
+ closed_header = <div css={closedHeaderStyles}>This form is now closed. You will not be able to submit your response.</div>;
}
-
return (
<div>
- <HeaderBar title={form.name} description={form.description} key={2}/>
- <div css={css`${require("./css/FormPage.css")};`}>
- <form id="form" onSubmit={handleSubmit} className="unselectable">
+ <HeaderBar title={form.name} description={form.description}/>
+
+ <div>
+ <form id="form" onSubmit={handleSubmit} css={[formStyles, unselectable]}>
{ closed_header }
- {questions}
+ { questions }
</form>
- <div className="nav unselectable">
- <div className={ "nav_buttons" + (open ? "" : " closed") }>
- <Link to="/" className="return_home">Return Home</Link>
- </div>
- <br className="nav_separator"/>
- { submit }
- </div>
+ <Navigation form_state={open}/>
</div>
+
<div css={css`margin-bottom: 10rem`}/>
<ScrollToTop/>
</div>
diff --git a/src/pages/css/FormPage.css b/src/pages/css/FormPage.css
deleted file mode 100644
index 254ddef..0000000
--- a/src/pages/css/FormPage.css
+++ /dev/null
@@ -1,452 +0,0 @@
-form {
- margin: auto;
- width: 50%;
-}
-
-@media (max-width: 800px) {
- /* Make form larger on mobile and tablet screens */
- form {
- width: 80%;
- }
-}
-
-hr {
- color: gray;
- margin: 3rem 0;
-}
-
-h1 {
- font-size: 2.5rem;
- margin-bottom: 0;
- text-align: center;
-}
-
-h3 {
- margin-top: 0;
- text-align: center;
-}
-
-.section_header {
- margin-top: 1rem;
-}
-
-.closed_header {
- margin-bottom: 2rem;
- text-align: center;
-}
-
-.closed_header div {
- font-size: 1.5rem;
- background-color: #f04747;
-
- padding: 1rem 4rem;
- border-radius: 8px;
-}
-
-.unselectable {
- -moz-user-select: none;
- -webkit-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.selectable {
- -moz-user-select: text;
- -webkit-user-select: text;
- -ms-user-select: text;
- user-select: text;
-}
-
-/* ------------------------------------------------------------- */
-/* Required */
-/* ------------------------------------------------------------- */
-.required_star {
- display: none;
-}
-
-#required.required_star {
- display: inline-block;
- position: relative;
-
- color: red;
-
- top: -0.2rem;
- margin-left: 0.2rem;
-}
-
-/* ------------------------------------------------------------- */
-/* Checkboxes */
-/* ------------------------------------------------------------- */
-.checkbox_label {
- display: inline-block;
- position: relative;
- top: 0.25em;
-
- width: 1em;
- height: 1em;
-
- margin: 1rem 0.5rem 0 0;
- border: whitesmoke 0.2rem solid;
- border-radius: 25%;
-
- -webkit-transition: background-color 300ms ease-in-out;
- transition: background-color 300ms ease-in-out;
-}
-
-.checkbox_label input {
- position: absolute;
- opacity: 0;
- height: 0;
- width: 0;
-}
-
-.unselected_checkbox_label {
- background-color: white;
-}
-
-.unselected_checkbox_label:hover {
- background-color: lightgray;
-}
-
-.selected_checkbox_label {
- background-color: #7289DA; /* Blurple */
-}
-
-.checkmark_span {
- position: absolute;
-}
-
-.selected_checkbox_label .checkmark_span {
- width: 0.30rem;
- height: 0.60rem;
- left: 0.25em;
-
- border: solid white;
- border-width: 0 0.2rem 0.2rem 0;
-
- -webkit-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- transform: rotate(45deg);
-}
-
-/* ------------------------------------------------------------- */
-/* Radio */
-/* ------------------------------------------------------------- */
-input[type="radio"] {
- margin: 1rem 0.5rem 0 0;
-}
-
-/* ------------------------------------------------------------- */
-/* Select */
-/* ------------------------------------------------------------- */
-.select_container {
- display: inline-block;
- position: relative;
-
- width: min(20rem, 90%);
- height: 100%;
- min-height: 2rem;
-
- background: whitesmoke;
-
- color: black;
- text-align: center;
-
- margin-bottom: 0;
-
- border: 0.1rem solid black;
- border-radius: 8px;
-
- -webkit-transition: border-radius 400ms;
- transition: border-radius 400ms;
-}
-
-.select_container.active {
- height: auto;
- border-radius: 8px 8px 0 0;
-}
-
-.select_arrow {
- display: inline-block;
- height: 0.5rem;
- width: 0.5rem;
-
- position: relative;
- float: right;
- right: 1em;
- top: 0.7rem;
-
- border: solid black;
- border-width: 0 0.2rem 0.2rem 0;
-
- -webkit-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- transform: rotate(45deg);
-
- -webkit-transition: transform 400ms;
- transition: transform 400ms;
-}
-
-.select_container.active .select_arrow {
- -webkit-transform: translateY(40%) rotate(225deg);
- -ms-transform: translateY(40%) rotate(225deg);
- transform: translateY(40%) rotate(225deg);
-}
-
-.selected_option {
- display: block;
- padding: 0.5rem 0;
-}
-
-.select_options_container {
- position: relative;
- width: 100%;
-
- /* Need to account for margin */
- left: -0.1rem;
-}
-
-.select_options {
- display: block;
- position: absolute;
- width: 100%;
-
- visibility: hidden;
- opacity: 0;
-
- background: whitesmoke;
- overflow: hidden;
-
- border: 0.1rem solid black;
- border-radius: 0 0 8px 8px;
- border-top: none;
-
- -webkit-transition: opacity 400ms, visibility 400ms;
- transition: opacity 400ms, visibility 400ms;
-}
-
-.select_container.active .select_options {
- visibility: visible;
- opacity: 1;
-}
-
-.select_options > div > div {
- padding: 0.75rem;
-}
-
-.select_options > div:hover {
- background-color: lightgray;
-}
-
-.select_options hr {
- margin: 0 1rem;
-}
-
-/* ------------------------------------------------------------- */
-/* Text Types */
-/* ------------------------------------------------------------- */
-.short_text, .text_area {
- display: inline-block;
- width: min(20rem, 90%);
- height: 100%;
- min-height: 2rem;
-
- background: whitesmoke;
-
- color: black;
- padding: 0 1rem;
- font: inherit;
-
- margin-bottom: 0;
-
- border: 0.1rem solid black;
- border-radius: 8px;
-}
-
-.text_area {
- min-height: 20rem;
- min-width: 40%;
- width: 100%;
- box-sizing: border-box;
-
- padding: 1rem;
-}
-
-/* ------------------------------------------------------------- */
-/* Range */
-/* ------------------------------------------------------------- */
-.range {
- display: flex;
- justify-content: space-between;
- position: relative;
- width: 100%;
-}
-
-.range label {
- width: 1rem;
-}
-
-.range label span {
- display: inline-block;
- transform: translateX(-50%);
- margin: 0 50%;
-
- white-space: nowrap;
-
- transition: transform 300ms;
-}
-
-.range_dot {
- width: 0.8rem;
- height: 0.8rem;
- background-color: whitesmoke;
-
- border: 0.2rem solid whitesmoke;
- border-radius: 50%;
-
- transition: background-color 300ms;
-}
-
-.range_dot.selected {
- background-color: #7289DA; /* Blurple */
-}
-
-.range_slider_container {
- display: flex;
- justify-content: center;
- width: 100%;
-
- position: absolute;
- z-index: -1;
-
- top: 2rem;
-
- transition: all 300ms;
-}
-
-.range_slider {
- width: 98%; /* Needs to be slightly smaller than container to work on all devices */
- height: 0.5rem;
- background-color: whitesmoke;
-
- transition: transform 300ms;
-}
-
-/* ------------------------------------------------------------- */
-/* Mobile Range */
-/* ------------------------------------------------------------- */
-@media (max-width: 800px){
- .range {
- width: 20%;
- display: block;
- margin: 0 auto;
- }
-
- .range_dot {
- margin-bottom: 1.5rem;
- }
-
- .range label span {
- margin-left: 0;
- transform: translateY(1.6rem) translateX(2rem);
- }
-
- .range_slider_container {
- width: 0.5rem;
- left: 0.32rem;
- height: 88%;
-
- background: whitesmoke;
- z-index: -1;
- }
-
- .range_slider {
- display: none;
- }
-}
-
-/* ------------------------------------------------------------- */
-/* Navigation */
-/* ------------------------------------------------------------- */
-.nav {
- margin: auto;
- width: 50%;
-
- text-align: center;
- font-size: 1.5rem;
- white-space: nowrap;
-}
-
-.nav_separator {
- height: 0;
- display: none;
-}
-
-.nav > div {
- display: inline-block;
- margin: 2rem auto;
- width: 50%;
-}
-
-.nav_buttons {
- text-align: left;
-}
-
-.nav_buttons.closed {
- text-align: center;
-}
-
-.submit_form {
- text-align: right;
-}
-
-/* Tile Buttons Vertically On Smaller Devices */
-@media (max-width: 850px) {
- .nav {
- width: 100%;
- }
-
- .nav_separator {
- display: block;
- }
-
- .nav > div {
- display: flex;
- justify-content: center;
-
- margin: 0 auto;
- }
-}
-
-.return_home {
- padding: 0.5rem 2rem;
- border-radius: 8px;
-
- color: white;
- text-decoration: none;
-
- background-color: #99AAB5; /* Gray-ish */
- transition: background-color 300ms;
-}
-
-.return_home:hover {
- background-color: #6E7D88; /* Darker gray-ish */
-}
-
-.submit_form button {
- padding: 0.5rem 4rem;
- cursor: pointer;
-
- border: none;
- border-radius: 8px;
-
- color: white;
- font: inherit;
-
- background-color: #7289DA; /* Blurple */
- transition: background-color 300ms;
-}
-
-.submit_form button:hover {
- background-color: #4E609C; /* Darker blurple */
-}
diff --git a/src/tests/pages/FormPage.test.tsx b/src/tests/pages/FormPage.test.tsx
index f7ecc32..62577cd 100644
--- a/src/tests/pages/FormPage.test.tsx
+++ b/src/tests/pages/FormPage.test.tsx
@@ -27,6 +27,6 @@ test("calls api method to load form", () => {
Object.defineProperty(forms, "getForm", {value: jest.fn(oldImpl)});
render(<Router><Route history={history}><FormPage /></Route></Router>);
-
+
expect(forms.getForm).toBeCalled();
});