diff --git a/src/components/atoms/PersonCard/style.module.scss b/src/components/atoms/PersonCard/style.module.scss index 23b3652099a2dab59672a6ff1494aeb0b5336a2d..ff63d91262a903223b16ab83c611204a4439bd69 100644 --- a/src/components/atoms/PersonCard/style.module.scss +++ b/src/components/atoms/PersonCard/style.module.scss @@ -74,6 +74,7 @@ justify-content: center; flex-direction: column; align-items: middle; + margin-top: 30px; } .userInfoBlock { @@ -100,6 +101,7 @@ .userCardContainer { display: flex; padding: 0; + margin-top: 30px; } .userInfoBlock { diff --git a/src/components/pages/ModuleResources/index.tsx b/src/components/pages/ModuleResources/index.tsx index 2312c4980b7c9ee0ee31ad7845193c5a8fb87ec0..ba28834997c24d5c1e4be84dfa71941e7da38592 100644 --- a/src/components/pages/ModuleResources/index.tsx +++ b/src/components/pages/ModuleResources/index.tsx @@ -1,4 +1,5 @@ import React from "react"; +import Spinner from "react-bootstrap/Spinner"; import { request, download } from "../../../utils/api"; import { api, methods } from "../../../constants/routes"; import SearchBox from "components/molecules/SearchBox"; @@ -42,7 +43,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { isLoaded: false, view: "folder", resources: [], - searchText: "", + searchText: "" }; } @@ -51,7 +52,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { const onSuccess = (data: { json: () => Promise<any> }) => { let resourceArr: Resource[] = []; - data.json().then((json) => { + data.json().then(json => { for (const key in json) { let resource = json[key]; resourceArr.push({ @@ -59,21 +60,21 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { type: resource.type, tags: resource.tags, folder: resource.category, - id: resource.id, + id: resource.id } as Resource); } this.setState({ resources: resourceArr, isLoaded: true }); }); }; const onFailure = (error: { text: () => Promise<any> }) => { - error.text().then((errorText) => { + error.text().then(errorText => { this.setState({ error: errorText, isLoaded: true }); }); }; request(api.MATERIALS_RESOURCES, methods.GET, onSuccess, onFailure, { year: this.props.year, - course: this.moduleCode, + course: this.moduleCode }); } @@ -81,7 +82,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { if (indices.length === 1) { // Only one file to download, call single file endpoint let filename = this.state.resources.filter( - (document) => document.id === indices[0] + document => document.id === indices[0] )[0].title; download(api.MATERIALS_RESOURCES_FILE(indices[0]), methods.GET, filename); } else { @@ -89,7 +90,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { download(api.MATERIALS_ZIPPED_SELECTION, methods.GET, "materials.zip", { ids: indices, course: this.moduleCode, - year: this.props.year, + year: this.props.year }); } } @@ -98,7 +99,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { download(api.MATERIALS_ZIPPED, methods.GET, category + ".zip", { year: this.props.year, course: this.moduleCode, - category: category, + category: category }); } @@ -115,7 +116,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { }); }; const onFailure = (error: { text: () => Promise<any> }) => { - error.text().then((errorText) => { + error.text().then(errorText => { console.log(errorText); }); }; @@ -131,7 +132,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { let rx = /([a-z]+)\(([^)]+)\)/gi; let match: RegExpExecArray | null; let title = item.title.toLowerCase(); - let tags = item.tags.map((tag) => tag.toLowerCase()); + let tags = item.tags.map(tag => tag.toLowerCase()); let type = item.type.toLowerCase(); while ((match = rx.exec(searchText)) !== null) { @@ -143,7 +144,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { break; case "tag": let matchSafe = match as RegExpExecArray; - if (!tags.some((tag) => tag === matchSafe[2])) { + if (!tags.some(tag => tag === matchSafe[2])) { return false; } break; @@ -152,14 +153,26 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { } } let rest = searchText.replace(rx, "").trim(); - if (tags.some((tag) => tag.indexOf(rest) !== -1)) { + if (tags.some(tag => tag.indexOf(rest) !== -1)) { return true; } return title.indexOf(rest) !== -1; } getloadedItems() { - if (!this.state.isLoaded) return <>Loading...</>; + if (!this.state.isLoaded) + return ( + <div + style={{ + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)" + }} + > + <Spinner animation="border" /> + </div> + ); if (this.state.error) return <> Error retrieving data: {this.state.error} </>; return null; @@ -180,7 +193,7 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { new Set<string>(this.state.resources.map((res: Resource) => res.folder)) ).map((title: string, id: number) => ({ title: title, - id: id, + id: id })); const view = () => { @@ -198,8 +211,8 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { resources={this.state.resources} scope={scope} searchText={this.state.searchText} - onDownloadClick={(ids) => this.handleFileDownload(ids)} - onItemClick={(id) => this.handleFileClick(id)} + onDownloadClick={ids => this.handleFileDownload(ids)} + onItemClick={id => this.handleFileClick(id)} includeInSearchResult={this.includeInSearchResult} /> @@ -207,8 +220,8 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { resources={this.state.resources} scope={scope} searchText={this.state.searchText} - onDownloadClick={(ids) => this.handleFileDownload(ids)} - onItemClick={(id) => this.handleFileClick(id)} + onDownloadClick={ids => this.handleFileDownload(ids)} + onItemClick={id => this.handleFileClick(id)} /> </> ); @@ -219,11 +232,11 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { folders={folders} resources={this.state.resources} searchText={this.state.searchText} - onDownloadClick={(ids) => this.handleFileDownload(ids)} - onSectionDownloadClick={(category) => + onDownloadClick={ids => this.handleFileDownload(ids)} + onSectionDownloadClick={category => this.handleSectionDownload(category) } - onItemClick={(id) => this.handleFileClick(id)} + onItemClick={id => this.handleFileClick(id)} includeInSearchResult={this.includeInSearchResult} /> </> @@ -234,12 +247,12 @@ class ModuleResources extends React.Component<ResourcesProps, ResourceState> { <> <TopSection onViewButtonClick={() => this.toggleView()} - currentView={this.state.view} - scope={scope} + currentView={this.state.view} + scope={scope} /> <SearchBox searchText={this.state.searchText} - onSearchTextChange={(text) => this.setState({ searchText: text })} + onSearchTextChange={text => this.setState({ searchText: text })} /> {this.getloadedItems() || view()} </> diff --git a/src/components/pages/SignIn/index.tsx b/src/components/pages/SignIn/index.tsx index 904eefd990a865a002579f15dda500ef28af3de7..e4b89ccc40290fc0ad1896b65b1603978e946ff5 100644 --- a/src/components/pages/SignIn/index.tsx +++ b/src/components/pages/SignIn/index.tsx @@ -1,9 +1,66 @@ import React from "react"; +import styles from "./style.module.scss"; +import Navbar from "react-bootstrap/Navbar"; +import Container from "react-bootstrap/Container"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import logo from "assets/images/logo.svg"; +import cx from "classnames"; +import InputGroup from "react-bootstrap/InputGroup"; +import FormControl from "react-bootstrap/FormControl"; +import Button from "react-bootstrap/Button"; const SignIn: React.FC = () => { return ( <> - Sign In + <Navbar + className={styles.navBar} + sticky="top" + expand="lg" + variant="light" + > + <Container style={{ display: "flex", justifyContent: "center" }}> + <img + src={logo} + width="30" + height="30" + className={cx("d-inline-block", "align-center")} + alt="Scientia logo" + /> + </Container> + </Navbar> + + <div className={styles.centered}> + <div style={{ marginRight: "15px", marginLeft: "15px", display: "flex", flexDirection: "column", alignItems: "center" }}> + <h1>Scientia</h1> + <i style={{ color: "gray"}}> + A Unified DoC EdTech Platform + </i> + </div> + <div style={{ marginRight: "15px", marginLeft: "15px", marginTop: "20px" }}> + <p className={styles.inputBarHeading}>Username</p> + <InputGroup className="mb-3"> + <FormControl + className={styles.inputBar} + placeholder="Username" + aria-label="Username" + aria-describedby="basic-addon1" + /> + </InputGroup> + <p className={styles.inputBarHeading}>Password</p> + <InputGroup className="mb-3"> + <FormControl + className={styles.inputBar} + placeholder="Password" + aria-label="Password" + aria-describedby="basic-addon1" + /> + </InputGroup> + <Button variant="secondary" className={styles.inputButton}> + Sign In + </Button> + </div> + </div> </> ); }; diff --git a/src/components/pages/SignIn/style.module.scss b/src/components/pages/SignIn/style.module.scss new file mode 100644 index 0000000000000000000000000000000000000000..f6b1d4522afebfe74d3ba0e5e9441874a83f3da2 --- /dev/null +++ b/src/components/pages/SignIn/style.module.scss @@ -0,0 +1,91 @@ +@import "assets/scss/custom"; + +.navBar { + padding: 0.75rem 1rem; + background: #fff; + border-bottom: 0.0625rem solid #cdd4db; +} + +.centered { + position: fixed; + left: 50%; + transform: translate(-50%, 0%); + margin-top: 75px; + max-width: 420px; + width: 90%; +} + + +$button-background: transparentize($gray-200, 0.75); +$button-border: transparentize($gray-300, 1); + +.inputBar { + border-radius: 0.5rem; + border-width: 1px; + background-color: $button-background; + border-color: $button-background; + transition: 0.2s background-color; + -webkit-transition: 0.2s background-color; + -moz-transition: 0.2s back-ground-color; +} + +.inputBar::placeholder { + color: #acb5bd; + opacity: 1; +} + +.inputBar:focus { + box-shadow: none !important; + border-color: $gray-300; + background-color: $white; +} + +.inputBarHeading { + color: $black; + font-size: 18px; + font-weight: 500; + margin-bottom: 10px; +} + +.inputButton.focus, +.inputButton:focus { + color: #000; + background-color: #f8f9fa; + border-color: #0062cc; + box-shadow: none; +} + +.inputButton { + margin-bottom: 0.625rem; + color: #fff; + background: $black; + font-weight: 500; + font-size: 1.05rem; + letter-spacing: 0; + border-width: 0rem; + line-height: 1.375rem; + height: 2.25rem; + border-radius: 0.5rem !important; + transition: 0.2s background; + -webkit-transition: 0.2s background; + -moz-transition: 0.2s background; + text-align: center; + margin-top: 30px; + width: 100%; +} + +.inputButton.active, +.inputButton:active { + color: #fff; + background: #000 !important; + font-weight: 500; + border-width: 0rem; + height: 2.25rem; + line-height: 1.375rem; +} + +.inputButton:hover { + background: $gray-800; + border-color: #fff; + color: $white; +}