Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
feat: ✨ implement loading screen and theme storage
Browse files Browse the repository at this point in the history
  • Loading branch information
BSoDium committed May 1, 2022
1 parent dd75fb4 commit 137fe46
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/App.global.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
@import "./sass/pages/default";
@import "./sass/pages/credentials";
@import "./sass/pages/dashboard";
@import "./sass/components/cards";
@import "./sass/components/buttons";
@import "./sass/components/theme-switcher";
@import "./sass/components/spinner";
@import "./sass/layout/basic";

@import "./sass/themes/dark";
Expand Down
9 changes: 6 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ export function isDev(): boolean {
* @returns {JSX.Element}
*/
function App(): JSX.Element {
const [theme, setTheme] = useState(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
const [theme, setTheme] = useState(localStorage.getItem('theme') || (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));
const session = new Session();
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
// save theme preference to local storage
localStorage.setItem('theme', newTheme);
};

return (
Expand All @@ -40,7 +43,7 @@ function App(): JSX.Element {
<Route
path="dashboard"
element={(
<PrivacyWrapper session={session}>
<PrivacyWrapper theme={theme} session={session}>
<Dashboard />
</PrivacyWrapper>
)}
Expand Down
38 changes: 27 additions & 11 deletions src/components/PrivacyWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useState } from 'react';
import { Navigate } from 'react-router-dom';
import Session from 'utils/Session';
import Spinner from 'components/Spinner';

function PrivacyWrapper({ children, session }: { children: React.ReactNode, session: Session }) {
export declare interface PrivacyWrapperProps {
children: React.ReactNode,
session: Session,
theme?: string,
}

function PrivacyWrapper({ children, theme, session }: PrivacyWrapperProps): JSX.Element {
const [isLoading, setIsLoading] = useState(true);
const [isLoggedIn, setIsLoggedIn] = useState(false);

Expand All @@ -14,20 +20,30 @@ function PrivacyWrapper({ children, session }: { children: React.ReactNode, sess
});
}, [session]);

return (
isLoading ? (
<div className="privacy-wrapper">
<div className="spinner-wrapper">
Loading
<div className="spinner" />
</div>
// display a spinner if the API request is still loading
let content;
if (isLoading) {
content = (
<div className="loading-page-wrapper">
<Spinner message="Logging in" />
</div>
) : (
);
} else {
content = (
<div className="privacy-wrapper">
{isLoggedIn ? children : <Navigate to="/login" />}
</div>
)
);
}
return (
<div className={theme}>
{content}
</div>
);
}

PrivacyWrapper.defaultProps = {
theme: 'light',
};

export default PrivacyWrapper;
25 changes: 25 additions & 0 deletions src/components/Spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

/**
* A lightweight spinner component.
* @returns {JSX.Element}
*/
export default function Spinner({ message }: {message?: string}): JSX.Element {
return (
<div className="spinner-wrapper">
<div className="lds-ring">
<div />
<div />
<div />
<div />
</div>
<div className="spinner-message">
{message}
</div>
</div>
);
}

Spinner.defaultProps = {
message: 'Loading...',
};
8 changes: 7 additions & 1 deletion src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import React from 'react';
export default function Dashboard() {
return (
<div className="dashboard-wrapper">
This is the Dashboard !
<div className="dashboard-header" />
<div className="dashboard-body">
<div className="card centered centered-content">
<h1>This is a motherfucking dashboard</h1>
<h2>And it&apos;s fucking beautiful</h2>
</div>
</div>
</div>
);
}
69 changes: 69 additions & 0 deletions src/sass/components/_spinner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
@import "../themes/dark";
@import "../themes/light";

@mixin themable($theme-name, $theme-map) {
.#{$theme-name} {
.loading-page-wrapper {
background-color: map-get($theme-map, bg);
color: map-get($theme-map, text);
width: 100vw;
height: 100vh;
}

.spinner-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}

.spinner-message {
font-size: 1.4rem;
margin-bottom: 20px;
}

// credit to loading.io for the spinner

.lds-ring {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 47px;
height: 47px;
margin: 6px;
border: 6px solid map-get($theme-map, icons);
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: map-get($theme-map, icons) transparent transparent
transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
}

@include themable(light, $light);
@include themable(dark, $dark);
2 changes: 1 addition & 1 deletion src/sass/layout/_basic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
}

.centered {
position: relative;
position: absolute; // TODO: this should probably be changed
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
Expand Down
29 changes: 29 additions & 0 deletions src/sass/pages/_dashboard.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@import "../themes/dark";
@import "../themes/light";

@mixin themable($theme-name, $theme-map) {
.#{$theme-name} {
.dashboard-wrapper {
background-color: map-get($theme-map, bg);
color: map-get($theme-map, text);
width: 100vw;
height: 100vh;
}

.dashboard-header {
box-sizing: border-box;
width: 100%;
height: 80px;
border-bottom: 1px solid map-get($theme-map, card-border);
background-color: map-get($theme-map, card-bg);
}

.dahsboard-body {
box-sizing: border-box;
width: 100%;
}
}
}

@include themable(light, $light);
@include themable(dark, $dark);
1 change: 1 addition & 0 deletions src/sass/themes/_dark.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$dark: (
bg: #0d1117,
icons: #d3d3d3,
text: #d3d3d3,
text-secondary: #a5a5a5,
text-href: #2c80e0,
Expand Down
1 change: 1 addition & 0 deletions src/sass/themes/_light.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$light: (
bg: #fff,
icons: #000,
text: #000,
text-secondary: #575757,
text-href: #246bbb,
Expand Down
11 changes: 9 additions & 2 deletions src/utils/Session.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isDev } from 'App';

export declare interface LoginData {
email: string;
password: string;
Expand All @@ -17,7 +19,7 @@ export default class Session {
* - no actual bearer token is generated
* - all the data displayed in the UI is mocked
*/
devlogin() {
async devlogin() {
this.bearerToken = 'dev';
}

Expand Down Expand Up @@ -51,6 +53,8 @@ export default class Session {
},
});
this.bearerToken = '';
// remove the token from local storage
localStorage.removeItem('bearerToken');
}

/**
Expand All @@ -74,7 +78,8 @@ export default class Session {
Authorization: `Bearer ${this.bearerToken}`,
},
});
return response.ok;

return isDev() ? true : response.ok;
}

/**
Expand All @@ -90,5 +95,7 @@ export default class Session {
body: JSON.stringify(accountData),
});
this.bearerToken = await response.json();
// save the token to local storage
localStorage.setItem('bearerToken', this.bearerToken);
}
}

0 comments on commit 137fe46

Please sign in to comment.