From 6902de6880cc415240a2960f81aa2bee6ec685aa Mon Sep 17 00:00:00 2001 From: "Ioana Circu (circui)" Date: Sat, 16 May 2020 15:03:05 +0000 Subject: [PATCH] Initial commit --- .gitignore | 5 + README.md | 6 + chromium_page_load.png | Bin 0 -> 6560 bytes index.js | 101 ++++++++++++++ modules/list.js | 61 ++++++++ modules/user.js | 69 +++++++++ package.json | 26 ++++ public/.DS_Store | Bin 0 -> 6148 bytes public/core.js | 59 ++++++++ public/favicon.ico | Bin 0 -> 15406 bytes public/images/amber.png | Bin 0 -> 11875 bytes public/images/desktop.png | Bin 0 -> 5591 bytes public/images/green.png | Bin 0 -> 11664 bytes public/images/offline.png | Bin 0 -> 16094 bytes public/images/online.png | Bin 0 -> 15411 bytes public/images/red.png | Bin 0 -> 10012 bytes public/images/tablet.png | Bin 0 -> 4957 bytes public/index.html | 41 ++++++ public/modules/404.js | 4 + public/modules/home.js | 38 +++++ public/modules/login.js | 38 +++++ public/modules/logout.js | 9 ++ public/modules/register.js | 24 ++++ public/script.js | 64 +++++++++ public/style.css | 271 ++++++++++++++++++++++++++++++++++++ public/views/404.html | 2 + public/views/home.html | 11 ++ public/views/login.html | 6 + public/views/logout.html | 2 + public/views/register.html | 7 + public/website.appcache.old | 15 ++ 31 files changed, 859 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 chromium_page_load.png create mode 100644 index.js create mode 100644 modules/list.js create mode 100644 modules/user.js create mode 100644 package.json create mode 100644 public/.DS_Store create mode 100644 public/core.js create mode 100644 public/favicon.ico create mode 100644 public/images/amber.png create mode 100644 public/images/desktop.png create mode 100644 public/images/green.png create mode 100644 public/images/offline.png create mode 100644 public/images/online.png create mode 100644 public/images/red.png create mode 100644 public/images/tablet.png create mode 100644 public/index.html create mode 100644 public/modules/404.js create mode 100644 public/modules/home.js create mode 100644 public/modules/login.js create mode 100644 public/modules/logout.js create mode 100644 public/modules/register.js create mode 100644 public/script.js create mode 100644 public/style.css create mode 100644 public/views/404.html create mode 100644 public/views/home.html create mode 100644 public/views/login.html create mode 100644 public/views/logout.html create mode 100644 public/views/register.html create mode 100644 public/website.appcache.old diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32e6245 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +.DS_Store +package-lock.json +*.db +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..aff0037 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ + +# Single Page Application Template + +This is a simple template for a [single-page application](https://medium.com/@NeotericEU/single-page-application-vs-multiple-page-application-2591588efe58). It is written in pure JavaScript and uses NodeJS and Koa for its backend, both as the [RESTful API](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/) and to serve the client code. + +It uses SQLite for data persistence. diff --git a/chromium_page_load.png b/chromium_page_load.png new file mode 100644 index 0000000000000000000000000000000000000000..faf15b847fa9898855e42cc791896ab283d8bdb1 GIT binary patch literal 6560 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 a0k}Pk { + console.log('---------------------------------------------------------------') + console.log('GET /') + try { + await send(ctx, 'public/index.html') + } catch(err) { + console.log(err.message) + await send(ctx, 'public/index.html') + } +}) + +router.post('/register', koaBody, async ctx => { + console.log('---------------------------------------------------------------') + console.log('POST /register') + const user = await new User(dbName) + try { + const body = typeof ctx.request.body === 'string' ? JSON.parse(ctx.request.body) : ctx.request.body + await user.register(body.user, body.pass, body.email) + ctx.status = 201 + ctx.body = {status: 'success', msg: 'account created'} + } catch(err) { + ctx.status = 422 + ctx.body = {status: "error", msg: err.message} + } finally { + user.tearDown() + } +}) + +router.get('/login', async ctx => { + console.log('---------------------------------------------------------------') + console.log('GET /login') + const user = await new User(dbName) + try { + const header = ctx.request.headers.authorization + const hash = header.split(' ')[1] + const status = await user.login(hash) + ctx.status = 200 + ctx.body = {status: 'success', msg: 'valid credentials'} + } catch(err) { + ctx.status = 401 + ctx.body = {status: "error", msg: err.message} + } finally { + user.tearDown() + } +}) + +router.post('/lists', koaBody, async ctx => { + console.log('---------------------------------------------------------------') + console.log('POST /lists') + const list = await new List(dbName) + try { + const body = typeof ctx.request.body === 'string' ? JSON.parse(ctx.request.body) : ctx.request.body + console.log(body) + const header = ctx.request.headers.authorization + console.log(header) + body.id = await list.add(header, body.listname, body.description) + ctx.status = 201 + ctx.body = {status: 'success', msg: 'list added', data: ctx.body} + } catch(err) { + ctx.status = 422 + ctx.body = {status: "error", msg: err.message} + } finally { + list.tearDown() + } +}) + +router.get('/lists', async ctx => { + console.log('---------------------------------------------------------------') + console.log('GET /lists') + const list = await new List(dbName) + try { + const lists = await list.getLists(ctx.request.headers.authorization) + console.log(lists) + ctx.status = 200 + ctx.body = {status: 'success', msg: 'lists found', data: lists} + } catch(err) { + ctx.status = 422 + ctx.body = {status: "error", msg: err.message} + } +}) + +app.use(router.routes()) +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/modules/list.js b/modules/list.js new file mode 100644 index 0000000..b3e6408 --- /dev/null +++ b/modules/list.js @@ -0,0 +1,61 @@ + +const sqlite = require('sqlite-async') +const atob = require('atob') + +module.exports = class List { + + constructor(dbName = ':memory:') { + return (async() => { + this.db = await sqlite.open(dbName) + // we need this table to store the user accounts + const sql = 'CREATE TABLE IF NOT EXISTS lists\ + (id INTEGER PRIMARY KEY AUTOINCREMENT,\ + userid TEXT, listname TEXT, description TEXT,\ + date TEXT DEFAULT CURRENT_TIMESTAMP);' + await this.db.run(sql) + return this + })() + } + + async add(token, listname, description) { + try { + console.log(token) + const hash = token.substring(6) //removes the Basic_ bit + console.log(hash) + const str = atob(hash) + console.log(str) + const username = str.split(':')[0] + console.log(username) + const sql = `INSERT INTO lists(userid, listname, description)\ + VALUES("${username}", "${listname}", "${description}")` + console.log(sql) + const recordID = await this.db.run(sql) + console.log(recordID.lastID) + return recordID.lastID + // return 42 + } catch(err) { + console.log(err.message) + throw err + } + } + + async getLists(token) { + try { + const hash = token.substring(6) //removes the Basic_ bit + const str = atob(hash) + const username = str.split(':')[0] + const sql = `SELECT * FROM lists WHERE userid="${username}" ORDER BY date DESC;` + console.log(sql) + const lists = await this.db.all(sql) + console.log(lists) + return lists + } catch(err) { + console.log(err.message) + throw err + } + } + + async tearDown() { + await this.db.close() + } +} diff --git a/modules/user.js b/modules/user.js new file mode 100644 index 0000000..93aed09 --- /dev/null +++ b/modules/user.js @@ -0,0 +1,69 @@ + +const crypto = require('crypto') +const bcrypt = require('bcrypt-promise') +const sqlite = require('sqlite-async') +const atob = require('atob') + +const saltRounds = 10 + +module.exports = class User { + + constructor(dbName = ':memory:') { + return (async() => { + this.db = await sqlite.open(dbName) + // we need this table to store the user accounts + const sql = 'CREATE TABLE IF NOT EXISTS users\ + (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT, email TEXT);' + await this.db.run(sql) + return this + })() + } + + /** + * registers a new user + * @param {String} user the chosen username + * @param {String} pass the chosen password + * @returns {Boolean} returns true if the new user has been added + */ + async register(user, pass, email) { + try { + Array.from(arguments).forEach( val => { + if(val.length === 0) throw new Error('missing field') + }) + console.log(`user: ${user}, pass: ${pass}, email: ${email}`) + let sql = `SELECT COUNT(id) as records FROM users WHERE user="${user}";` + const data = await this.db.get(sql) + if(data.records !== 0) throw new Error(`username \'${user}\' already in use`) + sql = `SELECT COUNT(id) as records FROM users WHERE email="${email}";` + const emails = await this.db.get(sql) + if(emails.records !== 0) throw new Error(`email address \'${email}\' is already in use`) + pass = await bcrypt.hash(pass, saltRounds) + sql = `INSERT INTO users(user, pass, email) VALUES("${user}", "${pass}", "${email}")` + await this.db.run(sql) + return true + } catch(err) { + console.log('ERROR IN USER.REGISTER') + console.log(err.message) + throw err + } + } + + /** + * checks to see if a set of login credentials are valid + * @param {String} hash the base64-encoded string user:pass + * @returns {Boolean} returns true if credentials are valid + */ + async login(hash) { + const data = atob(hash).split(':') + let sql = `SELECT user, pass FROM users WHERE email="${data[0]}";` + const record = await this.db.get(sql) + if(!record) throw new Error(`email \'${data[0]}\' not found`) + const valid = await bcrypt.compare(data[1], record.pass) + if(!valid) throw new Error(`invalid password for account \'${data[0]}\'`) + return true + } + + async tearDown() { + await this.db.close() + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ef7c40d --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "todo", + "version": "1.0.0", + "engines": { + "node": "12.14.x" + }, + "description": "Simple todo app as an SPA", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Mark J Tyers", + "license": "ISC", + "dependencies": { + "atob": "^2.1.2", + "bcrypt": "^4.0.1", + "bcrypt-promise": "^2.0.0", + "koa": "^2.11.0", + "koa-body": "^4.1.1", + "koa-router": "^8.0.8", + "koa-send": "^5.0.0", + "koa-static": "^5.0.0", + "sqlite-async": "^1.0.12" + } +} diff --git a/public/.DS_Store b/public/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..61820f0185bd6ca6655c631b8187ad8c2e17d59b GIT binary patch literal 6148 zcmeHKO>Wab6n@jDjok>5MWvRVH%Kh1Dk)S|g^;YYEV@Gqf(4+~u1#a)dZO5=DIq8u z?ttI~T!jm85Doy}o0(S5PZ2AG&^+nQ_dN5y8T%W1#zRD+GmP3qO(JsOjI}is3yj;@ z=WNN;G=M_&u}yC%KT73kn9gO}3afxs;9paKzuh{WlB5B}RQY~oh!$QJ9>VYaRECJC zL9Z#G3rZ9#14l*rtG{M_onfsa>m0l@jAB-Zt6Z`1yWFtM`(dhbzlHrY$%|I&yI5MT zt*q7^$7wjXoLAkREW1Te4D(Jfc)?dsf}$6i_^FiXbsU7xlDIr>t{=#(2$C!wC~^|T zNO}1@$s$>HhJ)lXM9xUTEC$IUyV(a!FEYs+ijZ;iLS(cT{7-3L44vFmKyZ9h6X zIlp{2dO!Z~nT5ilh*eS9ZG%_v1;Lae7u`XY%IpmF%vpn48AZ_QE%fbC0qxRhg~dnY zRp+IS90|^l(ghm-n8|i2$NUX2P9MGBH1D4(^UjQdE>-W_;O4XQNId6N#)^7NVk&1d z)r?m&*O3!bh&~gH!S7*!`|4wq0NztI5+g?oG^qB28?g4r3YfRk;WfaTRlq7>6{sq} z>w^bp^bJlls-**kIsyP|s8)uUe;SzM8T1WKG@=D2G!>|+!W=P#rla07dA`AkMolMS z4j;mdEX)Z-sL|2Cr_xFI8f|G6unJ5ou&ghey#GJG`TRdkvR76CtH6JyfT$gI4?B1y zv$xJY9PhOr`~=R%c@vF_g2HUaD&Vbn6Rr$x9tS|*;6x*8VD?8q$zThsz+YA17nK;z AkN^Mx literal 0 HcmV?d00001 diff --git a/public/core.js b/public/core.js new file mode 100644 index 0000000..62161fa --- /dev/null +++ b/public/core.js @@ -0,0 +1,59 @@ + +export function generateToken(user, pass) { + const token = `${user}:${pass}` + const hash = btoa(token) + return `Basic ${hash}` +} + +export async function login() { + if(!getCookie('authorization')) throw new Error('cookie not found') + const options = { headers: { Authorization: getCookie('authorization') } } + const response = await fetch('/login',options) + const status = response.status + console.log(`HTTP status code: ${status}`) + if(response.status === 401) throw new Error('status 401 NOT AUTHORIZED') +} + +// from plainjs.com +export function setCookie(name, value, days) { + const d = new Date + d.setTime(d.getTime() + 24*60*60*1000*days) + document.cookie = `${name}=${value};path=/;expires=${d.toGMTString()}` +} + +export function getCookie(name) { + const v = document.cookie.match(`(^|;) ?${name}=([^;]*)(;|$)`) + return v ? v[2] : null +} + +export function deleteCookie(name) { + setCookie(name, '', -1) +} + +export function onlineStatus() { + if(navigator.onLine) { + return true + } else { + return false + } +} + +export function showMessage(message) { + console.log(message) + document.querySelector('aside p').innerText = message + document.querySelector('aside').classList.remove('hidden') + setTimeout( () => document.querySelector('aside').classList.add('hidden'), 2000) +} + +export function getLocation() { + if(navigator.geolocation) { + console.log('location supported') + navigator.geolocation.getCurrentPosition( position => { + const pos = position.coords + const locString = `lat: ${pos.latitude}, lon: ${pos.longitude}` + document.getElementById('location').innerHTML = `${locString}
 ` + }) + } else { + console.log('geolocation not supported') + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d8b77792acdc477f751a3525fc81fd23c068c0e8 GIT binary patch literal 15406 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 L;m_~?Zw>qx+BlQ< literal 0 HcmV?d00001 diff --git a/public/images/amber.png b/public/images/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..3f492083bc13ff08b6a66de72786de42e9858b6b GIT binary patch literal 11875 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 J6@MrF@IO6(Ksx{c literal 0 HcmV?d00001 diff --git a/public/images/green.png b/public/images/green.png new file mode 100644 index 0000000000000000000000000000000000000000..499f166d9bb0b98212a71bf2143bcae17cfe40c4 GIT binary patch literal 11664 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 literal 0 HcmV?d00001 diff --git a/public/images/offline.png b/public/images/offline.png new file mode 100644 index 0000000000000000000000000000000000000000..755791ef9f0a7e54129b250602f059d18707b255 GIT binary patch literal 16094 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 literal 0 HcmV?d00001 diff --git a/public/images/online.png b/public/images/online.png new file mode 100644 index 0000000000000000000000000000000000000000..5218fd39251798fb28a0c04e451805ebe356113b GIT binary patch literal 15411 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 McQh5t<;|b`ACgpTXaE2J literal 0 HcmV?d00001 diff --git a/public/images/red.png b/public/images/red.png new file mode 100644 index 0000000000000000000000000000000000000000..89496c7a81764a1d6cf3c9fb7d63e6182594fc29 GIT binary patch literal 10012 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 literal 0 HcmV?d00001 diff --git a/public/images/tablet.png b/public/images/tablet.png new file mode 100644 index 0000000000000000000000000000000000000000..8394acac0460e17240731268e8c71424a8e886d5 GIT binary patch literal 4957 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 + + + + + Simple SPA + + + + + + + + +
