Commit bdddedf3 authored by Geovanny's avatar Geovanny

Nav bar done and some login

parent 541ddfa2
......@@ -3,6 +3,7 @@ server/node_modules/
server/.env
discord/.env
discord/__pycache__
web/node_modules
*.pyc
__pycache__
.vscode
\ No newline at end of file
......@@ -45,7 +45,7 @@ class UnitManager(commands.Cog):
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
if msg.content.lower() != 'yes':
if not(msg.content.lower() == 'yes' or msg.content.lower() == 'y'):
return await ctx.send('Operation aborted')
try:
await Api.put('/unit/{0}'.format(data['id']), params)
......@@ -91,13 +91,13 @@ class UnitManager(commands.Cog):
embed.add_field(name='ID', value=unit_data.id, inline=True)
embed.add_field(name='Name', value=unit_data.name)
embed.add_field(name='Type', value=unit_data.type, inline=True)
embed.add_field(name='Type', value=unit_data.unit_type, inline=True)
embed.add_field(name='HP', value=unit_data.hp)
embed.add_field(name='Stars', value=(unit_data.stars/2))
embed.add_field(name='Speed', value=unit_data.speed, inline=True)
embed.add_field(name='Range', value=unit_data.range)
embed.add_field(name='Ammo', value=unit)
embed.add_field(name='Leadership Cost', value=unit_data.leadership)
embed.add_field(name='Troop Count', value=unit_data.troop_count, inline=True)
embed.add_field(name='Range', value=unit_data.unit_range)
embed.add_field(name='Ammo', value=unit_data.ammo)
embed.add_field(name='Troop Count', value=unit_data.tc, inline=True)
embed.add_field(name='Piercing AP', value=unit_data.pap, inline=True)
embed.add_field(name='Piercing Dg', value=unit_data.pd, inline=True)
embed.add_field(name='Piercing Df', value=unit_data.pdf, inline=True)
......@@ -108,6 +108,8 @@ class UnitManager(commands.Cog):
embed.add_field(name='Blunt Dg', value=unit_data.bd, inline=True)
embed.add_field(name='Blunt Df', value=unit_data.bdf, inline=True)
embed.add_field(name='Labour', value=unit_data.labour, inline=True)
embed.add_field(name='Hero Level', value=unit_data.hl, inline=True)
embed.add_field(name='Leadership Cost', value=unit_data.ld)
await ctx.send(embed=embed)
......@@ -127,7 +129,7 @@ class UnitManager(commands.Cog):
await self.createUnitTable(ctx, units_data)
async def createUnitTable(self, ctx, data):
return await EmbedStyle.createPages(self.bot, ctx, data, 5, self.createUnitPage)
return await EmbedStyle.createPages(self.bot, ctx, data, 10, self.createUnitPage)
def createUnitPage(self, data, minI, maxI):
embed = discord.Embed(color=0x19212d)
......
class Unit(object):
def __init__(self, id, name, type, stars=0, hp=0, pap=0, pd=0, sap=0, sd=0, bap=0, bd=0, pdf=0, sdf=0, bdf=0, leadership=0, troop_count=0, hero_level=0, speed=0, range=0, ammo=0, labour=0,
def __init__(self, id, name, unit_type, stars=0, hp=0, pap=0, pd=0, sap=0, sd=0, bap=0, bd=0, pdf=0, sdf=0, bdf=0, ld=0, tc=0, hl=0, speed=0, unit_range=0, ammo=0, labour=0,
img=None,
vet_img=None,
unit_level=0,
elite_flg=None):
if unit_type=='':
unit_type = 'None'
self.id = id
self.name = name
self.type = type
self.unit_type = unit_type
self.stars = stars
self.hp = hp
self.pap = pap
......@@ -19,11 +21,11 @@ class Unit(object):
self.pdf = pdf
self.sdf = sdf
self.bdf = bdf
self.leadership = leadership
self.troop_count = troop_count
self.hero_level = hero_level
self.ld = ld
self.tc = tc
self.hl = hl
self.speed = speed
self.range = range
self.unit_range = unit_range
self.ammo = ammo
self.labour = labour
self.img = img
......@@ -46,4 +48,4 @@ class Unit(object):
}
def __str__(self):
return '[{0}] {1}\t| {2}\t| {3}'.format(self.id, self.name, self.type, self.stars)
\ No newline at end of file
return '[{0}] {1}\t| {2}\t| {3}'.format(self.id, self.name, self.unit_type, self.stars)
\ No newline at end of file
from discord_argparse import *
insert_param_converter = ArgumentConverter(
type = OptionalArgument(
unit_type = OptionalArgument(
str,
doc='Type of Unit',
),
......@@ -62,10 +62,10 @@ insert_param_converter = ArgumentConverter(
doc='Hero level required',
),
speed = OptionalArgument(
int,
float,
doc='Speed of unit',
),
range = OptionalArgument(
unit_range = OptionalArgument(
int,
doc='Range of unit',
),
......@@ -74,7 +74,7 @@ insert_param_converter = ArgumentConverter(
doc='Ammo if unit',
),
labour = OptionalArgument(
int,
float,
doc='Resourse collection labour',
),
img = OptionalArgument(
......@@ -92,7 +92,7 @@ modify_param_converter = ArgumentConverter(
str,
doc='New name',
),
type = OptionalArgument(
unit_type = OptionalArgument(
str,
doc='Type of Unit',
),
......@@ -153,10 +153,10 @@ modify_param_converter = ArgumentConverter(
doc='Hero level required',
),
speed = OptionalArgument(
int,
float,
doc='Speed of unit',
),
range = OptionalArgument(
unit_range = OptionalArgument(
int,
doc='Range of unit',
),
......@@ -165,7 +165,7 @@ modify_param_converter = ArgumentConverter(
doc='Ammo if unit',
),
labour = OptionalArgument(
int,
float,
doc='Resourse collection labour',
),
img = OptionalArgument(
......
......@@ -48,6 +48,8 @@ class UserManager(commands.Cog):
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
if not(msg.content.lower() == 'yes' or msg.content.lower() == 'y'):
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
await Api.deleteSession('/user/unit/{0}'.format(data['id']), session)
......@@ -76,6 +78,8 @@ class UserManager(commands.Cog):
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
if not(msg.content.lower() == 'yes' or msg.content.lower() == 'y'):
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
body = params
......@@ -104,11 +108,12 @@ class UserManager(commands.Cog):
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
if not(msg.content.lower() == 'yes' or msg.content.lower() == 'y'):
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
body = params
body['unit_id'] = data['id']
print(body)
await Api.postSession('/user/unit', body, session)
return await ctx.send('Unit Assigned Successfully')
except ApiError as error:
......@@ -135,7 +140,7 @@ class UserManager(commands.Cog):
for i in range(minI, maxI):
if i < len(data):
unit = data[i]
units_str+= '[{0}] {1}\t| {2}\t| {3}\t| {4}\n'.format(unit.id, unit.name, unit.type, unit.stars, unit.unit_level)
units_str+= '[{0}] {1}\t| {2}\t| {3}\t| {4}\n'.format(unit.id, unit.name, unit.unit_type, unit.stars, unit.unit_level)
embed.add_field(name='id\t| name\t| type\t| stars\t| level', value=units_str)
......
......@@ -5,7 +5,7 @@ param_converter = ArgumentConverter(
str,
doc='Level of Unit',
),
eltie_flg = OptionalArgument(
elite_flg = OptionalArgument(
bool,
doc='Is Unit Elite',
)
......
......@@ -4,13 +4,20 @@ const Koa = require('koa');
const Router = require('@koa/router');
const bodyParser = require('koa-body');
const session = require('koa-session')
const serve = require('koa-static');
const logger = require('koa-logger')
const userRouter = require('./user/route');
const getUser = require('./user/model');
const [userRouter, userAuthRouter] = require('./user/route');
const unitRouter = require('./unit/route');
const SESS_CONFIG = require('./session_config');
const ENV = require('./settings')
const app = new Koa();
const router = new Router();
const authRouter = new Router();
app.use(serve(`${__dirname}/../web`))
app.use(logger())
app.keys = [ENV.SESS_KEY]
app.use(bodyParser());
......@@ -19,8 +26,30 @@ app.use(session(SESS_CONFIG, app));
router.use('/unit', unitRouter.routes(), unitRouter.allowedMethods());
router.use('/user', userRouter.routes(), userRouter.allowedMethods());
//app.use(auth());
authRouter.use('/user', userAuthRouter.routes(), userAuthRouter.allowedMethods());
app.use(router.routes()).use(router.allowedMethods());
// Make sure user is authorized
app.use(async (context, next) => {
if(context.session.user_id){
await next();
console.log(context.status)
} else {
context.response.status = 401;
}
});
// Add user to context
app.use(async (context, next) => {
const user = getUser.getUserFromId(context.session.user_id);
if(user){
context.user = user;
await next();
} else {
context.response.status = 403;
}
});
app.use(authRouter.routes()).use(authRouter.allowedMethods());
app.listen(3000, () => console.log('Server Started'));
\ No newline at end of file
......@@ -57,6 +57,14 @@
"negotiator": "0.6.2"
}
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
......@@ -100,6 +108,16 @@
"ylru": "^1.2.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
......@@ -116,6 +134,19 @@
"type-is": "^1.6.14"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
......@@ -211,6 +242,11 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"formidable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
......@@ -226,6 +262,11 @@
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"http-assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz",
......@@ -247,6 +288,11 @@
"toidentifier": "1.0.0"
}
},
"humanize-number": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/humanize-number/-/humanize-number-0.0.2.tgz",
"integrity": "sha1-EcCvakcWQ2M1iFiASPF5lUFInBg="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
......@@ -388,6 +434,17 @@
}
}
},
"koa-logger": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/koa-logger/-/koa-logger-3.2.1.tgz",
"integrity": "sha512-MjlznhLLKy9+kG8nAXKJLM0/ClsQp/Or2vI3a5rbSQmgl8IJBQO0KI5FA70BvW+hqjtxjp49SpH2E7okS6NmHg==",
"requires": {
"bytes": "^3.1.0",
"chalk": "^2.4.2",
"humanize-number": "0.0.2",
"passthrough-counter": "^1.0.0"
}
},
"koa-send": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz",
......@@ -526,6 +583,11 @@
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"passthrough-counter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passthrough-counter/-/passthrough-counter-1.0.0.tgz",
"integrity": "sha1-GWfZ5m2lcrXAI8eH2xEqOHqxZvo="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
......@@ -657,6 +719,14 @@
"safe-buffer": "~5.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
},
"thenify": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
......
......@@ -6,6 +6,7 @@
"fs": "0.0.1-security",
"koa": "^2.11.0",
"koa-body": "^4.1.1",
"koa-logger": "^3.2.1",
"koa-session": "^5.13.1",
"koa-static": "^5.0.0",
"promise-mysql": "^4.1.3"
......
......@@ -4,7 +4,7 @@ const db = require('../database/database');
const unitModel = {};
const unit_columns = ['name', 'type', 'stars', 'hp', 'pap', 'pd', 'sap', 'sd', 'bap', 'bp', 'pdf', 'sdf', 'bdf', 'leadership', 'troop_count', 'hero_level', 'speed', 'range', 'ammo', 'labour', 'img', 'vet_img'];
const unit_columns = ['name', 'unit_type', 'stars', 'hp', 'pap', 'pd', 'sap', 'sd', 'bap', 'bp', 'pdf', 'sdf', 'bdf', 'ld', 'tc', 'hl', 'speed', 'unit_range', 'ammo', 'labour', 'img', 'vet_img'];
unitModel.getAll = async () =>{
const sql_text = 'SELECT * FROM units ORDER BY name ASC;';
......
......@@ -9,12 +9,12 @@ const userModel = {};
const uu_columns = ['unit_level', 'elite_flg'];
userModel.getUserFromId = async (id) => {
const sql_text = 'SELECT TOP 1 id, discord_id, house_id, leadership FROM users WHERE id = ?;';
const sql_text = 'SELECT id, discord_id, house_id, leadership FROM users WHERE id = ? LIMIT 1;';
const data = await db.con.query(sql_text,[id]);
return data[0];
}
userModel.getUserFromDiscord = async (discordId) =>{
const sql_text = 'SELECT id, discord_id, house_id, leadership FROM users WHERE discord_id = ?;';
const sql_text = 'SELECT id, discord_id, house_id, leadership FROM users WHERE discord_id = ? LIMIT 1;';
const data = await db.con.query(sql_text, [discordId]);
return data[0];
}
......
......@@ -4,14 +4,9 @@ const Koa = require('koa');
const Router = require('@koa/router');
const router = new Router();
const authRouter = new Router();
const userModel = require('./model');
function checkUser(context){
if(!context.session.user_id){
context.throw(401, 'No User Logged')
}
}
router.post('/d-login', async (context, next) =>{
if(context.session.user_id && userModel.getUserFromId(context.session.user_id)){
context.throw(400, 'User is Already Logged In')
......@@ -34,8 +29,43 @@ router.post('/d-login', async (context, next) =>{
}
});
router.get('/units', async (context, next) => {
checkUser(context);
router.post('/discord-register', async(context, next) =>{
const body = context.request.body;
if(!body || !body.discordId){
context.throw(422, 'No Discord Id')
}
const discord_id = body.discordId;
if(context.user && !context.user.discord_id){
try{
await userModel.addDiscordIdToUser(context.user.id, discord_id);
context.status = 204;
}catch(error){
console.log(error);
context.throw(422, 'Invalid Discord Id')
}
}
let user = undefined;
try{
user = await userModel.getUserFromDiscord(discord_id);
}catch(error){
console.log(error);
context.throw(422, 'Invalid Discord Id')
}
if(!user){
try{
await userModel.createUserWithDiscord(discord_id);
context.status = 204;
}catch(error){
context.throw(422, 'Failed to create user with Discord Id')
}
}else{
context.throw(422, 'User already exists')
}
});
authRouter.get('/units', async (context, next) => {
try{
const data = await userModel.getUserUnits(context.session.user_id);
if(data.length===1 && data[0].id===null){
......@@ -49,8 +79,7 @@ router.get('/units', async (context, next) => {
}
});
router.get('/unit/:term', async (context, next) =>{
checkUser(context);
authRouter.get('/unit/:term', async (context, next) =>{
try{
const data = await userModel.getUserUnit(context.session.user_id, context.params.term)
context.response.body = data;
......@@ -61,8 +90,7 @@ router.get('/unit/:term', async (context, next) =>{
}
})
router.post('/unit', async (context, next) => {
checkUser(context);
authRouter.post('/unit', async (context, next) => {
try{
const body = context.request.body;
if(!body.unit_id){
......@@ -79,8 +107,7 @@ router.post('/unit', async (context, next) => {
}
})
router.put('/unit/:unit_id', async (context, next) =>{
checkUser(context);
authRouter.put('/unit/:unit_id', async (context, next) =>{
try{
const body = context.request.body;
if(!body){
......@@ -94,8 +121,7 @@ router.put('/unit/:unit_id', async (context, next) =>{
}
})
router.delete('/unit/:unit_id', async (context, next) =>{
checkUser(context);
authRouter.delete('/unit/:unit_id', async (context, next) =>{
try{
await userModel.deleteUserUnit(context.session.user_id, context.params.unit_id);
context.status = 204;
......@@ -105,39 +131,5 @@ router.delete('/unit/:unit_id', async (context, next) =>{
}
})
router.post('/discord-register', async(context, next) =>{
const body = context.request.body;
if(!body || !body.discordId){
context.throw(422, 'No Discord Id')
}
const discord_id = body.discordId;
if(context.user && !context.user.discord_id){
try{
await userModel.addDiscordIdToUser(context.user.id, discord_id);
context.status = 204;
}catch(error){
console.log(error);
context.throw(422, 'Invalid Discord Id')
}
}
let user = undefined;
try{
data = await userModel.getUserFromDiscord(discord_id);
}catch(error){
console.log(error);
context.throw(422, 'Invalid Discord Id')
}
if(!user){
try{
await userModel.createUserWithDiscord(discord_id);
context.status = 204;
}catch(error){
context.throw(422, 'Failed to create user with Discord Id')
}
}else{
context.throw(422, 'User already exists')
}
});
module.exports = router;
\ No newline at end of file
module.exports = [router, authRouter];
\ No newline at end of file
@font-face {
font-family: 'Font Awesome 5 Brands';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("/fontawesome/fa-brands-400.woff2") format("woff2");
}
@font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("/fontawesome/fa-regular-400.woff2") format("woff2");
}
@font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("/fontawesome/fa-solid-900.woff2") format("woff2");
}
@mixin icon($icon_code, $style){
&::before {
font-family: 'Font Awesome 5 Free';
content: $icon_code;
display: inline-block;
@if $style == "solid" {
font-weight: 900;
} @else if $style == "regular" {
font-weight: 400;
}
@content;
}
}
@keyframes fa-spin {
0% { transform: rotate( 0deg); }
100% { transform: rotate(360deg); }
}
@mixin spin_icon{
animation: fa-spin 2s linear infinite;
}
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="./stylesheets/main.css"/>
<script src="sugar.js"></script>
<script>Sugar.extend()</script>
<script src="main.js" type="module"></script>
</head>
<body>
<nav-placeholder></nav-placeholder>
<script src="/navbar/navbar.js"></script>
<h1>STUFF IN HERE</h1>
</body>
</html>
import Sync from './sync'
class LoginPageController{
constructor(view){
this.view = view;
this.sync = new Sync();
this.view.addEventListener('login_attempt', this.login(event.detail.credentials));
this.view.addEventListener('register_attempt', this.login(event.detail.credentials))
}
async login(credentials){
try{
const user_data = await this.sync.login(credentials);
localStorage.setItem('username', user_data.user_name);
location.replace('/');
}catch(error){
console.log(error);
alert('Failed to login')
}
}
async login(credentials){
try{
const user_data = await this.sync.register(credentials);
localStorage.setItem('username', user_data.user_name);
location.replace('/');
}catch(error){
console.log(error);
alert('Failed to register')
}
}
}
export default LoginPageController;
\ No newline at end of file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="./stylesheets/main.css"/>
<script src="sugar.js"></script>
<script>Sugar.extend()</script>
<script src="/main.js" type="module"></script>
</head>
<body>
<nav-placeholder></nav-placeholder>
<script src="/navbar/navbar.js"></script>
<content-body>
<center-div>
<div class="tab">
<button class="tablinks active" onclick="changeTab(event, 'Login')">Login</button>
<button class="tablinks" onclick="changeTab(event, 'Register')">Register</button>
</div>
<!-- Tab content -->
<div id="Login" class="tabcontent" style="display: block;">
<login-form>
<input type="text" name="login" placeholder="Login"/>
<input type="password" name="password" placeholder="********"/>
<button id="login_button">Log In</button>
</login-form>
</div>
<div id="Register" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
</center-div>
</content-body>
<script>
function changeTab(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
</script>
</body>
</html>
class LoginView extends EventTarget {
constructor(element){
super()
this.element = element
this.login_field = this.element.querySelector("[name=login]")
this.password_field = this.element.querySelector("[name=password]")
this.login_button = this.element.querySelector("#login_button")
this.login_button.addEventListener("click", () => {
this.dispatchEvent(new CustomEvent("login_attempt", {detail: {
login: this.login_field.value,
password: this.password_field.value }
}))
})
}
show(){
this.element.style.display = ""
}
hide(){
this.element.style.display = "none"
}
}
export default LoginView
\ No newline at end of file
class Server{
async login(credentials){
const login_response = await fetch('/user/login', {
method: "POST",
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json'
}
})
if(!login_response.ok){
throw new Error(`Login failed with ${login_response.status}`)
}
const user_data = await login_response.json();
return user_data;
}
async register(credentials){
const register_response = await fetch('/user/register', {
method: "POST",
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json'
}
})
if(!register_response.ok){
throw new Error(`Register failed with ${login_response.status}`)
}
const user_data = await register_response.json();
return user_data;
}
}
\ No newline at end of file
import LoginView from "./login_view.js"
class LoginPageView extends EventTarget {
constructor(){
this.login_form = new LoginView(document.querySelector('login-form'))
this.login_form.addEventListener("login_attempt", (event) => {
this.dispatchEvent(new CustomEvent("login_attempt", {detail: {login: event.detail.login, password: event.detail.password}}))
})
this.register_form.addEventListener("register_attempt", (event) => {
this.dispatchEvent(new CustomEvent("register_attempt", {detail: {
login: event.detail.login,
password: event.detail.password,
confirm_password: event.detail.confirm_password}
}))
})
}
}
export default LoginPageView;
\ No newline at end of file
<nav-bar>
<bar-title>
<a href="/">Conquy Blade</a>
</bar-title>
<bar-options>
<div class="dropdown">
<p>Unit</p>
<div class="dropdown-content">
<a>All Units</a>
<a>My Units</a>
</div>
</div>
<div class="dropdown">
<p>House</p>
<div class="dropdown-content">
<a>All Units</a>
<a>My Units</a>
</div>
</div>
</bar-options>
<bar-user>
<a href="/login">Login/Register</a>
</bar-user>
</nav-bar>
<script src="navbar.js"></script>
\ No newline at end of file
function loadPage(href)
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", href, false);
xmlhttp.send();
return xmlhttp.responseText;
}
const nav_placeholder = document.querySelector('nav-placeholder')
nav_placeholder.innerHTML = loadPage('/navbar/navbar.html')
const bar_user = document.querySelector('bar-user a');
console.log(bar_user)
const saved_user = localStorage.getItem('username');
if(saved_user){
bar_user.innerText = saved_user;
}
function testy(){
console.log('asd')
}
\ No newline at end of file
This diff is collapsed.
content-body{
grid-area: content;
}
center-div{
text-align: center;
left: 50%;
position: absolute;
display: inline-block;
margin-top: 50px;
margin-left: -250px;
background-color: rgb(27, 26, 26);
height: 500px;
width: 500px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
}
.tab {
overflow: hidden;
// border: 1px solid #ccc;
background-color: #383838;
button{
font-family: monospace;
font-size: 20px;
}
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
// float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
.tabcontent {
animation: fadeEffect 1s; /* Fading effect takes 1 second */
}
/* Go from zero to full opacity */
@keyframes fadeEffect {
from {opacity: 0;}
to {opacity: 1;}
}
\ No newline at end of file
@import "../fontawesome/font_awesome.scss";
@import "./navbar.scss";
@import "./login.scss";
body{
font-family: monospace;
background-color: rgb(49, 49, 49);
color: whitesmoke;
display: grid;
grid-template:
"navbar" 100px
"content" 1fr
"footer" 200px
}
\ No newline at end of file
nav-bar{
grid-area: navbar;
display: grid;
color: rgb(219, 219, 219);
grid-template:
"title options user"
/1fr 5fr 1fr
;
background-color: rgb(117, 16, 16);
}
bar-title {
margin: auto;
a {
grid-area: title;
font-size: 300%;
color: whitesmoke;
text-decoration: none;
}
}
bar-options{
grid-area: options;
}
.dropdown {
position: relative;
display: inline-block;
text-align: center;
font-size: 30px;
min-width: 160px;
height: 100%;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #2c2c2c;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 12px 16px;
z-index: 1;
a:hover{
background-color: rgb(59, 15, 15);
}
}
.dropdown:hover {
background-color: #9c4949;
.dropdown-content {
display: block;
}
}
bar-user{
font-size: 30px;
text-align: center;
padding-top: 30px;
a{
text-decoration: none;
color: whitesmoke;
}
}
bar-user:hover{
background-color: rgb(95, 26, 26);
}
\ No newline at end of file
content-body {
grid-area: content;
}
center-div {
text-align: center;
left: 50%;
position: absolute;
display: inline-block;
margin-top: 50px;
margin-left: -250px;
background-color: #1b1a1a;
height: 500px;
width: 500px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}
.tab {
overflow: hidden;
background-color: #383838;
}
.tab button {
font-family: monospace;
font-size: 20px;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
.tabcontent {
animation: fadeEffect 1s;
/* Fading effect takes 1 second */
}
/* Go from zero to full opacity */
@keyframes fadeEffect {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*# sourceMappingURL=login.css.map */
{"version":3,"sourceRoot":"","sources":["../sass/login.scss"],"names":[],"mappings":"AAAA;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EAEA;;AAEA;EACI;EACA;;;AAIN;AACF;EACI;EAEA;EACA;EACA;EACA;EACA;;;AAGF;AACF;EACI;;;AAGF;AACF;EACI;;;AAGF;AACF;EACI;EACA;EACA;EACA;;;AAGJ;EACI;AAA0B;;;AAG9B;AACA;EACI;IAAM;;EACN;IAAI","file":"login.css"}
\ No newline at end of file
@font-face {
font-family: "Font Awesome 5 Brands";
font-style: normal;
font-weight: 400;
font-display: block;
src: url("/fontawesome/fa-brands-400.woff2") format("woff2");
}
@font-face {
font-family: "Font Awesome 5 Free";
font-style: normal;
font-weight: 400;
font-display: block;
src: url("/fontawesome/fa-regular-400.woff2") format("woff2");
}
@font-face {
font-family: "Font Awesome 5 Free";
font-style: normal;
font-weight: 900;
font-display: block;
src: url("/fontawesome/fa-solid-900.woff2") format("woff2");
}
@keyframes fa-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
nav-bar {
grid-area: navbar;
display: grid;
color: #dbdbdb;
grid-template: "title options user"/1fr 5fr 1fr;
background-color: #751010;
}
bar-title {
margin: auto;
}
bar-title a {
grid-area: title;
font-size: 300%;
color: whitesmoke;
text-decoration: none;
}
bar-options {
grid-area: options;
}
.dropdown {
position: relative;
display: inline-block;
text-align: center;
font-size: 30px;
min-width: 160px;
height: 100%;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #2c2c2c;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
padding: 12px 16px;
z-index: 1;
}
.dropdown-content a:hover {
background-color: #3b0f0f;
}
.dropdown:hover {
background-color: #9c4949;
}
.dropdown:hover .dropdown-content {
display: block;
}
bar-user {
font-size: 30px;
text-align: center;
padding-top: 30px;
}
bar-user a {
text-decoration: none;
color: whitesmoke;
}
bar-user:hover {
background-color: #5f1a1a;
}
content-body {
grid-area: content;
}
center-div {
text-align: center;
left: 50%;
position: absolute;
display: inline-block;
margin-top: 50px;
margin-left: -250px;
background-color: #1b1a1a;
height: 500px;
width: 500px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}
.tab {
overflow: hidden;
background-color: #383838;
}
.tab button {
font-family: monospace;
font-size: 20px;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
.tabcontent {
animation: fadeEffect 1s;
/* Fading effect takes 1 second */
}
/* Go from zero to full opacity */
@keyframes fadeEffect {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
body {
font-family: monospace;
background-color: #313131;
color: whitesmoke;
display: grid;
grid-template: "navbar" 100px "content" 1fr "footer" 200px;
}
/*# sourceMappingURL=main.css.map */
{"version":3,"sourceRoot":"","sources":["../fontawesome/font_awesome.scss","../sass/navbar.scss","../sass/login.scss","../sass/main.scss"],"names":[],"mappings":"AAAA;EACI;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAmBF;EACI;IAAK;;EACP;IAAO;;;AC1CX;EACI;EACA;EACA;EACA,eACI;EAGJ;;;AAGJ;EAEI;;AACA;EACI;EACA;EAEA;EACA;;;AAIR;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACI;;;AAIR;EACI;;AACA;EACI;;;AAIR;EACI;EACA;EACA;;AACA;EACI;EACA;;;AAIR;EACI;;;ACnEJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EAEA;;AAEA;EACI;EACA;;;AAIN;AACF;EACI;EAEA;EACA;EACA;EACA;EACA;;;AAGF;AACF;EACI;;;AAGF;AACF;EACI;;;AAGF;AACF;EACI;EACA;EACA;EACA;;;AAGJ;EACI;AAA0B;;;AAG9B;AACA;EACI;IAAM;;EACN;IAAI;;;AC5DR;EACI;EACA;EACA;EACA;EACA,eACI","file":"main.css"}
\ No newline at end of file
nav-bar {
grid-area: navbar;
display: grid;
color: #dbdbdb;
grid-template: "title options user"/1fr 5fr 1fr;
background-color: #751010;
}
bar-title {
margin: auto;
}
bar-title a {
grid-area: title;
font-size: 300%;
color: whitesmoke;
text-decoration: none;
}
bar-options {
grid-area: options;
}
.dropdown {
position: relative;
display: inline-block;
text-align: center;
font-size: 30px;
min-width: 160px;
height: 100%;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #2c2c2c;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
padding: 12px 16px;
z-index: 1;
}
.dropdown-content a:hover {
background-color: #3b0f0f;
}
.dropdown:hover {
background-color: #9c4949;
}
.dropdown:hover .dropdown-content {
display: block;
}
bar-user {
font-size: 30px;
text-align: center;
padding-top: 30px;
}
bar-user a {
text-decoration: none;
color: whitesmoke;
}
bar-user:hover {
background-color: #5f1a1a;
}
/*# sourceMappingURL=navbar.css.map */
{"version":3,"sourceRoot":"","sources":["../sass/navbar.scss"],"names":[],"mappings":"AAAA;EACI;EACA;EACA;EACA,eACI;EAGJ;;;AAGJ;EAEI;;AACA;EACI;EACA;EAEA;EACA;;;AAIR;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACI;;;AAIR;EACI;;AACA;EACI;;;AAIR;EACI;EACA;EACA;;AACA;EACI;EACA;;;AAIR;EACI","file":"navbar.css"}
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment