Interim update
This commit is contained in:
171
Server/app/svelte/public/css/auth.css
Normal file
171
Server/app/svelte/public/css/auth.css
Normal file
@@ -0,0 +1,171 @@
|
||||
|
||||
label {
|
||||
font-size: 1.3rem;
|
||||
font-family: var(--sans-serif);
|
||||
}
|
||||
|
||||
.auth-pane {
|
||||
position: relative;
|
||||
padding: 3.4rem;
|
||||
padding-top: 3.4rem;
|
||||
padding-bottom: 3.4rem;
|
||||
width: 30rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.auth-title {
|
||||
position: relative;
|
||||
top: 0.2rem;
|
||||
margin-bottom: 2.7rem;
|
||||
}
|
||||
|
||||
.auth-label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.authEmailInput, .authPasswordInput {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 0.34rem;
|
||||
color: #353535;
|
||||
height: 2.73rem;
|
||||
padding-left: 0.34rem;
|
||||
}
|
||||
|
||||
.authEmailInput {
|
||||
margin-bottom: 0.682rem;
|
||||
}
|
||||
|
||||
.auth-button {
|
||||
margin-top: 1.365rem;
|
||||
height: 3.412rem;
|
||||
width: 100%;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.3rem;
|
||||
color: white;
|
||||
background-color: var(--red);
|
||||
border-color: var(--red);
|
||||
border-radius: 0.512rem;
|
||||
filter: drop-shadow(0.068rem 0.136rem 0.068rem rgb(0 0 0 / 0.4));
|
||||
}
|
||||
|
||||
.auth-button:active {
|
||||
background-color: var(--darker-pink);
|
||||
}
|
||||
|
||||
#email-msg,#password-msg {
|
||||
display: inline;
|
||||
color:red;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
}
|
||||
|
||||
.auth-line {
|
||||
margin-top: 1.5rem;
|
||||
width: 100%;
|
||||
height: 0.07rem;
|
||||
border: 0;
|
||||
border-radius: 0.1rem;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.auth-methods-group {
|
||||
display: grid;
|
||||
grid-template-columns: auto ; /*auto auto*/
|
||||
justify-content: center;
|
||||
gap: 2.7rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.auth-methods-group img {
|
||||
height: auto;
|
||||
width: 3.4rem;
|
||||
}
|
||||
|
||||
.auth-methods-group> div {
|
||||
position: relative;
|
||||
border-radius: 6.8rem;
|
||||
width: 3.4rem;
|
||||
height: 3.4rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#google-btn {
|
||||
position: absolute;
|
||||
top: -0.8rem;
|
||||
left: -0.8rem;
|
||||
}
|
||||
|
||||
#google-logo {
|
||||
position: relative;
|
||||
background: white;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#google-btn-wrapper {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#google-btn div {
|
||||
position: absolute;
|
||||
height: 5rem;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
#google-btn iframe {
|
||||
position: absolute;
|
||||
height: 10rem;
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.password-field {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.eye-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
opacity: 0.25;
|
||||
top: 2.6rem;
|
||||
right: 0.8rem;
|
||||
width: 1.7rem;
|
||||
}
|
||||
|
||||
.eye-icon * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#forgot-password {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
height: 2rem;
|
||||
color:#5f5f5f;
|
||||
margin-left: auto;
|
||||
width: max-content;
|
||||
font-family: var(--sans-serif);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
|
||||
#remember-me {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
#remember-me-checkbox {
|
||||
min-height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
flex: 0;
|
||||
accent-color: var(--gray);
|
||||
}
|
||||
|
||||
#remember-me label {
|
||||
position: relative;
|
||||
margin-top: -0.2rem;
|
||||
color: #5f5f5f;
|
||||
}
|
@@ -1,21 +1,7 @@
|
||||
|
||||
:root {
|
||||
--light-blue:hsl(195, 67%, 95%);
|
||||
--darker-pink:hsl(344, 60%, 47%);
|
||||
--pink:hsl(344, 73%, 57%);
|
||||
--dark-green:hsl(176, 63%, 25%);
|
||||
--green:hsl(147, 33%, 60%);
|
||||
--orange:hsl(30, 97%, 72%);
|
||||
--light-orange: hsl(19, 76%, 72%);
|
||||
--dark-brown:hsl(23, 47%, 20%);
|
||||
--brown:hsl(23, 47%, 30%);
|
||||
--light-brown: hsl(23, 47%, 50%);
|
||||
--dark-pink:hsl(343, 39%, 16%);
|
||||
--red:hsl(359, 72%, 61%);
|
||||
--dark-blue:hsl(217, 25%, 16%);
|
||||
--grey-blue:hsl(223, 13%, 22%);
|
||||
--cream:hsl(34, 43%, 90%);
|
||||
--dark-cream:hsl(33, 26%, 84%);
|
||||
--red:#c52a28;
|
||||
--gray: #5B6970;
|
||||
--sans-serif: "OpenSans";
|
||||
--serif: "Lora";
|
||||
}
|
||||
@@ -48,12 +34,10 @@ body {
|
||||
|
||||
#content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
display: grid;
|
||||
grid-template-rows: max-content auto max-content;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/*---Fonts---------------------------------------------------------*/
|
||||
@@ -475,9 +459,8 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
|
||||
.pane {
|
||||
background: white;
|
||||
border: 0;
|
||||
border: 0.1rem solid rgb(187, 187, 187);
|
||||
border-radius: 0.635rem;
|
||||
box-shadow: 0 0 0.314rem rgb(187, 187, 187);
|
||||
}
|
||||
|
||||
.pane-container {
|
||||
|
55
Server/app/svelte/public/css/profile.css
Normal file
55
Server/app/svelte/public/css/profile.css
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
#notifications-div>button {
|
||||
cursor: pointer;
|
||||
margin-left: 0.341rem;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(1) {
|
||||
width: 1.706rem;
|
||||
height: 1.706rem;
|
||||
background-color: #ccc;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(2) {
|
||||
width: 2.047rem;
|
||||
height: 2.047rem;
|
||||
background-color: #ccc;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(3) {
|
||||
width: 2.389rem;
|
||||
height: 2.389rem;
|
||||
background-color: #ccc;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#notifications-div>button>div {
|
||||
cursor: pointer;
|
||||
margin: auto;
|
||||
background-color: white;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(1)>div {
|
||||
width: 1.228rem;
|
||||
height: 1.228rem;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(2)>div {
|
||||
width: 1.57rem;
|
||||
height: 1.57rem;
|
||||
}
|
||||
|
||||
#notifications-div>:nth-child(3)>div {
|
||||
width: 1.843rem;
|
||||
height: 1.843rem;
|
||||
}
|
||||
|
||||
*/
|
160
Server/app/svelte/public/js/libraries/authTools.js
Normal file
160
Server/app/svelte/public/js/libraries/authTools.js
Normal file
@@ -0,0 +1,160 @@
|
||||
|
||||
import {getData, sendData} from "/js/libraries/serverTools.js"
|
||||
|
||||
export function getUser(user,callbackOuter) {
|
||||
let callback = function(response) {
|
||||
Object.assign(user,JSON.parse(response))
|
||||
if(callbackOuter!=undefined) {
|
||||
callbackOuter()
|
||||
}
|
||||
}
|
||||
getData("/xx/get-user",callback)
|
||||
}
|
||||
|
||||
export function changeUser(name,value,user) {
|
||||
if (user[name]!=value && user[name]!=undefined) {
|
||||
user[name] = value
|
||||
let data = new Object();
|
||||
data[name] = value
|
||||
sendData("/xx/change-user",data)
|
||||
}
|
||||
}
|
||||
|
||||
export function changePasswordVisibility(button) {
|
||||
let input = button.previousElementSibling
|
||||
let type = input.type
|
||||
if (type=="text") {
|
||||
input.type = "password";
|
||||
button.style.opacity = 0.25
|
||||
}
|
||||
else {
|
||||
input.type = "text";
|
||||
button.style.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
export function checkEmail(email,msg) {
|
||||
if (email.includes("@")) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
msg.innerHTML = "must contain '@'"
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function checkPassword(password,msg) {
|
||||
let passwordLength = password.length
|
||||
if (passwordLength<8) {
|
||||
msg.innerHTML = "must be 8 characters"
|
||||
return false
|
||||
}
|
||||
let numNumbers = password.match(/\d/g)?.length || 0;
|
||||
if (numNumbers<1) {
|
||||
msg.innerHTML = "mush have digits"
|
||||
return false
|
||||
}
|
||||
let numLetters = password.match(/\D/g)?.length || 0;
|
||||
if (numLetters<2) {
|
||||
msg.innerHTML = "must have letters"
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function redirectLogged() {
|
||||
let callback = function(responseText) {
|
||||
let response = JSON.parse(responseText)
|
||||
if (response) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
}
|
||||
getData("/xx/check-login",callback)
|
||||
}
|
||||
|
||||
export function redirectNotLogged() {
|
||||
let callback = function(responseText) {
|
||||
let response = JSON.parse(responseText)
|
||||
if (!response) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
}
|
||||
getData("/xx/check-login",callback)
|
||||
}
|
||||
|
||||
// Redirect to the landing page
|
||||
export function toLandingPage(response) {
|
||||
if (response!=0) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to the dashboard page
|
||||
export function toDashboard() {
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
// Process log in
|
||||
export function processLoginResponse(response,msgs,remember) {
|
||||
if (response==0) {
|
||||
msgs.email.innerHTML = "not found"
|
||||
}
|
||||
else if (response==1) {
|
||||
msgs.password.innerHTML = "is wrong"
|
||||
}
|
||||
else {
|
||||
if (remember) {
|
||||
let date = new Date()
|
||||
date.setMonth(date.getMonth()+1)
|
||||
date = date.toUTCString()
|
||||
document.cookie = "__genierememberme=; expires=" + date + "; path=/;SameSite=Lax";
|
||||
}
|
||||
toDashboard()
|
||||
}
|
||||
}
|
||||
|
||||
// Log in
|
||||
export function login(msgs,inputs) {
|
||||
msgs.email.innerHTML = ""
|
||||
msgs.password.innerHTML = ""
|
||||
let data = {email: inputs.email.value, password: inputs.password.value, remember: inputs.remember.checked}
|
||||
sendData('/xx/login-post', data, (response) => processLoginResponse(response,msgs,inputs.remember.checked))
|
||||
}
|
||||
|
||||
// Process sign in
|
||||
function processSignupResponse(response,msgs) {
|
||||
if (response) {
|
||||
toDashboard()
|
||||
}
|
||||
else {
|
||||
msgs.email.innerHTML = "already exists"
|
||||
}
|
||||
}
|
||||
|
||||
// Sign up
|
||||
export function signup(msgs,inputs) {
|
||||
msgs.email.innerHTML = ""
|
||||
let email = inputs.email.value
|
||||
let password = inputs.password.value
|
||||
if (checkEmail(email,msgs.email)==false) {
|
||||
return
|
||||
}
|
||||
if (checkPassword(password,msgs.password)==false) {
|
||||
return
|
||||
}
|
||||
let data = {email: email, password: password}
|
||||
sendData('/xx/signup-post', data, (response) => processSignupResponse(response,msgs))
|
||||
}
|
||||
|
||||
export function confirmEmail(msg,code,callback) {
|
||||
msg.innerHTML = ""
|
||||
sendData('xx/confirm-email',code,callback)
|
||||
}
|
||||
|
||||
// Log out
|
||||
export function logout() {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open( "GET", "/logout", false ); // false for synchronous request
|
||||
xmlHttp.send( null );
|
||||
window.location.href = "/";
|
||||
}
|
@@ -7,5 +7,7 @@
|
||||
"communes": "Communes",
|
||||
"cooperatives": "Cooperatives",
|
||||
"parties": "Parties",
|
||||
"partners": "Partners"
|
||||
"partners": "Partners",
|
||||
"login": "Login",
|
||||
"profile": "Profile"
|
||||
}
|
@@ -10,6 +10,7 @@ import watch from "rollup-plugin-watch";
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
|
||||
function serve() {
|
||||
let server;
|
||||
|
||||
|
128
Server/app/svelte/src/auth/auth-component.svelte
Normal file
128
Server/app/svelte/src/auth/auth-component.svelte
Normal file
@@ -0,0 +1,128 @@
|
||||
<svelte:options tag="auth-component" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, setContext,getContext } from 'svelte'
|
||||
import { sendText } from "/js/libraries/serverTools.js"
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
import "/js/components/login-component.js"
|
||||
import "/js/components/signup-component.js"
|
||||
|
||||
// Main code
|
||||
AuthTools.redirectLogged()
|
||||
|
||||
let loginComponent
|
||||
let signupComponent
|
||||
|
||||
let context = {
|
||||
googleInit: false
|
||||
}
|
||||
setContext("auth",context)
|
||||
|
||||
function switchFocus(component) {
|
||||
if (component==loginComponent) {
|
||||
loginComponent.focused = true
|
||||
signupComponent.focused = false
|
||||
}
|
||||
else {
|
||||
loginComponent.focused = false
|
||||
signupComponent.focused = true
|
||||
}
|
||||
}
|
||||
|
||||
function callbackGoogle(data) {
|
||||
console.log(data)
|
||||
sendText("/signup-google",data.credential,(response) => AuthTools.processLoginResponse(response,context.msgs,context.remember.checked))
|
||||
}
|
||||
|
||||
function initGoogle() {
|
||||
if (typeof google != 'undefined') {
|
||||
google.accounts.id.initialize({
|
||||
client_id: '93612176787-sr8qjqem4e3kok4msrnj8s1illt85a9g.apps.googleusercontent.com',
|
||||
callback: callbackGoogle,
|
||||
auto_select: true,
|
||||
context: "signin"
|
||||
})
|
||||
context.googleInit = true
|
||||
}
|
||||
else {
|
||||
setTimeout(initGoogle,100)
|
||||
}
|
||||
}
|
||||
|
||||
initGoogle()
|
||||
|
||||
</script>
|
||||
|
||||
<div id="auth-group">
|
||||
<div id="auth-grid-group">
|
||||
<login-component bind:this={loginComponent} on:click={() => switchFocus(loginComponent)} on:keydown={() => ""}></login-component>
|
||||
<signup-component bind:this={signupComponent} on:click={() => switchFocus(signupComponent)} on:keydown={() => ""}></signup-component>
|
||||
</div>
|
||||
<div id="auth-or" class="pane">
|
||||
<span>OR</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@import '/css/common.css';
|
||||
|
||||
span {
|
||||
font-size: 1.4rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
}
|
||||
|
||||
#auth-group {
|
||||
margin: auto;
|
||||
width: auto;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
#auth-grid-group {
|
||||
display: grid;
|
||||
grid-template-columns: 30rem 30rem;
|
||||
justify-content: center;
|
||||
gap: 1.37rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#auth-or {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 5.4rem;
|
||||
height: 5.4rem;
|
||||
border-radius: 6.8rem;
|
||||
background-color: white;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
#auth-grid-group {
|
||||
display: grid;
|
||||
grid-template-columns: 30rem;
|
||||
grid-template-rows: auto auto;
|
||||
justify-content: center;
|
||||
gap: 1.37rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#auth-or {
|
||||
top: 46.4rem;
|
||||
}
|
||||
|
||||
#auth-group {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
131
Server/app/svelte/src/auth/confirmation-component.svelte
Normal file
131
Server/app/svelte/src/auth/confirmation-component.svelte
Normal file
@@ -0,0 +1,131 @@
|
||||
<svelte:options tag="confirmation-component" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Export statements
|
||||
|
||||
// Main code
|
||||
let confirmationInputs = []
|
||||
let confirmationMsg
|
||||
let confirmationButton
|
||||
|
||||
function onlyNumberKey(ind,evt) {
|
||||
// Only ASCII character in that range allowed
|
||||
var value = evt.data
|
||||
if (value in ["0","1","2","3","4","5","6","7","8","9"]) {
|
||||
if (ind<4) {
|
||||
confirmationInputs[ind+1].focus()
|
||||
}
|
||||
else {
|
||||
AuthTools.confirmEmail(confirmationMsg,getCode(),callback)
|
||||
}
|
||||
}
|
||||
else {
|
||||
confirmationInputs[ind].value = ""
|
||||
}
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
let code = ""
|
||||
for (let input of confirmationInputs) {
|
||||
code += input.value
|
||||
}
|
||||
return parseInt(code)
|
||||
}
|
||||
|
||||
function callback(response) {
|
||||
if (response=="true") {
|
||||
AuthTools.toDashboard()
|
||||
}
|
||||
else {
|
||||
confirmationMsg.innerHTML = "Wrong code"
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<div class="pane auth-pane">
|
||||
<h2 class="auth-title title-highlight">CONFIRMATION CODE</h2>
|
||||
<div id="confirmationInputs">
|
||||
<input bind:this={confirmationInputs[0]} class="authConfirmationInput" type="text" maxlength="1" on:input={(evt) => onlyNumberKey(0,evt)}><span class="dash">-</span>
|
||||
<input bind:this={confirmationInputs[1]} class="authConfirmationInput" type="text" maxlength="1" on:input={(evt) => onlyNumberKey(1,evt)}><span class="dash">-</span>
|
||||
<input bind:this={confirmationInputs[2]} class="authConfirmationInput" type="text" maxlength="1" on:input={(evt) => onlyNumberKey(2,evt)}><span class="dash">-</span>
|
||||
<input bind:this={confirmationInputs[3]} class="authConfirmationInput" type="text" maxlength="1" on:input={(evt) => onlyNumberKey(3,evt)}><span class="dash">-</span>
|
||||
<input bind:this={confirmationInputs[4]} class="authConfirmationInput" type="text" maxlength="1" on:input={(evt) => onlyNumberKey(4,evt)}>
|
||||
</div>
|
||||
<span bind:this={confirmationMsg} id="confirmation-msg"></span>
|
||||
<button bind:this={confirmationButton} class="auth-button" on:click="{() => AuthTools.confirmEmail(confirmationMsg,getCode(),callback)}">Confirm</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@import '/css/common.css';
|
||||
|
||||
.auth-pane {
|
||||
position: relative;
|
||||
padding: 3.4rem;
|
||||
padding-top: 5.5rem;
|
||||
padding-bottom: 5.5rem;
|
||||
width: 33rem;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.auth-title {
|
||||
position: relative;
|
||||
left: 0.7rem;
|
||||
top: 0.2rem;
|
||||
margin-bottom: 1.4rem;
|
||||
}
|
||||
|
||||
.authConfirmationInput {
|
||||
position: relative;
|
||||
width: 3.16rem;
|
||||
font-family: var(--serif,serif);
|
||||
font-size: 3rem;
|
||||
border-radius: 0.34rem;
|
||||
margin-bottom: 0.7rem;
|
||||
text-align: center;
|
||||
padding-left: 0;
|
||||
padding-bottom: 0.3 rem;
|
||||
}
|
||||
|
||||
.dash {
|
||||
display: block;
|
||||
font-size: 3rem;
|
||||
font-family: var(--serif,serif);
|
||||
}
|
||||
|
||||
#confirmationInputs {
|
||||
margin: auto;
|
||||
display: grid;
|
||||
justify-content: space-between;
|
||||
grid-auto-flow: column;
|
||||
}
|
||||
|
||||
.auth-button {
|
||||
margin-top: 1.4rem;
|
||||
height: 3.4rem;
|
||||
width: 100%;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.6rem;
|
||||
color: white;
|
||||
background-color: var(--pink);
|
||||
border-color: var(--pink);
|
||||
border-radius: 0.5rem;
|
||||
filter: drop-shadow(0.07rem 0.14rem 0.07rem rgb(0 0 0 / 0.4));
|
||||
}
|
||||
|
||||
#confirmation-msg {
|
||||
display: inline;
|
||||
color:red;
|
||||
}
|
||||
</style>
|
108
Server/app/svelte/src/auth/login-component.svelte
Normal file
108
Server/app/svelte/src/auth/login-component.svelte
Normal file
@@ -0,0 +1,108 @@
|
||||
<svelte:options tag="login-component" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Export statements
|
||||
export let focused = false
|
||||
|
||||
// Main code
|
||||
|
||||
let emailInput
|
||||
let passwordInput
|
||||
let inputs
|
||||
|
||||
let passwordVisibilityButton
|
||||
|
||||
let emailMsg
|
||||
let passwordMsg
|
||||
let msgs
|
||||
let rememberMe
|
||||
|
||||
let googleButton
|
||||
|
||||
let parentProps = getContext("auth")
|
||||
|
||||
function renderGoogle() {
|
||||
if (parentProps.googleInit) {
|
||||
google.accounts.id.renderButton(googleButton,{
|
||||
theme: 'outline',
|
||||
size: 'large'
|
||||
})
|
||||
let iframe = googleButton.getElementsByTagName('iframe')[0]
|
||||
iframe.style.height = "5rem"
|
||||
iframe.style.width = "5rem"
|
||||
}
|
||||
else {
|
||||
setTimeout(renderGoogle,100)
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
||||
rememberMe.checked = true
|
||||
|
||||
inputs = {email: emailInput, password: passwordInput, remember: rememberMe}
|
||||
msgs = {email: emailMsg, password: passwordMsg}
|
||||
|
||||
parentProps.msgs = msgs
|
||||
parentProps.remember = rememberMe
|
||||
parentProps.loginGoogle = googleButton
|
||||
|
||||
document.addEventListener("keypress", function(event) {
|
||||
if (event.code == "Enter") {
|
||||
if (focused) {
|
||||
AuthTools.login(msgs,inputs)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
renderGoogle()
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<div id="login-group"class="pane auth-pane">
|
||||
<h2 class="auth-title">LOG IN</h2>
|
||||
<label class="auth-label" for="emailInput">Email </label><span bind:this={emailMsg} id="email-msg"></span>
|
||||
<input bind:this={emailInput} id="emailInput" class="authEmailInput" type="email">
|
||||
<div class="password-field">
|
||||
<label class="auth-label" for="passwordInput">Password </label><span bind:this={passwordMsg} id="password-msg"></span>
|
||||
<input bind:this={passwordInput} id="passwordInput" class="authPasswordInput" type="password">
|
||||
<button bind:this={passwordVisibilityButton} class="eye-icon" on:click="{() => AuthTools.changePasswordVisibility(passwordVisibilityButton)}">
|
||||
<object type="image/svg+xml" data="/img/auth/eye_icon.svg" title="eye icon"></object>
|
||||
</button>
|
||||
</div>
|
||||
<div id="remember-me">
|
||||
<input bind:this={rememberMe} type="checkbox" id="remember-me-checkbox"><label id="remember-me-label" for="passwordInput">remember me</label>
|
||||
</div>
|
||||
<button class="auth-button" on:click="{() => AuthTools.login(msgs,inputs)}">Log in</button>
|
||||
<a id="forgot-password" href="forgot-password">Forgot password?</a>
|
||||
<hr class="auth-line">
|
||||
<div class="auth-methods-group">
|
||||
<div id="google-btn-wrapper">
|
||||
<div bind:this={googleButton} id="google-btn"></div>
|
||||
<img src="/img/auth/google_icon.svg" id="google-logo" alt="google icon">
|
||||
</div>
|
||||
<!--
|
||||
<button on:click={openGoogleWindow}>
|
||||
<img src="img/auth/google_icon.svg" id="navbar-logo" alt="google icon">
|
||||
</button>
|
||||
<button onclick="">
|
||||
<img src="img/auth/facebook_icon.svg" id="navbar-logo" alt="facebook icon">
|
||||
</button>
|
||||
<button onclick="">
|
||||
<img src="img/auth/linkedin_icon.svg" id="navbar-logo" alt="linkedin icon">
|
||||
</button>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@import '/css/common.css';
|
||||
@import '/css/auth.css';
|
||||
|
||||
</style>
|
241
Server/app/svelte/src/auth/signup-component.svelte
Normal file
241
Server/app/svelte/src/auth/signup-component.svelte
Normal file
@@ -0,0 +1,241 @@
|
||||
<svelte:options tag="signup-component" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Export statements
|
||||
export let focused = false
|
||||
|
||||
// Main code
|
||||
|
||||
let signupGroup
|
||||
let emailInput
|
||||
let passwordInput
|
||||
let passwordVisibilityButton
|
||||
let inputs
|
||||
let googleButton
|
||||
|
||||
let emailMsg
|
||||
let passwordMsg
|
||||
let msgs
|
||||
let rememberMe
|
||||
|
||||
let dialog
|
||||
let signUp
|
||||
let signUpField
|
||||
|
||||
let parentProps = getContext("auth")
|
||||
|
||||
function removeMsg(msg) {
|
||||
if (msg.innerHTML!="") {
|
||||
msg.innerHTML = ""
|
||||
}
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
dialog.style.display = "block"
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (dialog!=null) {
|
||||
dialog.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function sendEmail() {
|
||||
let email = signUpField.value
|
||||
if (email.includes("@")) {
|
||||
sendText("/get-email",email)
|
||||
signUpField.value = ""
|
||||
signUpField.placeholder = "Subscribed!"
|
||||
signUpField.style.setProperty("--c", "hsl(147, 33%, 60%)")
|
||||
}
|
||||
else {
|
||||
signUpField.value = ""
|
||||
signUpField.placeholder = "must contain '@'"
|
||||
signUpField.style.setProperty("--c", "hsl(0, 100%, 60%)")
|
||||
}
|
||||
}
|
||||
|
||||
function clearField() {
|
||||
signUpField.placeholder = ""
|
||||
}
|
||||
|
||||
function renderGoogle() {
|
||||
if (parentProps.googleInit) {
|
||||
google.accounts.id.renderButton(googleButton,{
|
||||
theme: 'outline',
|
||||
size: 'large'
|
||||
})
|
||||
}
|
||||
else {
|
||||
setTimeout(renderGoogle,100)
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
||||
rememberMe.checked = true
|
||||
inputs = {email: emailInput, password: passwordInput}
|
||||
msgs = {email: emailMsg, password: passwordMsg}
|
||||
|
||||
document.addEventListener("keypress", function(event) {
|
||||
if (event.code == "Enter") {
|
||||
if (focused) {
|
||||
AuthTools.signup(msgs,inputs,toLandingPage)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//renderGoogle()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<div id="signup-group" class="pane auth-pane" bind:this={signupGroup}>
|
||||
<h2 class="auth-title">SIGN UP</h2>
|
||||
<label class="auth-label" for="emailInput">Email </label><span bind:this={emailMsg} id="email-msg" on:change={() => removeMsg(emailMsg)}></span>
|
||||
<input bind:this={emailInput} id="emailInput" class="authEmailInput" type="email">
|
||||
<div class="password-field">
|
||||
<label class="auth-label" for="emailInput">Password </label><span bind:this={passwordMsg} id="password-msg"></span>
|
||||
<input bind:this={passwordInput} id="passwordInput" class="authPasswordInput" type="password" on:change={() => removeMsg(passwordMsg)}>
|
||||
<button bind:this={passwordVisibilityButton} class="eye-icon" on:click="{() => AuthTools.changePasswordVisibility(passwordVisibilityButton)}">
|
||||
<object type="image/svg+xml" data="/img/auth/eye_icon.svg" title="eye-icon"></object>
|
||||
</button>
|
||||
</div>
|
||||
<div id="remember-me">
|
||||
<input bind:this={rememberMe} type="checkbox" id="remember-me-checkbox"><label id="remember-me-label" for="passwordInput">remember me</label>
|
||||
</div>
|
||||
<button class="auth-button" on:click="{showDialog}">Sign up</button> <!--() => AuthTools.signup(msgs,inputs,AuthTools.toLandingPage)-->
|
||||
<p id="forgot-password"></p>
|
||||
<hr class="auth-line">
|
||||
<div class="auth-methods-group">
|
||||
<button on:click="{showDialog}">
|
||||
<img src="/img/auth/google_icon.svg" id="navbar-logo" alt="google icon">
|
||||
</button>
|
||||
<!--<button onclick="">
|
||||
<img src="img/auth/facebook_icon.svg" id="navbar-logo" alt="facebook icon">
|
||||
</button>
|
||||
<button onclick="">
|
||||
<img src="img/auth/linkedin_icon.svg" id="navbar-logo" alt="linkedin icon">
|
||||
</button>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div bind:this={dialog} id="dialog">
|
||||
<button id="shadow" on:click={hide}></button>
|
||||
<div id="wrapper" class="pane">
|
||||
<h2>Registration is closed</h2>
|
||||
<p>We are still in the process of opening.</p>
|
||||
<p>Sign up for updates to know when it becomes available:</p>
|
||||
<div id="newsletter-container">
|
||||
<input bind:this={signUpField} on:click={clearField} id="newsletterEmailInput" type="text">
|
||||
<button bind:this={signUp} on:click={sendEmail} id="newsletterEmailButton">sign up</button>
|
||||
</div>
|
||||
<button id="no-button" on:click={hide}>No thanks</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@import '/css/common.css';
|
||||
@import '/css/auth.css';
|
||||
|
||||
#dialog {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#wrapper p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
#wrapper h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
#shadow {
|
||||
position: fixed;
|
||||
cursor: default;
|
||||
top: 50%; right: 50%;
|
||||
transform: translate(50%,-50%);
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background:rgb(0, 0, 0, 0.2);
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
#newsletter-container {
|
||||
position: relative;
|
||||
height: 3rem;
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#newsletterEmailInput {
|
||||
height: 2.5rem;
|
||||
border-radius: 0.2rem 0 0 0.2rem;
|
||||
filter: drop-shadow( 0.07rem 0.14rem 0.07rem rgb(0 0 0 / 0.4));
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#newsletterEmailInput::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||
color: var(--c,gray);
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
|
||||
#newsletterEmailButton {
|
||||
width: 6.8rem;
|
||||
height: 2.5rem;
|
||||
background: var(--pink);
|
||||
color: #ffffff;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.4rem;
|
||||
border-radius: 0 0.2rem 0.2rem 0;
|
||||
filter: drop-shadow( 0.07rem 0.14rem 0.07rem rgb(0 0 0 / 0.4));
|
||||
}
|
||||
|
||||
#newsletterEmailButton:active {
|
||||
background: var(--darker-pink);
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
top: 50%; right: 50%;
|
||||
transform: translate(50%,-50%);
|
||||
position: fixed;
|
||||
max-width: 36rem;
|
||||
width: 90vw;
|
||||
padding: 2rem 4rem;
|
||||
z-index: 1999999;
|
||||
}
|
||||
|
||||
#wrapper * {
|
||||
font-family: var(--sans-serif);
|
||||
}
|
||||
|
||||
#no-button {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 13rem;
|
||||
height: 3rem;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: #ffffff;
|
||||
border: 0.2rem solid var(--pink);
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.4rem;
|
||||
border-radius: 0.5rem;
|
||||
filter: drop-shadow( 0.07rem 0.14rem 0.07rem rgb(0 0 0 / 0.4));
|
||||
}
|
||||
|
||||
#no-button:active {
|
||||
background: hsl(343, 23%, 82%);
|
||||
}
|
||||
|
||||
</style>
|
@@ -71,17 +71,17 @@
|
||||
<div bind:this={root} id="root" class="pane-centering">
|
||||
<div class="pane-container">
|
||||
<div id="sidebars-left" class="sidebar">
|
||||
<div bind:this={sidebarLeft} id="sidebar-left" class="pane">
|
||||
<div bind:this={sidebarLeft} id="sidebar-left">
|
||||
<slot name="sidebar-left"></slot>
|
||||
</div>
|
||||
<div bind:this={sidebarLeft2} id="sidebar-left2" class="pane">
|
||||
<div bind:this={sidebarLeft2} id="sidebar-left2">
|
||||
<slot name="sidebar-left2"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div bind:this={sidebarRight} id="sidebar-right" class="pane sidebar">
|
||||
<slot name="sidebar-right"></slot>
|
||||
</div>
|
||||
<div bind:this={mainPane} id="main-pane" class="pane">
|
||||
<div bind:this={mainPane} id="main-pane">
|
||||
<slot name="main" id="main-slot"></slot>
|
||||
</div>
|
||||
</div>
|
||||
@@ -95,7 +95,10 @@
|
||||
}
|
||||
|
||||
#root {
|
||||
position: relative;
|
||||
margin-top: auto;
|
||||
min-height: var(--min-height,auto);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#main-pane {
|
||||
@@ -105,10 +108,8 @@
|
||||
padding-top: var(--padding-top,0rem);
|
||||
padding-bottom: var(--padding-bottom,0rem);
|
||||
text-align: justify;
|
||||
background: var(--background,white);
|
||||
box-shadow: var(--box-shadow,0 0 0.314rem rgb(187, 187, 187));
|
||||
margin: auto;
|
||||
height: min-content;
|
||||
height: 100%;
|
||||
max-width: var(--width-main,66rem);
|
||||
width: var(--width-main,66rem);
|
||||
z-index: 1;
|
||||
@@ -124,13 +125,14 @@
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-left: calc(-1*var(--width-left,22.5rem) - 1rem - 4rem);
|
||||
width: calc(var(--width-left,22.5rem) + 4rem);
|
||||
width: max-content;
|
||||
max-width: 30rem;
|
||||
}
|
||||
|
||||
#sidebar-left,#sidebar-left2 {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
padding: 2rem 2rem;
|
||||
padding: 0rem 0rem;
|
||||
}
|
||||
|
||||
#sidebar-left {
|
||||
@@ -149,16 +151,16 @@
|
||||
padding: 2rem 2rem;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1880px) {
|
||||
@media only screen and (max-width: 1340px) {
|
||||
|
||||
#main-pane {
|
||||
max-width: initial;
|
||||
width: 100%;
|
||||
max-width: var(--width-main,66rem);
|
||||
padding-left: var(--padding-left-mobile,1.8rem);
|
||||
padding-right: var(--padding-right-mobile,1.8rem);
|
||||
padding-top: var(--padding-top-mobile,1.8rem);
|
||||
padding-bottom: var(--padding-bottom-mobile,1.8rem);
|
||||
padding-left: var(--padding-left-mobile,0rem);
|
||||
padding-right: var(--padding-right-mobile,0rem);
|
||||
padding-top: var(--padding-top-mobile,0rem);
|
||||
padding-bottom: var(--padding-bottom-mobile,0rem);
|
||||
}
|
||||
|
||||
#sidebars-left, #sidebar-right {
|
||||
|
@@ -32,8 +32,8 @@
|
||||
<button on:click={() => {location.href='#'}} id="footer-up" aria-label="go up">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="42.545" height="72.601" viewBox="0 0 42.545 72.601">
|
||||
<g id="Group_268" data-name="Group 268" transform="translate(-6.177 -2.399)">
|
||||
<rect id="Rectangle_146" data-name="Rectangle 146" width="11" height="51" rx="5.5" transform="translate(22 24)" fill="#cb1816"/>
|
||||
<path id="Path_1145" data-name="Path 1145" d="M23.814,4.021a5,5,0,0,1,7.372,0l16.134,17.6c2.94,3.207,1.046,10.4-3.686,8.379S28.02,14.081,28.391,13.524,16.544,27.976,11.366,30,4.741,24.828,7.68,21.621Z" fill="#DD1C1A"/>
|
||||
<rect id="Rectangle_146" data-name="Rectangle 146" width="11" height="51" rx="5.5" transform="translate(22 24)" fill="var(--red)"/>
|
||||
<path id="Path_1145" data-name="Path 1145" d="M23.814,4.021a5,5,0,0,1,7.372,0l16.134,17.6c2.94,3.207,1.046,10.4-3.686,8.379S28.02,14.081,28.391,13.524,16.544,27.976,11.366,30,4.741,24.828,7.68,21.621Z" fill="var(--red)"/>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
@@ -54,8 +54,8 @@ footer {
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
background: #5B6970;/*var(--dark-green);*/
|
||||
border-top: #cb1816 solid 0.5rem;
|
||||
background: var(--gray);
|
||||
border-top: var(--red) solid 0.5rem;
|
||||
}
|
||||
|
||||
footer p, footer a {
|
||||
|
@@ -228,7 +228,7 @@
|
||||
<p class="description">If there are no groups in your town with whom you can organize then do the following:</p>
|
||||
<ol>
|
||||
<li>Click on the map to show us where you are located;</li>
|
||||
<li>Add a way to contact you or leave blank for a pin to point to our discord;</li>
|
||||
<li>Add a way to contact you (an invite link or an email, not a phone number) or leave blank for a pin to point to our discord;</li>
|
||||
<li>Press "Submit" to add yourself to our map;</li>
|
||||
<li>Verify yourself by having a chat with us at our Discord server to show on the map;</li>
|
||||
</ol>
|
||||
|
@@ -163,7 +163,7 @@
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
width: 14rem;
|
||||
line-height: 4rem;
|
||||
background: #cb1816;
|
||||
background: var(--red);
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
419
Server/app/svelte/src/navbar/navbar-logged.svelte
Normal file
419
Server/app/svelte/src/navbar/navbar-logged.svelte
Normal file
@@ -0,0 +1,419 @@
|
||||
<svelte:options tag="navbar-logged" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { loadLocaleContent, locales } from "/js/libraries/serverTools.js"
|
||||
|
||||
// Main code
|
||||
let hambInput
|
||||
let navbar
|
||||
let localesDropdown
|
||||
let initiativesDropdown
|
||||
let loaded = writable(0)
|
||||
let content = writable({})
|
||||
let logoText
|
||||
|
||||
let locale = loadLocaleContent(content,"navbar-component",loaded)
|
||||
|
||||
function changeNavbar() {
|
||||
if (hambInput.checked) {
|
||||
navbar.style.background = "white"
|
||||
//navbar.style.boxShadow = "0 0 0.314rem rgb(187, 187, 187)"
|
||||
}
|
||||
else {
|
||||
setTimeout(()=> {
|
||||
navbar.style.position = "relative"
|
||||
navbar.style.background = ""
|
||||
navbar.style.boxShadow = ""
|
||||
}
|
||||
,510)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function showDropdown(dropdown) {
|
||||
let state = dropdown.style.display
|
||||
initiativesDropdown.style.display = "none"
|
||||
localesDropdown.style.display = "none"
|
||||
if (state=="block") {
|
||||
dropdown.style.display = "none"
|
||||
}
|
||||
else {
|
||||
dropdown.style.display = "block"
|
||||
}
|
||||
}
|
||||
|
||||
function changeLocale(lang) {
|
||||
localStorage.setItem("locale",lang)
|
||||
let locSplit = location.href.split("/")
|
||||
let localesSymbols = Object.keys(locales)
|
||||
locSplit = locSplit.filter(x => !localesSymbols.includes(x))
|
||||
let loc = locSplit.slice(0,locSplit.length-1).join("/") + "/" + lang + "/" + locSplit[locSplit.length-1]
|
||||
location.href = loc
|
||||
}
|
||||
|
||||
function fixHeading() {
|
||||
if (locale=="ru") {
|
||||
let func = () => {
|
||||
if (logoText==undefined) {
|
||||
setTimeout(func,100)
|
||||
}
|
||||
else {
|
||||
if (((window.innerWidth < 1700 && window.innerWidth > 1400) || window.innerWidth < 400) && logoText.style.lineHeight!="100%") {
|
||||
logoText.style.lineHeight = "120%"
|
||||
logoText.style.top = "1rem"
|
||||
logoText.style.width = "16rem"
|
||||
}
|
||||
else if (((window.innerWidth > 1700) || (window.innerWidth > 400 && window.innerWidth < 1400)) && logoText.style.lineHeight!="400%") {
|
||||
logoText.style.lineHeight = "400%"
|
||||
logoText.style.top = "0rem"
|
||||
logoText.style.width = "auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
func()
|
||||
addEventListener("resize", func)
|
||||
}
|
||||
}
|
||||
|
||||
function hide(dropdown) {
|
||||
let callback = () => {
|
||||
dropdown.style.display = "none"
|
||||
}
|
||||
setTimeout(callback,100)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fixHeading()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Navigation bar -->
|
||||
{#key loaded}
|
||||
{#if Object.keys($content).length!=0}
|
||||
<header bind:this={navbar} id="navbar">
|
||||
<!-- Hamburger icon -->
|
||||
<input bind:this={hambInput} type="checkbox" id="side-menu" on:click={changeNavbar}>
|
||||
<label id="hamb" for="side-menu"><span id="hamb-line"></span></label>
|
||||
<!-- Logo -->
|
||||
<a id=logo-container href={"/" + locale + "/"}>
|
||||
<img src="/img/common/flag.png" id="navbar-logo" alt="logo">
|
||||
<span bind:this={logoText} id="navbar-logo-text" >{@html $content.orgName}</span>
|
||||
</a>
|
||||
<!-- Menu -->
|
||||
<nav id="nav">
|
||||
<ul id="menu">
|
||||
<li><a href={"/"+locale+"/join-us"}>{$content.joinUs}</a></li>
|
||||
<li><a href={"/"+locale+"/manifesto"}>{$content.manifesto}</a></li>
|
||||
<!-- Options dropdown -->
|
||||
<!-- A list of links pointing to different pages of the website. Implemented as a div opened on :hover-->
|
||||
<li id="options-container">
|
||||
<button on:click={() => showDropdown(initiativesDropdown)} on:focusout={() => hide(initiativesDropdown)} class="options-button">{$content.initiatives}</button>
|
||||
<div bind:this={initiativesDropdown} class="options-dropdown">
|
||||
<a href={"/"+locale+"/groups"}>{$content.groups}</a>
|
||||
<a href={"/"+locale+"/communes"}>{$content.communes}</a>
|
||||
<a href={"/"+locale+"/cooperatives"}>{$content.cooperatives}</a>
|
||||
<a href={"/"+locale+"/parties"}>{$content.parties}</a>
|
||||
<a href={"/"+locale+"/partners"}>{$content.partners}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href={"/"+locale+"/profile"}>{$content.profile}</a></li>
|
||||
<li id="locales">
|
||||
<button on:click={() => showDropdown(localesDropdown)} on:focusout={() => hide(localesDropdown)}>
|
||||
<picture>
|
||||
<source srcset="/img/common/globe.webp">
|
||||
<source srcset="/img/common/globe.png">
|
||||
<img id="locales-img" alt="globe">
|
||||
</picture>
|
||||
</button>
|
||||
</li>
|
||||
<div bind:this={localesDropdown} class="options-dropdown">
|
||||
{#each Object.entries(locales) as [loc,name]}
|
||||
<button on:click={() => changeLocale(loc)}>{name}</button>
|
||||
{/each}
|
||||
</div>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
{/if}
|
||||
{/key}
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
@import '/css/common.css';
|
||||
|
||||
/* Header */
|
||||
#navbar{
|
||||
position: relative;
|
||||
top: 0;
|
||||
width: min(100%,116rem);
|
||||
z-index: 1000000000;
|
||||
height: 5.26rem;
|
||||
padding-left: 0rem;
|
||||
padding-right: 0rem;
|
||||
}
|
||||
|
||||
#navbar * {
|
||||
font-family: var(--sans-serif, sans-serif);
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
#logo-container {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
margin-left: 1rem;
|
||||
height: 100%;
|
||||
max-height: 5.26rem;
|
||||
color: black;
|
||||
z-index: 1;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#navbar-logo {
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
object-fit: contain;
|
||||
border-radius: 10rem;
|
||||
}
|
||||
|
||||
#navbar-logo-text {
|
||||
position: relative;
|
||||
word-wrap: normal;
|
||||
height: 100%;
|
||||
line-height: 400%;
|
||||
font-size: 1.4rem;
|
||||
color: #292222;
|
||||
font-family: var(--sans-serif, sans-serif);
|
||||
font-weight: 400;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
/* Nav menu */
|
||||
#nav {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
#menu > li > a, .options-button {
|
||||
display: block;
|
||||
padding: 1.2rem;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
color: black;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#menu > li > a:active{
|
||||
background-color: #f7aec0;
|
||||
}
|
||||
|
||||
#menu li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#nav{
|
||||
max-height: 0;
|
||||
/*transition: max-height .5s ease-out;*/
|
||||
}
|
||||
|
||||
/* Menu Icon */
|
||||
#hamb{
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
right: 0rem;
|
||||
padding: 2.8rem 2rem;
|
||||
z-index: 9999;
|
||||
}/* Style label tag */
|
||||
|
||||
#hamb-line {
|
||||
background: black;
|
||||
display: block;
|
||||
height: 2px;
|
||||
position: relative;
|
||||
width: 24px;
|
||||
|
||||
} /* Style span tag */
|
||||
|
||||
#hamb-line::before,
|
||||
#hamb-line::after{
|
||||
background: black;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transition: all .2s ease-out;
|
||||
width: 100%;
|
||||
}
|
||||
#hamb-line::before{
|
||||
top: 5px;
|
||||
}
|
||||
#hamb-line::after{
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
#side-menu {
|
||||
display: none;
|
||||
} /* Hide checkbox */
|
||||
|
||||
/* Toggle menu icon */
|
||||
#side-menu:checked ~ nav {
|
||||
display: block;
|
||||
max-height: 100%;
|
||||
padding-top: 5.625rem;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #logo-container {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #hamb {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #logo-container {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #hamb #hamb-line {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #hamb #hamb-line::before {
|
||||
transform: rotate(-45deg);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ #hamb #hamb-line::after {
|
||||
transform: rotate(45deg);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* Options */
|
||||
|
||||
.options-dropdown {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 5.6rem;
|
||||
right: 1.8rem;
|
||||
border: #404040 solid 0.1rem;
|
||||
background-color: white;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.options-dropdown button, .options-dropdown a {
|
||||
display: block;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.2rem;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.options-dropdown button:hover, .options-dropdown a:hover {
|
||||
background-color: var(--red);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.options-button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Localization */
|
||||
|
||||
#locales {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#locales button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
#locales button:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#locales-img {
|
||||
position: relative;
|
||||
top: 0rem;
|
||||
height: 2rem;
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
|
||||
/*
|
||||
#options-dropdown>:first-child {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#options-dropdown>:nth-child(2) {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Responsiveness */
|
||||
@media only screen and (min-width: 1200px) {
|
||||
|
||||
#navbar {
|
||||
position: relative;
|
||||
width: min(100%,116rem);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding-right: 4rem;
|
||||
padding-left: 4rem;
|
||||
}
|
||||
|
||||
#nav {
|
||||
max-height: none;
|
||||
top: 0;
|
||||
position: relative;
|
||||
float: right;
|
||||
width: fit-content;
|
||||
background-color: transparent;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#side-menu:checked ~ nav {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#menu li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menu > li > a:hover, .options-button:hover, #navbar-logo-text:hover {
|
||||
color: rgb(127, 127, 127);
|
||||
}
|
||||
|
||||
#menu > li > a, .options-button {
|
||||
padding: 0.9rem;
|
||||
padding-top: 1.9rem;
|
||||
padding-bottom: 1.9rem;
|
||||
}
|
||||
|
||||
#hamb {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#locales {
|
||||
position: relative;
|
||||
margin-right: 1.8rem;
|
||||
}
|
||||
|
||||
#locales-img {
|
||||
top: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
@@ -1,4 +1,4 @@
|
||||
<svelte:options tag="navbar-component" />
|
||||
<svelte:options tag="navbar-not-logged" />
|
||||
|
||||
<script>
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
<a href={"/"+locale+"/partners"}>{$content.partners}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href={"/"+locale+"/auth"}>{$content.login}</a></li>
|
||||
<li id="locales">
|
||||
<button on:click={() => showDropdown(localesDropdown)} on:focusout={() => hide(localesDropdown)}>
|
||||
<picture>
|
||||
@@ -320,7 +321,7 @@
|
||||
}
|
||||
|
||||
.options-dropdown button:hover, .options-dropdown a:hover {
|
||||
background-color: rgb(187 53 52 / 96%);
|
||||
background-color: var(--red);
|
||||
color: white;
|
||||
}
|
||||
|
20
Server/app/svelte/src/profile/profile-communes.svelte
Normal file
20
Server/app/svelte/src/profile/profile-communes.svelte
Normal file
@@ -0,0 +1,20 @@
|
||||
<svelte:options tag="profile-communes" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Main code
|
||||
|
||||
onMount(() => {
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
265
Server/app/svelte/src/profile/profile-component.svelte
Normal file
265
Server/app/svelte/src/profile/profile-component.svelte
Normal file
@@ -0,0 +1,265 @@
|
||||
<svelte:options tag="profile-component" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import libraries
|
||||
import { onMount, afterUpdate, setContext } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
import {svgFromObject} from "/js/libraries/miscTools.js"
|
||||
|
||||
//Import components
|
||||
import "/js/components/pane-aligner.js"
|
||||
import "/js/components/profile-general.js"
|
||||
import "/js/components/profile-groups.js"
|
||||
|
||||
// Main code
|
||||
AuthTools.redirectNotLogged()
|
||||
|
||||
let root
|
||||
let general
|
||||
let groups
|
||||
let communes
|
||||
let coops
|
||||
let parties
|
||||
let panes
|
||||
|
||||
let generalButton
|
||||
let groupsButton
|
||||
let communesButton
|
||||
let coopsButton
|
||||
let partiesButton
|
||||
let buttons
|
||||
|
||||
let locationPopup
|
||||
|
||||
let user = {}
|
||||
AuthTools.getUser(user)
|
||||
|
||||
function changePane(pane,button) {
|
||||
for (let p of panes) {
|
||||
p.style.display = "none"
|
||||
}
|
||||
for (let b of buttons) {
|
||||
styleField(b,400,"#636363")
|
||||
}
|
||||
pane.style.display = "initial"
|
||||
|
||||
styleField(button,500,"#c52a28")
|
||||
}
|
||||
|
||||
function styleField(div,weight,color) {
|
||||
div.style.fontWeight = weight
|
||||
let svgObject = div.querySelector("object")
|
||||
let svgItem = svgFromObject(svgObject)
|
||||
svgItem.setAttribute("fill", color)
|
||||
}
|
||||
|
||||
function fillFields() {
|
||||
if (Object.keys(user).length!=0 && root!=undefined) {
|
||||
for (let b of buttons) {
|
||||
styleField(b,400,"#636363")
|
||||
}
|
||||
styleField(generalButton,500,"#c52a28")
|
||||
}
|
||||
else {
|
||||
setTimeout(fillFields, 100)
|
||||
}
|
||||
}
|
||||
|
||||
function showLocationOverlay() {
|
||||
locationPopup.style.display = "block"
|
||||
}
|
||||
|
||||
setContext("profile-component",showLocationOverlay)
|
||||
|
||||
onMount(() => {
|
||||
general.user = user
|
||||
|
||||
panes = [general,groups,communes,coops,parties]
|
||||
buttons = [generalButton,groupsButton,communesButton,coopsButton,partiesButton]
|
||||
|
||||
fillFields()
|
||||
general.style.display = "initial"
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this={locationPopup} class="overlay" style="display: none">
|
||||
<div id="location-overlay-content">
|
||||
<p>wegwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww</p>
|
||||
</div>
|
||||
<button class="overlay-button" on:click={() => locationPopup.style.display = "none"}></button>
|
||||
</div>
|
||||
|
||||
<pane-aligner>
|
||||
<div id="left-column" class="pane" slot="sidebar-left" bind:this={root}>
|
||||
<button bind:this={generalButton} on:click={() => changePane(general,generalButton)}>
|
||||
<object id="general-img" class="icons" type="image/svg+xml" data="/img/profile/icons/general.svg" title="general"></object>
|
||||
<span>general</span>
|
||||
</button>
|
||||
<button bind:this={groupsButton} on:click={() => changePane(groups,groupsButton)}>
|
||||
<object id="groups-img" class="icons" type="image/svg+xml" data="/img/common/groups.svg" title="groups"></object>
|
||||
<span>groups</span>
|
||||
</button>
|
||||
<button bind:this={communesButton} on:click={() => changePane(communes,communesButton)}>
|
||||
<object id="communes-img" class="icons" type="image/svg+xml" data="/img/common/communes.svg" title="communes"></object>
|
||||
<span>communes</span>
|
||||
</button>
|
||||
<button bind:this={coopsButton} on:click={() => changePane(coops,coopsButton)}>
|
||||
<object id="coops-img" class="icons" type="image/svg+xml" data="/img/common/coops.svg" title="coops"></object>
|
||||
<span>cooperatives</span>
|
||||
</button>
|
||||
<button bind:this={partiesButton} on:click={() => changePane(parties,partiesButton)}>
|
||||
<object id="parties-img" class="icons" type="image/svg+xml" data="/img/common/parties.svg" title="parties"></object>
|
||||
<span>parties</span>
|
||||
</button>
|
||||
<button on:click={AuthTools.logout} id="logout-button">
|
||||
<object id="logout-img" class="icons" type="image/svg+xml" data="/img/profile/icons/logout.svg" title=""></object>
|
||||
<span>logout</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="main-column" slot="main">
|
||||
<profile-general bind:this={general} style="display: none;"></profile-general>
|
||||
<profile-groups bind:this={groups} style="display: none;"></profile-groups>
|
||||
<profile-communes bind:this={communes} style="display: none;"></profile-communes>
|
||||
<profile-coops bind:this={coops} style="display: none;"></profile-coops>
|
||||
<profile-parties bind:this={parties} style="display: none;"></profile-parties>
|
||||
</div>
|
||||
</pane-aligner>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
@import '/css/common.css';
|
||||
|
||||
#location-overlay-content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 40rem;
|
||||
width: 40rem;
|
||||
background: white;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
top: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.overlay-button {
|
||||
position: absolute;
|
||||
background: gray;
|
||||
opacity: 0.5;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#general-img {
|
||||
top: 0rem;
|
||||
}
|
||||
|
||||
#groups-img {
|
||||
top: 0.3rem;
|
||||
}
|
||||
|
||||
#coops-img {
|
||||
top: 0rem;
|
||||
}
|
||||
|
||||
#parties-img {
|
||||
top: 0rem;
|
||||
}
|
||||
|
||||
#logout-img {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
#logout-button {
|
||||
padding-top: 1rem;
|
||||
padding-left: 0.1rem;
|
||||
}
|
||||
|
||||
#left-column {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 15.2rem;
|
||||
padding: 2rem;
|
||||
border-radius: 0.64rem 0.64rem 0.64rem 0.64rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.icons {
|
||||
position: relative;
|
||||
width: 1.8rem;
|
||||
}
|
||||
|
||||
#left-column button span {
|
||||
position: absolute;
|
||||
padding-left: 3.4rem;
|
||||
margin-top: 0rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
}
|
||||
|
||||
#left-column button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#main-column {
|
||||
padding: 1rem 2rem 1rem 2rem;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 0 0.64rem 0.64rem 0;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
min-height: 20rem;
|
||||
}
|
||||
|
||||
pane-aligner {
|
||||
--width-main: 800px;
|
||||
--width-left: 10.5rem;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1340px) {
|
||||
|
||||
|
||||
#left-column {
|
||||
position: relative;
|
||||
margin-left: 0rem;
|
||||
width: 100%;
|
||||
border-radius: 0.64rem 0.64rem 0rem 0;
|
||||
}
|
||||
|
||||
#main-column {
|
||||
border-radius: 0.64rem;
|
||||
padding: 3rem 0.5rem;
|
||||
padding-bottom: 1.5rem;
|
||||
border-radius: 0rem 0rem 0.64rem 0.64rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#logout-button {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#left-column button {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
#logout-button {
|
||||
padding-top: 1rem;
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
20
Server/app/svelte/src/profile/profile-coops.svelte
Normal file
20
Server/app/svelte/src/profile/profile-coops.svelte
Normal file
@@ -0,0 +1,20 @@
|
||||
<svelte:options tag="profile-coops" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Main code
|
||||
|
||||
onMount(() => {
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
415
Server/app/svelte/src/profile/profile-general.svelte
Normal file
415
Server/app/svelte/src/profile/profile-general.svelte
Normal file
@@ -0,0 +1,415 @@
|
||||
<svelte:options tag="profile-general" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, setContext } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
//Import components
|
||||
import "/js/components/select-component.js"
|
||||
import "/js/components/switch-component.js"
|
||||
|
||||
//Export statements
|
||||
export let user = null
|
||||
|
||||
// Main code
|
||||
let emailInput
|
||||
|
||||
let section
|
||||
let saveEmailButton
|
||||
let changePasswordInputDiv
|
||||
let changePasswordMsg
|
||||
let savePasswordButton
|
||||
let passwordInput
|
||||
let changePasswordDiv
|
||||
let passwordVisibilityButton
|
||||
let emailMsg
|
||||
let passwordDiv
|
||||
let emailDiv
|
||||
let emailInputDiv
|
||||
let prevEmail
|
||||
|
||||
function showSaveButton(button) {
|
||||
prevEmail = emailInput.value
|
||||
button.style.display = "initial"
|
||||
emailMsg.style.display = "inline"
|
||||
let windowWidth = window.innerWidth
|
||||
if (windowWidth<1100) {
|
||||
emailInputDiv.style.marginTop = "1rem"
|
||||
emailDiv.style.flexDirection = "column"
|
||||
}
|
||||
else {
|
||||
//emailInput.style.width = "19rem"
|
||||
}
|
||||
}
|
||||
|
||||
function saveEmail() {
|
||||
let email = emailInput.value
|
||||
if (AuthTools.checkEmail(email,emailMsg)) {
|
||||
if (email!=user.email) {
|
||||
AuthTools.changeUser("email",email,user)
|
||||
}
|
||||
resetEmailField()
|
||||
}
|
||||
}
|
||||
|
||||
function resetEmailField() {
|
||||
if (prevEmail!=undefined) {
|
||||
emailInput.value = prevEmail
|
||||
}
|
||||
emailInput.style.width = "100%"
|
||||
emailMsg.style.display = "none"
|
||||
emailDiv.style.flexDirection = "row"
|
||||
emailInputDiv.style.marginTop = "0rem"
|
||||
saveEmailButton.style.display = "none"
|
||||
emailMsg.innerHTML = ""
|
||||
}
|
||||
|
||||
function launchChangePassword() {
|
||||
let windowWidth = window.innerWidth
|
||||
if (windowWidth<1100) {
|
||||
changePasswordInputDiv.style.display = "flex";
|
||||
}
|
||||
else {
|
||||
changePasswordInputDiv.style.display = "initial";
|
||||
}
|
||||
changePasswordDiv.style.display = "none";
|
||||
passwordInput.focus()
|
||||
}
|
||||
|
||||
function savePassword() {
|
||||
let password = passwordInput.value
|
||||
if (AuthTools.checkPassword(password,changePasswordMsg)) {
|
||||
if (password!=user.password) {
|
||||
AuthTools.changeUser("password",password,user)
|
||||
}
|
||||
changePasswordMsg.innerHTML = ""
|
||||
resetPasswordField()
|
||||
}
|
||||
}
|
||||
|
||||
function resetPasswordField() {
|
||||
changePasswordInputDiv.style.display = "none";
|
||||
changePasswordDiv.style.display = "initial";
|
||||
changePasswordMsg.innerHTML = ""
|
||||
}
|
||||
|
||||
function fillFields() {
|
||||
if (user!=null && Object.keys(user).length!=0 && section!=undefined) {
|
||||
emailInput.value = user.email
|
||||
}
|
||||
else {
|
||||
setTimeout(fillFields, 10)
|
||||
}
|
||||
}
|
||||
|
||||
function resizeInput(el) {
|
||||
el.nextElementSibling.innerHTML = el.value
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
||||
fillFields()
|
||||
|
||||
document.addEventListener("click", function(event) {
|
||||
if (passwordDiv.focused) {
|
||||
resetEmailField()
|
||||
}
|
||||
else if (emailDiv.focused) {
|
||||
resetPasswordField()
|
||||
}
|
||||
else {
|
||||
resetEmailField()
|
||||
resetPasswordField()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<section bind:this={section} id="general-section">
|
||||
<h2 class="title-highlight">General</h2>
|
||||
<div bind:this={emailDiv} on:mouseenter={emailDiv.focused=true} on:mouseleave={emailDiv.focused=false}>
|
||||
<div class="title-msg">
|
||||
<span>Email:</span>
|
||||
<span bind:this={emailMsg} id="signup-email-msg"></span>
|
||||
</div>
|
||||
<div bind:this={emailInputDiv} id="emailInputDiv">
|
||||
<button bind:this={saveEmailButton} id="save-email" class="save-button" on:click={saveEmail}>save</button>
|
||||
<div class="input-wrapper">
|
||||
<input bind:this={emailInput} id="emailInput" class="text-input" type="text" on:click={() => showSaveButton(saveEmailButton)} on:input={() => resizeInput(emailInput)}>
|
||||
<div class="ghost-input"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div bind:this={passwordDiv} on:mouseenter={passwordDiv.focused=true} on:mouseleave={passwordDiv.focused=false} id="change-password-line-wrapper">
|
||||
<div id="change-password-line">
|
||||
<div class="title-msg">
|
||||
<span>Password:</span>
|
||||
<span bind:this={changePasswordMsg} id="signup-password-msg"></span>
|
||||
</div>
|
||||
|
||||
<div bind:this={changePasswordDiv} id="change-password-div">
|
||||
<button id="change-password" on:click={launchChangePassword}>change
|
||||
<object type="image/svg+xml" data="/img/profile/icons/pencil.svg" title="pencil-icon"></object>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div bind:this={changePasswordInputDiv} id="change-password-input-div">
|
||||
<button bind:this={savePasswordButton} id="save-password" class="save-button" on:click={savePassword}>save</button>
|
||||
<input bind:this={passwordInput} id="passwordInput" class="text-input" type="password">
|
||||
<button bind:this={passwordVisibilityButton} class="eye-icon" on:click="{() => AuthTools.changePasswordVisibility(passwordVisibilityButton)}">
|
||||
<object type="image/svg+xml" data="/img/auth/eye_icon.svg" title="eye icon"></object>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
@import '/css/common.css';
|
||||
|
||||
/*---General section-----------------------------------------------------------*/
|
||||
|
||||
.ghost-input {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: inline-block;
|
||||
max-width: calc(100% - 10rem);
|
||||
min-width: 0rem;
|
||||
height: 2.5rem;
|
||||
position: relative;
|
||||
right: 0
|
||||
}
|
||||
|
||||
span {
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
#general-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#general-section h2 {
|
||||
margin: auto;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#general-section >div {
|
||||
height: 3.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-bottom: 0.14rem solid;
|
||||
border-color: #cdcdcd;
|
||||
}
|
||||
|
||||
#general-section >div >:first-child {
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
}
|
||||
|
||||
/* add padding to every line to center the diving line*/
|
||||
#general-section >div:last-child {
|
||||
padding-bottom: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
#general-section >div div,
|
||||
#general-section >div input,
|
||||
#general-section >div :not(:first-child) input {
|
||||
font-weight: 500;
|
||||
font-size: 1.15rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
color: #292222;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#general-section >div>:last-child {
|
||||
padding-right: 1.35rem;
|
||||
}
|
||||
|
||||
.text-input {
|
||||
position: relative;
|
||||
width: 20.475rem;
|
||||
direction: rtl;
|
||||
border: 0;
|
||||
outline: none;
|
||||
bottom: 0.341rem;
|
||||
}
|
||||
|
||||
|
||||
/*---Email-------------------------------------------------------------------*/
|
||||
|
||||
#emailInput {
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0.1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#save-email {
|
||||
display: none;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
#signup-email-msg,
|
||||
#signup-password-msg {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
color:red;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#signup-email-msg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#general-section >div:nth-child(2) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#emailInputDiv {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title-msg {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.title-msg * {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/*---Change password-------------------------------------------------------------------*/
|
||||
|
||||
#change-password-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#change-password-div {
|
||||
width: 9.3rem;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#change-password {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
width: 8rem;
|
||||
height: 2.73rem;
|
||||
font-size: 1.15rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
padding-right: 2rem;
|
||||
margin-top: -0.55rem;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#change-password > object {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 1.5rem;
|
||||
right: 0.0rem;
|
||||
}
|
||||
|
||||
#change-password-input-div {
|
||||
display: none;
|
||||
float: right;
|
||||
position: relative;
|
||||
margin-top: -1.7rem;
|
||||
}
|
||||
|
||||
#passwordInput {
|
||||
width: 15rem;
|
||||
right: 0.65rem;
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
position: relative;
|
||||
bottom: 0.34rem;
|
||||
margin-right: 0.6rem;
|
||||
height: 2.73rem;
|
||||
width: 4.778rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.15rem;
|
||||
color: white;
|
||||
background-color: var(--red);
|
||||
border-color: var(--red);
|
||||
border-radius: 0.512rem;
|
||||
}
|
||||
|
||||
#save-password {
|
||||
bottom: 0.6rem
|
||||
}
|
||||
|
||||
.eye-icon {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
opacity: 0.25;
|
||||
height: 2.2rem;
|
||||
width: 1.7rem;
|
||||
}
|
||||
|
||||
.eye-icon * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1100px) {
|
||||
|
||||
#change-password-line-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
min-height: 4rem;
|
||||
}
|
||||
|
||||
#change-password-input-div {
|
||||
margin-top: 1rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
#general-section >div:nth-child(2) {
|
||||
height: auto;
|
||||
min-height: 4rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#passwordInput {
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#emailInput {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#save-password {
|
||||
bottom: 0rem
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
300
Server/app/svelte/src/profile/profile-groups.svelte
Normal file
300
Server/app/svelte/src/profile/profile-groups.svelte
Normal file
@@ -0,0 +1,300 @@
|
||||
<svelte:options tag="profile-groups" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { getData } from "/js/libraries/serverTools.js"
|
||||
|
||||
//Import components
|
||||
import "/js/components/select-component.js"
|
||||
import "/js/components/switch-component.js"
|
||||
|
||||
//Export statements
|
||||
export let groups = null
|
||||
|
||||
// Main code
|
||||
let section
|
||||
let user_groups
|
||||
let content = writable({})
|
||||
let loaded = writable(0)
|
||||
|
||||
let membersInput
|
||||
let saveMembersButton
|
||||
let membersInputDiv
|
||||
|
||||
let contactInput
|
||||
let saveContactButton
|
||||
let contactInputDiv
|
||||
|
||||
let locale = "en"
|
||||
|
||||
let inputContact
|
||||
let inputMembers
|
||||
|
||||
function groups_callback(response) {
|
||||
user_groups = JSON.parse(response)
|
||||
inputContact = getContact(user_groups[0].contact)
|
||||
inputMembers = user_groups[0].members
|
||||
loaded.update((val) => {
|
||||
return val + 1
|
||||
})
|
||||
}
|
||||
getData("/xx/get_user_groups",groups_callback)
|
||||
|
||||
function getAddress(g) {
|
||||
let location = [g.country,g.state,g.town].filter(x => x!=null)
|
||||
return location.map(x => locale=="en" ? x : translate($content,x)).join(", ")
|
||||
}
|
||||
|
||||
function getContact(c) {
|
||||
if (c==null) {
|
||||
return "https://discord.gg/Qk8KUk787z"
|
||||
}
|
||||
else {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
function launchChangeLocation() {
|
||||
showLocationOverlay()
|
||||
}
|
||||
|
||||
function launchChangeMembers() {
|
||||
|
||||
}
|
||||
|
||||
function showSaveButton(button) {
|
||||
button.style.display = "initial"
|
||||
}
|
||||
|
||||
function resetMembersField() {
|
||||
saveMembersButton.style.display = "none"
|
||||
}
|
||||
|
||||
function resetContactField() {
|
||||
saveContactButton.style.display = "none"
|
||||
}
|
||||
|
||||
function saveMembers() {
|
||||
let email = emailInput.value
|
||||
if (AuthTools.checkEmail(email,emailMsg)) {
|
||||
if (email!=user.email) {
|
||||
AuthTools.changeUser("email",email,user)
|
||||
}
|
||||
resetMembersField()
|
||||
}
|
||||
}
|
||||
|
||||
function saveContact() {}
|
||||
|
||||
let showLocationOverlay = getContext("profile-component")
|
||||
|
||||
onMount(() => {
|
||||
|
||||
document.addEventListener("click", function(event) {
|
||||
if (membersInputDiv.focused) {
|
||||
resetContactField()
|
||||
}
|
||||
else if (contactInputDiv.focused) {
|
||||
resetMembersField()
|
||||
}
|
||||
else {
|
||||
resetMembersField()
|
||||
resetContactField()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{#key $loaded}
|
||||
{#if $loaded==1}
|
||||
|
||||
<h2>Groups</h2>
|
||||
<h3>My group</h3>
|
||||
<section bind:this={section} class="entries-section">
|
||||
<div>
|
||||
<div class="change-field-line">
|
||||
<span>Location:</span>
|
||||
<div class="change-field-div">
|
||||
<button class="change-field-button" on:click={launchChangeLocation}>{getAddress(user_groups[0])}
|
||||
<object type="image/svg+xml" data="/img/profile/icons/pencil.svg" title="pencil-icon" class="pencil"></object>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="change-field-line">
|
||||
<span>Members:</span>
|
||||
<div bind:this={membersInputDiv} class="change-field-div input-pencil">
|
||||
<button bind:this={saveMembersButton} class="save-button" on:click={saveMembers}>save</button>
|
||||
<input bind:this={membersInput} id="membersInput" class="text-input" type="text" bind:value={inputMembers} on:click={() => showSaveButton(saveMembersButton)}>
|
||||
<button class="text-input-pencil-button" on:click={() => membersInput.focus()}>
|
||||
<object type="image/svg+xml" data="/img/profile/icons/pencil.svg" title="pencil-icon" class="pencil"></object>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="change-field-line">
|
||||
<span>Contact:</span>
|
||||
<div bind:this={contactInputDiv} class="change-field-div input-pencil">
|
||||
<button bind:this={saveContactButton} class="save-button" on:click={saveContact}>save</button>
|
||||
<input bind:this={contactInput} id="contactInput" class="text-input" type="text" bind:value={inputContact} on:click={() => showSaveButton(saveContactButton)}>
|
||||
<button class="text-input-pencil-button" on:click={() => contactInput.focus()}>
|
||||
<object type="image/svg+xml" data="/img/profile/icons/pencil.svg" title="pencil-icon" class="pencil"></object>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<h3>Requests</h3>
|
||||
<section bind:this={section} class="entries-section">
|
||||
|
||||
</section>
|
||||
{/if}
|
||||
{/key}
|
||||
|
||||
|
||||
<style>
|
||||
@import '/css/common.css';
|
||||
|
||||
.text-input-pencil-button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 2.3rem;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.text-input-pencil-button object {
|
||||
top: 0rem;
|
||||
}
|
||||
|
||||
.pencil {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 1.5rem;
|
||||
right: 0.0rem;
|
||||
}
|
||||
|
||||
.change-field-div input.text-input {
|
||||
position: relative;
|
||||
width: 20.475rem;
|
||||
direction: rtl;
|
||||
border: 0;
|
||||
outline: none;
|
||||
bottom: 0.341rem;
|
||||
position: relative;
|
||||
top: 0.1rem;
|
||||
font-style: var(--sans-serif,sans-serif)
|
||||
}
|
||||
|
||||
#membersInput {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
#contactInput {
|
||||
max-width: 18rem;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
position: relative;
|
||||
bottom: 0.34rem;
|
||||
margin-right: 0.6rem;
|
||||
height: 2.73rem;
|
||||
width: 4.778rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.15rem;
|
||||
color: white;
|
||||
background-color: var(--red);
|
||||
border-color: var(--red);
|
||||
border-radius: 0.512rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.entries-section {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.entries-section >div {
|
||||
height: 3.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-bottom: 0.14rem solid;
|
||||
border-color: #cdcdcd;
|
||||
}
|
||||
|
||||
/* add padding to every line to center the diving line*/
|
||||
.entries-section >div:last-child {
|
||||
padding-bottom: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
/*---Change field-------------------------------------------------------------------*/
|
||||
|
||||
.change-field-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.change-field-div {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.change-field-button {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 2.73rem;
|
||||
font-size: 1.15rem;
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
padding-right: 1.9rem;
|
||||
margin-top: -0.55rem;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
/*---General section-----------------------------------------------------------*/
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.entry-container {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.entry {
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
span {
|
||||
font-family: var(--sans-serif,sans-serif);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
#groups-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#groups-section h2 {
|
||||
margin: auto;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
</style>
|
20
Server/app/svelte/src/profile/profile-parties.svelte
Normal file
20
Server/app/svelte/src/profile/profile-parties.svelte
Normal file
@@ -0,0 +1,20 @@
|
||||
<svelte:options tag="profile-parties" />
|
||||
|
||||
<script>
|
||||
|
||||
// Import statements
|
||||
import { onMount } from 'svelte'
|
||||
import * as AuthTools from "/js/libraries/authTools.js"
|
||||
|
||||
// Main code
|
||||
|
||||
onMount(() => {
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
Reference in New Issue
Block a user