+

+

You are currently online

+
+ + +
+ +
+
+

+

+

+

+
+ + diff --git a/public/modules/404.js b/public/modules/404.js new file mode 100644 index 0000000..cfa9ddf --- /dev/null +++ b/public/modules/404.js @@ -0,0 +1,4 @@ + +export async function setup() { + document.querySelector('h1').innerText = '404 PAGE NOT FOUND!' +} diff --git a/public/modules/home.js b/public/modules/home.js new file mode 100644 index 0000000..f95953d --- /dev/null +++ b/public/modules/home.js @@ -0,0 +1,38 @@ + +import { getCookie, login, showMessage } from '../core.js' + +export async function setup() { + try { + console.log('MAIN SCRIPT') + await login() + displayLists() + document.querySelector('h1').innerText = 'My Lists' + document.querySelector('main > button').addEventListener('click', event => { + console.log('adding a new note') + // await displayLists() + }) + } catch(err) { + showMessage(err.message) + window.location.href = '/#login' + } +} + +async function displayLists() { + console.log('DISPLAY LISTS') + // const request= new Request('/lists') + // request.url = '/lists' + const options = { headers: { Authorization: getCookie('authorization') } } + const response = await fetch('/lists',options) + // const head = new Headers({authorization: getCookie('authorization')}) + // const options = { method: 'post', headers: head } + // request.headers = head + const json = await response.json() + // console.log(await response.json()) + const page = document.querySelector('main') + for(const list of json.data) { + console.log(list) + const section = document.createElement('article') + section.innerHTML = `

${list.listname}

${list.description}

` + page.appendChild(section) + } +} diff --git a/public/modules/login.js b/public/modules/login.js new file mode 100644 index 0000000..b349e93 --- /dev/null +++ b/public/modules/login.js @@ -0,0 +1,38 @@ + +import { generateToken, getCookie, setCookie, showMessage, getLocation } from '../core.js' + +export function setup() { + const cookie = getCookie('authorization') + if(getCookie('authorization')) { + console.log('authorised') + window.location.href = '/#home' + } + document.querySelector('h1').innerText = 'Log In' + document.querySelector('form').addEventListener('submit', async event => await login(event)) +} + +async function login() { + try { + event.preventDefault() + const elements = [...document.forms['login'].elements] + const data = {} + elements.forEach( el => { + if(el.name) data[el.name] = el.value + }) + const token = generateToken(data.email, data.pass) + console.log(token) + const options = { headers: { Authorization: token } } + const response = await fetch('/login',options) + const json = await response.json() + console.log(json) + const status = response.status + console.log(`HTTP status code: ${response.status}`) + if(response.status === 401) throw new Error(json.msg) + if(response.status === 200) { + setCookie('authorization', token, 1) + window.location.href = '#home' + } + } catch(err) { + showMessage(err.message) + } +} \ No newline at end of file diff --git a/public/modules/logout.js b/public/modules/logout.js new file mode 100644 index 0000000..80c9c01 --- /dev/null +++ b/public/modules/logout.js @@ -0,0 +1,9 @@ + +import { deleteCookie, getCookie } from '../core.js' + +export async function setup() { + navigator.geolocation.clearWatch(getCookie('geoID')) + deleteCookie('authorization') + deleteCookie('geoID') + window.location.href = '/#login' +} diff --git a/public/modules/register.js b/public/modules/register.js new file mode 100644 index 0000000..d3a6df7 --- /dev/null +++ b/public/modules/register.js @@ -0,0 +1,24 @@ + +import { showMessage } from '../core.js' + +export async function setup() { + document.querySelector('h1').innerText = 'Register a New Account' + document.querySelector('form').addEventListener('submit', await registerAccount) +} + +async function registerAccount(event) { + event.preventDefault() + try { + const elements = [...document.forms['register'].elements] + const data = {} + elements.forEach( el => { if(el.name) data[el.name] = el.value }) + console.log(data) + const options = { method: 'post', body: JSON.stringify(data) } + const response = await fetch('/register',options) + const json = await response.json() + if(response.status === 422) throw new Error(`422 Unprocessable Entity: ${json.msg}`) + window.location.href = '/#login' + } catch(err) { + showMessage(err.message) + } +} diff --git a/public/script.js b/public/script.js new file mode 100644 index 0000000..154d954 --- /dev/null +++ b/public/script.js @@ -0,0 +1,64 @@ + +/** + * ROUTER + * This module needs to be imported into your top-level html file. + * It checks the URL fragment/hash and dynamically loads the correct view + * and module. + * There needs to be an html view file and a module file for each fragment. + */ + +import { getCookie, getLocation, onlineStatus } from '../core.js' + +let geoID + +// event triggered when the page first loads, triggers the 'hashchange' event +window.addEventListener('DOMContentLoaded', async event => { + geoID = await navigator.geolocation.watchPosition(getLocation) + loadPage() +}) + +// event gets triggered every time the URL fragment (hash) changes in the address bar +window.addEventListener('hashchange', async event => await loadPage()) + +window.addEventListener('online', toggleOnlineIndicator) +window.addEventListener('offline', toggleOnlineIndicator) + +function toggleOnlineIndicator(event) { + const label = document.querySelector('header strong') + if(onlineStatus()) { + label.classList.remove('offline') + label.innerText = 'online' + document.querySelector('footer > p#connectivity').style.backgroundImage = 'url(images/online.png)' + } else { + label.classList.add('offline') + label.innerText = 'offline' + document.querySelector('footer > p#connectivity').style.backgroundImage = 'url(images/offline.png)' + } +} + +async function loadPage() { + try { + getLocation() + // the 'name' of the page is the name in the fragment without the # character + // if there is no fragment/hash, assume we want to load the home page (ternary operator) + console.log(typeof location.hash) + const pageName = location.hash ? location.hash.replace('#', '') : 'home' + console.log('location updated') + // load the html page that matches the fragment and inject into the page DOM + document.querySelector('main').innerHTML = await (await fetch(`./views/${pageName}.html`)).text() + // dynamically importing the code module who's name matches the page name + const module = await import(`./modules/${pageName}.js`) + // run the setup function in whatever module has been loaded + console.log('---------------------------------------------------------------') + console.log(`${pageName.toUpperCase()}: ${window.location.protocol}//${window.location.host}/${window.location.hash}`) + // window.location contains the contents of the browser address-bar (FYI) + // console.log(`${window.location.protocol}//${window.location.host}/${window.location.hash}`) + if(getCookie('authorization')) console.log(`Authorization: "${getCookie('authorization')}"`) + module.setup() + } catch(err) { + // errors are triggered if script can't find matching html fragment or script + console.log(`error: ${err.message}, redirecting to 404 page`) + console.log(err) + window.location.href = '/#404' + } +} diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..e699187 --- /dev/null +++ b/public/style.css @@ -0,0 +1,271 @@ + +body, p, h1, h2, h3, ul { + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; +} + +p { + margin-bottom: 0.6em; + font-size: 1em; +} + +h1 { + margin-bottom: 0.5em; + font-size: 1.6em; + color: #555; +} + +header { + width: 100%; + background-color: #CCC; + padding: 1em; + padding-bottom: 0.5em; +} + +header p { + font-size: 0.9em; + color: #555; + margin: 0.2em; +} + +header strong { + color: green; +} + +.offline { + color: red; +} + +main { + padding: 1em; +} + +footer { + position: absolute; + bottom: 0; + background-color: #DDD; + width: 100%; + padding: 0; +} + +input { + width: 200px; + font-size: 1.2em; +} + +ul { + padding: 0; + margin: 0; + list-style-type: none; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + background-color: #CCCC; + /* height: 3em; */ + justify-content: flex-start; +} + +li { + padding: 0; + margin: 0; + display: inline-block; + flex-basis: 8em; + /* border: 1px solid grey; */ + height: 2em; + text-align: center; + text-transform: uppercase; + padding-top: 1em; + font-size: 0.8em; +} + +li > a { + text-decoration: none; + color: black; +} + +li:hover a { + color: white; +} + +li:hover { + background-color: grey; +} + +aside { + border: 0.1em solid red; + padding: 1em; + margin: 1em; + color: red; + font-size: 1em; + border-radius: 0.5em; +} + +.hidden { + display: none; +} + +button { + background-color: grey; + border: 2px solid grey; + color: white; + padding: 0.5em 1em; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 0.8em; + margin-top: 0.5em; +} + +button:hover { + color: grey; + background-color: white; +} + +input[type="text"], input[type="email"], input[type="password"], textarea, select { + font-size: 0.8em; + width: 300px; + border: 1px solid #CCC; + padding: 0.5em; + margin-top: 0.3em; +} +main > button { + position: fixed; + z-index: 2; + bottom: 0.5em; + right: 0.5em; +} + +main > section { + display: absolute; + top: 15em; + width: 315px; + border: 2px solid #CCC; + padding: 1em; + padding-bottom: 3em; + margin: auto; +} + +main > section h2 { + margin-bottom: 0.5em; + color: #555; +} + +main > section button { + float: right; +} + +article { + background-color: #CCCC; + margin-bottom: 0.5em; + padding: 1em; + padding-bottom: 3em; +} + +article > h2 { + margin: 0; + padding: 0; + /* display: inline-block; */ + font-size: 1.2em; + /* background-color: blue; */ + height: 2em; + flex-grow: 1; +} + +article > p { + margin: 0; + padding: 0; + /* display: inline-block; */ + /* background-color: yellow; */ + height: 2em; + flex-grow: 2; +} + +article > button { + margin: 0; + display: block; + height: 3em; + flex-grow: 1; + float: right; +} + +footer { + position: fixed; + bottom: 0; + left: 0; + background-color: #DDDD; + width: 100%; + padding: 0; + margin: 0; + padding-left: 0.3em; + padding-top: 0.5em; +} + +footer > p#device, footer > p#resolution, footer > p#connectivity { + display: inline-block; + height: 1.5em; + width: 1.5em; + margin: 0; + margin-top: 0.3em; + margin-bottom: 0.3em; + background-size: contain; +} + +footer > p#connectivity { + background-image: url(images/online.png); +} + +footer > p#location { + display: inline-block; + margin: 0; + height: 0.7em; + margin-left: 0.3em; + font-size: 0.8em; + color: gray; +} + +/* ==================== DETECTS IF SCREEN SUPPORTS TOUCH ==================== */ + +/* Detects a touch-screen device */ +@media (hover: none) and (pointer: coarse) { + footer > p#device { + background-image: url(images/tablet.png); + background-size: contain; + } + +} + +/* Detects a non-touch screen with a mouse or trackpad */ +@media (hover: hover) and (pointer: fine) { + footer > p#device { + background-image: url(images/desktop.png); + background-size: contain; + } +} + +/* ======================== DETECTS THE SCREEN WIDTH ======================== */ + +/* Narrow screen */ +@media (max-width: 400px) { + footer > p#resolution { + background-image: url(images/red.png); + background-size: contain; + } +} + +/* Medium width screen */ +@media (min-width: 401px) and (max-width: 800px) { + footer > p#resolution { + background-image: url(images/amber.png); + background-size: contain; + } +} + +/* Wide screen */ +@media (min-width: 801px) { + footer > p#resolution { + background-image: url(images/green.png); + background-size: contain; + } +} diff --git a/public/views/404.html b/public/views/404.html new file mode 100644 index 0000000..8e6f1ef --- /dev/null +++ b/public/views/404.html @@ -0,0 +1,2 @@ + +

404 PAGE NOT FOUND!

diff --git a/public/views/home.html b/public/views/home.html new file mode 100644 index 0000000..36966fb --- /dev/null +++ b/public/views/home.html @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/public/views/login.html b/public/views/login.html new file mode 100644 index 0000000..f1fab4a --- /dev/null +++ b/public/views/login.html @@ -0,0 +1,6 @@ + +
+


+


+

+
diff --git a/public/views/logout.html b/public/views/logout.html new file mode 100644 index 0000000..b3d5339 --- /dev/null +++ b/public/views/logout.html @@ -0,0 +1,2 @@ + +

Log Out

diff --git a/public/views/register.html b/public/views/register.html new file mode 100644 index 0000000..992e4ad --- /dev/null +++ b/public/views/register.html @@ -0,0 +1,7 @@ + +
+


+


+


+

+
diff --git a/public/website.appcache.old b/public/website.appcache.old new file mode 100644 index 0000000..39c1607 --- /dev/null +++ b/public/website.appcache.old @@ -0,0 +1,15 @@ +CACHE MANIFEST +style.css +script.js +core.js +favicon.ico +modules/404.js +modules/home.js +modules/login.js +modules/logout.js +modules/register.js +views/404.html +views/home.html +views/login.html +views/logout.html +views/register.html \ No newline at end of file