Switch to site built with astro

This commit is contained in:
2021-09-23 09:26:56 -05:00
parent 679bbc7b0d
commit 996e3610ac
39 changed files with 349 additions and 1645 deletions

View File

@@ -1,58 +0,0 @@
import React, { Component } from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
} from 'react-router-dom'
import Home from './pages/Home/Home'
import Auth from './pages/Auth/Auth'
import Dashboard from './pages/Dashboard/Dashboard'
import { getSession } from './utils'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {}
}
async componentDidMount() {
// console.log(getSession())
}
render() {
return (
<Router>
<Switch>
<Route path='/register'>
<Auth />
</Route>
<Route path='/login'>
<Auth />
</Route>
<PrivateRoute
exact
path='/'
component={Dashboard}
/>
</Switch>
</Router>
)
}
}
/**
* A component to protect routes.
* Shows Auth page if the user is not authenticated
*/
const PrivateRoute = ({ component, ...options }) => {
const session = getSession()
const finalComponent = session ? Dashboard : Home
return <Route {...options} component={finalComponent} />
}

View File

@@ -1,333 +0,0 @@
.container {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
box-sizing: border-box;
overflow: hidden;
width: 100%;
height: 100vh;
}
.containerInner {
display: flex;
flex-direction: column;
box-sizing: border-box;
background: #000;
width: 100%;
height: 100%;
align-self: center;
max-width: 700px;
padding: 50px 15px 30px 15px;
}
.containerLoading {
display: flex;
flex-direction: row;
width: 100%;
height: auto;
justify-content: center;
align-content: center;
padding: 160px 0 0 0;
}
.column {
display: flex;
flex-direction: row;
box-sizing: border-box;
height: 100%;
width: 50%;
}
.row {
display: flex;
flex-direction: column;
box-sizing: border-box;
width: 100%;
}
.heroArtwork {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
}
.heroArtwork img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 500px;
user-select: none;
}
.heroTitle {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
}
.heroTitle img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 500px;
user-select: none;
}
.heroDescription {
display: flex;
text-align: center;
font-size: 18px;
line-height: 30px;
margin: 10px 0 32px 0px;
}
.error {
display: flex;
flex-direction: column;
width: 100%;
margin: 18px 0;
align-content: center;
justify-content: center;
text-align: center;
color: #FD5750;
font-size: 18px;
}
.success {
display: flex;
flex-direction: column;
width: 100%;
margin: 32px 0;
align-content: center;
justify-content: center;
text-align: center;
text-transform: lowercase;
color: #78f542;
font-size: 22px;
}
.containerRegister {}
.containerSignIn {}
.socialButtons {
display: flex;
flex-direction: row;
box-sizing: border-box;
margin: 15px auto 0px auto;
width: 100%;
}
.buttonGithub {
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
box-sizing: border-box;
margin: 0 auto 10px auto;
width: 100%;
padding: 12px;
border-radius: 4px;
font-size: 19px;
font-weight: 500;
opacity: 0.6;
transition: all 0.3s ease;
text-transform: lowercase;
}
.buttonGithub:hover {
cursor: pointer;
opacity: 1;
}
.buttonGithub img {
max-height: 28px;
margin-right: 13px;
margin-top: 1.5px;
}
.buttonGoogle {
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
box-sizing: border-box;
width: 100%;
padding: 12px;
border-radius: 4px;
font-size: 19px;
font-weight: 500;
opacity: 0.6;
transition: all 0.3s ease;
text-transform: lowercase;
}
.buttonGoogle:hover {
cursor: pointer;
opacity: 1;
}
.buttonGoogle img {
max-height: 25px;
margin-right: 11px;
margin-top: 3px;
}
.formType {
display: flex;
flex-direction: row;
margin: 0px auto 0px auto;
width: 100%;
padding: 10px 0;
font-size: 22px;
color: rgba(255,255,255,0.6);
text-transform: lowercase;
user-select: none;
}
.formTypeRegister {
display: flex;
width: 50%;
padding: 5px 40px 5px 0;
justify-content: flex-end;
border-right: 2px solid rgba(255,255,255,0.15);
}
.formTypeRegister:hover {
cursor: pointer;
}
.formTypeSignIn {
display: flex;
width: 50%;
padding: 5px 0 5px 40px;
text-align: left;
}
.formTypeSignIn:hover {
cursor: pointer;
}
.formTypeActive {
color: rgba(255,255,255,1);
}
.form {
display: flex;
flex-direction: column;
max-width: 380px;
width: 100%;
margin: 10px auto 0 auto;
text-align: center;
}
.formField {
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 25px;
}
.formLabel {
font-size: 19px;
font-weight: 500;
margin: 0 0 10px 0;
user-select: none;
display: none;
}
.formInput {
text-align: center;
font-size: 22px;
padding: 10px 0px 22px 0px;
border-bottom: 1.5px solid rgba(255,255,255,0.4);
border-top: 1.5px solid transparent;
border-right: 1.5px solid transparent;
border-left: 1.5px solid transparent;
transition: all 0.6s ease;
background: none;
outline: none;
color: #ffffff;
caret-color: white;
}
.formInput::placeholder {
text-align: center;
font-size: 22px;
color: rgba(255,255,255,0.5);
margin: 0;
}
.formInput:focus {
border-bottom: 1.5px solid rgba(255,255,255,1);
}
.formError {
margin: 10px 0 10px 0;
color: #FD5750;
font-size: 18px;
line-height: 32px;
}
.formButton {
margin: 16px auto 0 auto!important;
}
.formButton:hover {
cursor: pointer;
transform: scale(1.05);
}
.formButton:active {
cursor: pointer;
transform: scale(1);
}
.forgotPassword {
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
margin: 20px auto 5px auto;
width: 100%;
padding: 10px 0;
font-size: 19px;
color: rgba(255,255,255,0.6);
transition: all 0.3s ease;
}
.forgotPassword:hover {
cursor: pointer;
color: rgba(255,255,255,1);
}
.githubLink {
display: flex;
justify-content: center;
align-content: center;
width: 100%;
margin: 26px 0 40px 0;
}
.githubLink a {
font-size: 20px;
color: #FD5750;
opacity: 0.7;
transition: all 0.3s ease;
text-decoration: none;
}
.githubLink:hover a {
cursor: pointer;
opacity: 1;
}

