Interim update

This commit is contained in:
a-ill
2023-07-30 13:04:15 +03:00
parent 9051fa90f3
commit 7c9bb1e830
111 changed files with 25589 additions and 170 deletions

View 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;
}

View File

@@ -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 {

View 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;
}
*/

View 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 = "/";
}

View File

@@ -7,5 +7,7 @@
"communes": "Communes",
"cooperatives": "Cooperatives",
"parties": "Parties",
"partners": "Partners"
"partners": "Partners",
"login": "Login",
"profile": "Profile"
}

View File

@@ -10,6 +10,7 @@ import watch from "rollup-plugin-watch";
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;

View 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>

View 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>

View 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&nbsp;</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&nbsp;</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>

View 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&nbsp;</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&nbsp;</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>

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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;
}

View 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>

View File

@@ -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;
}

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>