View File

@@ -0,0 +1,15 @@
import { useState } from 'react';
export default function ReactCounter() {
const [count, setCount] = useState(0);
const add = () => setCount((i) => i + 1);
const subtract = () => setCount((i) => i - 1);
return (
<div id="react" className="counter">
<button onClick={subtract}>-</button>
<pre>{count}</pre>
<button onClick={add}>+</button>
</div>
);
}

View File

@@ -0,0 +1,85 @@
---
import { Markdown } from 'astro/components';
---
<article>
<div class="banner">
<p><strong>🧑‍🚀 Seasoned astronaut?</strong> Delete this file. Have fun!</p>
</div>
<section>
<Markdown>
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```
/
├── public/
│ ├── robots.txt
│ └── favicon.ico
├── src/
│ ├── components/
│ │ └── Tour.astro
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory.
Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
</Markdown>
</section>
<section>
<h2>👀 Want to learn more?</h2>
<p>Feel free to check <a href="https://github.com/snowpackjs/astro">our documentation</a> or jump into our <a href="https://astro.build/chat">Discord server</a>.</p>
</section>
</article>
<style>
article {
padding-top: 2em;
line-height: 1.5;
}
section {
margin-top: 2em;
display: flex;
flex-direction: column;
gap: 1em;
max-width: 70ch;
}
.banner {
text-align: center;
font-size: 1.2rem;
background: var(--color-light);
padding: 1em 1.5em;
padding-left: 0.75em;
border-radius: 4px;
}
pre,
code {
font-family: var(--font-mono);
background: var(--color-light);
border-radius: 4px;
}
pre {
padding: 1em 1.5em;
}
.tree {
line-height: 1.2;
}
code:not(.tree) {
padding: 0.125em;
margin: 0 -0.125em;
}
</style>

View File

@@ -1,32 +0,0 @@
import React, { Component } from 'react'
import styles from './Loading.module.css'
export default class Loading extends Component {
constructor(props) {
super(props)
this.state = {}
}
async componentDidMount() {}
render() {
return (
<div className={`${this.props.className}`}>
<div className={`${styles.container}`}>
<img
draggable={false}
alt={`Loading`}
src={
'https://s3.amazonaws.com/dashboard.serverless.com/images/icon-serverless-framework.png'
}
/>
<p>loading...</p>
</div>
</div>
)
}
}

View File

@@ -1,47 +0,0 @@
.container {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
box-sizing: border-box;
width: auto;
height: 100px;
opacity: 0.45;
text-align: center;
}
.container img {
display: flex;
align-self: center;
height: 100%;
width: auto;
max-width: 100px;
max-height: 100px;
margin: 0 0 20px 0;
animation-duration: 0.4s;
animation-name: pulse;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: ease;
filter: none;
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
}
.container p {
font-size: 22px;
color: rgba(255,255,255,0.5);
}
@keyframes pulse {
from {
transform: scale(1);
}
to {
transform: scale(1.15);
}
}

View File

@@ -1 +0,0 @@
export { default } from './Loading'

View File

@@ -1,123 +0,0 @@
html, body, #root {
display: block;
width: 100%;
height: 100%;
min-height: 100vh;
box-sizing: border-box;
background: #000;
color: #ffffff;
margin: 0;
font-family: 'Titillium Web', sans-serif;
font-weight: 500;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 18px;
}
div, h1, h2, h3, h4, h5, h6, p, span, input, button, li {
font-family: 'Titillium Web', sans-serif;
font-size: 24px;
color: #ffffff;
}
/**
* Links
*/
a, .link {
font-family: 'Titillium Web', sans-serif;
font-size: 24px;
font-weight: 400;
color: rgba(255,255,255,0.6);
text-decoration: none;
transition: all 0.14s ease;
}
a:hover, .link:hover {
cursor: pointer;
color: rgba(255,255,255,1);
}
a:active, .link:active {
color: rgba(255,255,255,0.6);
}
/**
* Buttons
*/
.buttonPrimaryLarge {
text-align: center;
font-size: 18px;
width: 100%;
max-width: 360px;
height: auto;
margin: 20px 0 0 0;
padding: 24px 24px 28px 24px;
background: #fd5750;
color: #fff;
font-family: 'Titillium Web', sans-serif;
font-size: 24px;
font-weight: 600;
border-radius: 4px;
border: 0px;
transition: all 0.14s ease;
user-select: none;
outline: none;
text-transform: lowercase;
}
.buttonPrimaryLarge:hover {
cursor: pointer;
transform: scale(1.03);
}
.buttonPrimaryLarge:active {
cursor: pointer;
transform: scale(1);
outline: none;
}
/**
* Animations
*/
.animateFadeIn {
animation: fadeIn 0.45s;
}
.animateScaleIn {
animation: scaleIn 0.35s;
}
.animateFlicker {
animation: flicker 2.5s infinite;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes flicker {
0% {
opacity: 0.3;
}
50% {
opacity: 1;
}
100% {
opacity: 0.3;
}
}

View File

@@ -1,15 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './index.css'
/**
* Render App
*/
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)

View File

@@ -1,249 +0,0 @@
import React, { Component } from 'react'
import {
Link,
withRouter,
} from 'react-router-dom'
import Loading from '../../fragments/Loading'
import styles from './Auth.module.css'
import {
userRegister,
userLogin,
userGet,
saveSession,
} from '../../utils'
class Auth extends Component {
constructor(props) {
super(props)
const pathName = window.location.pathname.replace('/', '')
this.state = {}
this.state.state = pathName
this.state.loading = true
this.state.error = null
this.state.formEmail = ''
this.state.formPassword = ''
// Bindings
this.handleFormInput = this.handleFormInput.bind(this)
this.handleFormSubmit = this.handleFormSubmit.bind(this)
this.handleFormTypeChange = this.handleFormTypeChange.bind(this)
}
/**
* Component did mount
*/
componentDidMount() {
this.setState({
loading: false
})
// Clear query params
const url = document.location.href
window.history.pushState({}, '', url.split('?')[0])
}
/**
* Handles a form change
*/
handleFormTypeChange(type) {
this.setState({ state: type },
() => {
this.props.history.push(`/${type}`)
})
}
/**
* Handle text changes within form fields
*/
handleFormInput(field, value) {
value = value.trim()
const nextState = {}
nextState[field] = value
this.setState(Object.assign(this.state, nextState))
}
/**
* Handles form submission
* @param {object} evt
*/
async handleFormSubmit(evt) {
evt.preventDefault()
this.setState({ loading: true })
// Validate email
if (!this.state.formEmail) {
return this.setState({
loading: false,
formError: 'email is required'
})
}
// Validate password
if (!this.state.formPassword) {
return this.setState({
loading: false,
formError: 'password is required'
})
}
let token
try {
if (this.state.state === 'register') {
token = await userRegister(this.state.formEmail, this.state.formPassword)
} else {
token = await userLogin(this.state.formEmail, this.state.formPassword)
}
} catch (error) {
console.log(error)
if (error.message) {
this.setState({
formError: error.message,
loading: false
})
} else {
this.setState({
formError: 'Sorry, something unknown went wrong. Please try again.',
loading: false
})
}
return
}
// Fetch user record and set session in cookie
let user = await userGet(token.token)
user = user.user
saveSession(user.id, user.email, token.token)
window.location.replace('/')
}
render() {
return (
<div className={`${styles.container} animateFadeIn`}>
<div className={styles.containerInner}>
{ /* Logo */}
<Link to='/' className={`${styles.logo}`}>
<img
draggable='false'
src={'./fullstack-app-title.png'}
alt='serverless-fullstack-application'
/>
</Link>
{ /* Loading */}
{this.state.loading && (
<div>
{< Loading className={styles.containerLoading} />}
</div>
)}
{ /* Registration Form */}
{!this.state.loading && (
<div className={styles.formType}>
<div
className={
`${styles.formTypeRegister}
${this.state.state === 'register' ? styles.formTypeActive : ''}`}
onClick={(e) => { this.handleFormTypeChange('register') }}>
Register
</div>
<div
className={
`${styles.formTypeSignIn}
${this.state.state === 'login' ? styles.formTypeActive : ''}`}
onClick={(e) => { this.handleFormTypeChange('login') }}>
Sign-In
</div>
</div>
)}
{this.state.state === 'register' && !this.state.loading && (
<div className={styles.containerRegister}>
<form className={styles.form} onSubmit={this.handleFormSubmit}>
<div className={styles.formField}>
<label className={styles.formLabel}>email</label>
<input
type='text'
placeholder='yours@example.com'
className={styles.formInput}
value={this.state.formEmail}
onChange={(e) => { this.handleFormInput('formEmail', e.target.value) }}
/>
</div>
<div className={styles.formField}>
<label className={styles.formLabel}>password</label>
<input
type='password'
placeholder='your password'
className={styles.formInput}
value={this.state.formPassword}
onChange={(e) => { this.handleFormInput('formPassword', e.target.value) }}
/>
</div>
{this.state.formError && (
<div className={styles.formError}>{this.state.formError}</div>
)}
<input
className={`buttonPrimaryLarge ${styles.formButton}`}
type='submit'
value='Register'
/>
</form>
</div>
)}
{this.state.state === 'login' && !this.state.loading && (
<div className={styles.containerSignIn}>
<form className={styles.form} onSubmit={this.handleFormSubmit}>
<div className={styles.formField}>
<label className={styles.formLabel}>email</label>
<input
type='text'
placeholder='yours@example.com'
className={styles.formInput}
value={this.state.formEmail}
onChange={(e) => { this.handleFormInput('formEmail', e.target.value) }}
/>
</div>
<div className={styles.formField}>
<label className={styles.formLabel}>password</label>
<input
type='password'
placeholder='your password'
className={styles.formInput}
value={this.state.formPassword}
onChange={(e) => { this.handleFormInput('formPassword', e.target.value) }}
/>
</div>
{this.state.formError && (
<div className={styles.formError}>{this.state.formError}</div>
)}
<input className={`buttonPrimaryLarge ${styles.formButton}`} type='submit' value='Sign In' />
</form>
</div>
)}
</div>
</div>
)
}
}
export default withRouter(Auth)

View File

@@ -1,231 +0,0 @@
.container {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
box-sizing: border-box;
overflow: hidden;
width: 100%;
height: 100vh;
}
.containerInner {
display: flex;
flex-direction: column;
box-sizing: border-box;
background: #000;
width: 100%;
height: 100%;
align-self: center;
max-width: 700px;
padding: 50px 15px 30px 15px;
}
.containerLoading {
display: flex;
flex-direction: row;
width: 100%;
height: auto;
justify-content: center;
align-content: center;
padding: 160px 0 0 0;
}
.logo {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
}
.logo img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 400px;
user-select: none;
}
.error {
display: flex;
flex-direction: column;
width: 100%;
margin: 18px 0;
align-content: center;
justify-content: center;
text-align: center;
color: #FD5750;
font-size: 18px;
}
.success {
display: flex;
flex-direction: column;
width: 100%;
margin: 32px 0;
align-content: center;
justify-content: center;
text-align: center;
text-transform: lowercase;
color: #78f542;
font-size: 22px;
}
.containerRegister {}
.containerSignIn {}
.formType {
display: flex;
flex-direction: row;
margin: 26px auto 0px auto;
width: 100%;
padding: 10px 0;
font-size: 22px;
color: rgba(255,255,255,0.6);
text-transform: lowercase;
user-select: none;
}
.formTypeRegister {
display: flex;
width: 50%;
padding: 5px 40px 5px 0;
justify-content: flex-end;
border-right: 2px solid rgba(255,255,255,0.15);
color: rgba(255,255,255,0.6);
}
.formTypeRegister:hover {
cursor: pointer;
}
.formTypeSignIn {
display: flex;
width: 50%;
padding: 5px 0 5px 40px;
text-align: left;
color: rgba(255,255,255,0.6);
}
.formTypeSignIn:hover {
cursor: pointer;
}
.formTypeActive {
color: rgba(255,255,255,1);
}
.form {
display: flex;
flex-direction: column;
max-width: 380px;
width: 100%;
margin: 10px auto 0 auto;
text-align: center;
}
.formField {
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 25px;
}
.formLabel {
font-size: 19px;
font-weight: 500;
margin: 0 0 10px 0;
user-select: none;
display: none;
}
.formInput {
text-align: center;
font-size: 22px;
padding: 10px 0px 22px 0px;
border-bottom: 1.5px solid rgba(255,255,255,0.4);
border-top: 1.5px solid transparent;
border-right: 1.5px solid transparent;
border-left: 1.5px solid transparent;
transition: all 0.6s ease;
background: none;
outline: none;
color: #ffffff;
caret-color: white;
}
.formInput::placeholder {
text-align: center;
font-size: 22px;
color: rgba(255,255,255,0.5);
margin: 0;
}
.formInput:focus {
border-bottom: 1.5px solid rgba(255,255,255,1);
}
.formError {
margin: 10px 0 10px 0;
color: #FD5750;
font-size: 18px;
line-height: 32px;
}
.formButton {
margin: 16px auto 0 auto!important;
}
.formButton:hover {
cursor: pointer;
transform: scale(1.05);
}
.formButton:active {
cursor: pointer;
transform: scale(1);
}
.forgotPassword {
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
margin: 20px auto 5px auto;
width: 100%;
padding: 10px 0;
font-size: 19px;
color: rgba(255,255,255,0.6);
transition: all 0.3s ease;
}
.forgotPassword:hover {
cursor: pointer;
color: rgba(255,255,255,1);
}
.githubLink {
display: flex;
justify-content: center;
align-content: center;
width: 100%;
margin: 26px 0 40px 0;
}
.githubLink a {
font-size: 20px;
color: #FD5750;
opacity: 0.7;
transition: all 0.3s ease;
text-decoration: none;
}
.githubLink:hover a {
cursor: pointer;
opacity: 1;
}

View File

@@ -1,82 +0,0 @@
import React, { Component } from 'react'
import {
withRouter
} from 'react-router-dom'
import styles from './Dashboard.module.css'
import {
getSession,
deleteSession
} from '../../utils'
class Dashboard extends Component {
constructor(props) {
super(props)
this.state = {}
// Bindings
this.logout = this.logout.bind(this)
}
async componentDidMount() {
const userSession = getSession()
this.setState({
session: userSession,
})
}
/**
* Log user out by clearing cookie and redirecting
*/
logout() {
deleteSession()
this.props.history.push(`/`)
}
render() {
return (
<div className={`${styles.container} animateFadeIn`}>
<div className={styles.containerInner}>
{ /* Navigation */ }
<div className={styles.navigationContainer}>
<div
className={`link`}>
{ this.state.session ? this.state.session.userEmail : '' }
</div>
<div
className={`link`}
onClick={this.logout}>
logout
</div>
</div>
{ /* Content */ }
<div className={`${styles.contentContainer}`}>
<div className={`${styles.artwork} animateFlicker`}>
<img
draggable='false'
src={'./fullstack-app-artwork.png'}
alt='serverless-fullstack-application'
/>
</div>
<div className={`${styles.welcomeMessage}`}>
Welcome to your serverless fullstack dashboard...
</div>
</div>
</div>
</div>
)
}
}
export default withRouter(Dashboard)

View File

@@ -1,92 +0,0 @@
.container {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
box-sizing: border-box;
overflow: hidden;
width: 100%;
height: 100vh;
}
.containerInner {
display: flex;
flex-direction: column;
box-sizing: border-box;
background: #000;
width: 100%;
height: 100%;
padding: 0 0 30px 0;
}
.navigationContainer {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-content: center;
box-sizing: border-box;
background: #000;
width: 100%;
height: 80px;
padding: 25px 45px 0 45px;
}
.navigationContainer div {
margin-left: 40px;
}
.contentContainer {
display: flex;
flex-direction: column;
align-content: center;
box-sizing: border-box;
background: #000;
width: 100%;
height: 100%;
padding: 7% 15px 45px 15px;
}
.welcomeMessage {
display: flex;
flex-direction: column;
align-content: center;
text-align: center;
width: 100%;
height: auto;
font-size: 28px;
}
.artwork {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
height: 250px;
}
.artwork img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 500px;
user-select: none;
}
/**
* Special
*/
::-moz-selection {
background: #fd5750;
color: #ffffff;
opacity: 1;
}
::selection {
background: #fd5750;
color: #ffffff;
opacity: 1;
}

View File

@@ -1,64 +0,0 @@
import React, { Component } from 'react'
import {
Link,
withRouter
} from 'react-router-dom'
import styles from './Home.module.css'
class Home extends Component {
constructor(props) {
super(props)
this.state = {}
}
async componentDidMount() { }
render() {
return (
<div className={`${styles.container} animateFadeIn`}>
<div className={styles.containerInner}>
{ /* Hero Artwork */}
<div className={`${styles.heroArtwork} animateFlicker`}>
<img
draggable='false'
src={'./fullstack-app-artwork.png'}
alt='serverless-fullstack-application'
/>
</div>
<div className={`${styles.heroTitle}`}>
<img
draggable='false'
src={'./fullstack-app-title.png'}
alt='serverless-fullstack-application'
/>
</div>
{ /* Hero Description */}
<div className={`${styles.heroDescription}`}>
A serverless full-stack application built with AWS Lambda, AWS HTTP API, Express.js, React & AWS DynamoDB.
</div>
{ /* Call To Action */}
<div className={`${styles.containerCta}`}>
<Link to='/register'>
<button className={`buttonPrimaryLarge`}>
Register
</button>
</Link>
<Link to='/login' className={`${styles.linkSignIn}`}>sign-in</Link>
</div>
</div>
</div>
)
}
}
export default withRouter(Home)

View File

@@ -1,105 +0,0 @@
.container {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
box-sizing: border-box;
overflow: hidden;
width: 100%;
height: 100vh;
}
.containerInner {
display: flex;
flex-direction: column;
box-sizing: border-box;
background: #000;
width: 100%;
height: 100%;
align-self: center;
max-width: 700px;
padding: 50px 15px 30px 15px;
}
.heroArtwork {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
}
.heroArtwork img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 500px;
user-select: none;
}
.heroTitle {
display: flex;
flex-direction: row;
box-sizing: border-box;
align-content: center;
justify-content: center;
width: 100%;
}
.heroTitle img {
width: auto;
height: auto;
align-self: center;
max-height: 100%;
max-width: 500px;
user-select: none;
}
.heroDescription {
display: flex;
text-align: center;
font-weight: 400;
font-size: 24px;
line-height: 38px;
margin: 32px 0px 52px 0;
}
.containerCta {
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
text-align: center;
}
.containerCta button {
margin: 0px auto 20px auto;
}
.containerCta .linkSignIn {
padding: 10px;
color: #fd5750;
opacity: 0.65;
}
.containerCta .linkSignIn:hover {
opacity: 1;
}
/**
* Special
*/
::-moz-selection {
background: #fd5750;
color: #ffffff;
opacity: 1;
}
::selection {
background: #fd5750;
color: #ffffff;
opacity: 1;
}

View File

@@ -0,0 +1,58 @@
---
// Component Imports
import Tour from '../components/Tour.astro';
// You can import components from any supported Framework here!
import ReactCounter from '../components/ReactCounter.jsx';
// Component Script:
// You can write any JavaScript/TypeScript that you'd like here.
// It will run during the build, but never in the browser.
// All variables are available to use in the HTML template below.
let title = 'My Astro Site';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
---
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>{title}</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="/style/global.css">
<link rel="stylesheet" href="/style/home.css">
<style>
header {
display: flex;
flex-direction: column;
gap: 1em;
max-width: min(100%, 68ch);
}
</style>
</head>
<body>
<main>
<header>
<div>
<img width="60" height="80" src="/assets/logo.svg" alt="Astro logo">
<h1>Welcome to <a href="https://astro.build/">Astro</a></h1>
</div>
</header>
<Tour />
<!--
- You can also use imported framework components directly in your markup!
-
- Note: by default, these components are NOT interactive on the client.
- The `:visible` directive tells Astro to make it interactive.
-
- See https://docs.astro.build/core-concepts/component-hydration/
-->
<ReactCounter client:visible />
</main>
</body>
</html>

View File

@@ -1,76 +0,0 @@
import Cookies from 'js-cookie'
/**
* Format Org and Username correctly for the Serverless Platform backend
*/
export const formatOrgAndUsername = (name = '') => {
name = name.toString().toLowerCase().replace(/[^a-z\d-]+/gi, '-')
// Remove multiple instances of hyphens
name = name.replace(/-{2,}/g, '-')
if (name.length > 40) {
name = name.substring(0, 40)
}
return name
}
/**
* Parse query parameters in a URL
* @param {*} searchString
*/
export const parseQueryParams = (searchString = null) => {
if (!searchString) {
return null
}
// Clone string
let clonedParams = (' ' + searchString).slice(1)
return clonedParams
.substr(1)
.split('&')
.filter((el) => el.length)
.map((el) => el.split('='))
.reduce(
(accumulator, currentValue) =>
Object.assign(accumulator, {
[decodeURIComponent(currentValue.shift())]: decodeURIComponent(currentValue.pop())
}),
{}
)
}
/**
* Parse hash fragment parameters in a URL
*/
export const parseHashFragment = (hashString) => {
const hashData = {}
let hash = decodeURI(hashString)
hash = hash.split('&')
hash.forEach((val) => {
val = val.replace('#', '')
hashData[val.split('=')[0]] = val.split('=')[1]
})
return hashData
}
/**
* Save session in browser cookie
*/
export const saveSession = (userId, userEmail, userToken) => {
Cookies.set('serverless', { userId, userEmail, userToken })
}
/**
* Get session in browser cookie
*/
export const getSession = () => {
const data = Cookies.get('serverless')
return data ? JSON.parse(data) : null
}
/**
* Delete session in browser cookie
*/
export const deleteSession = () => {
Cookies.remove('serverless')
}

View File

@@ -1,2 +1 @@
export * from './helpers'
export * from './api'