front style update

This commit is contained in:
ed barz 2023-05-29 12:46:35 +02:00
parent 3d75c39c07
commit ccc79e75d9
19 changed files with 542 additions and 12 deletions

View File

@ -1 +1 @@
VITE_API_URL=http://localhost:8069
VITE_API_URL=http://127.0.0.1:8069

171
package-lock.json generated
View File

@ -8,7 +8,8 @@
"name": "brz9front",
"version": "0.0.1",
"dependencies": {
"dotenv": "^16.0.3"
"dotenv": "^16.0.3",
"normalize.css": "^8.0.1"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
@ -19,6 +20,7 @@
"eslint-plugin-svelte": "^2.26.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.8.1",
"sass": "^1.62.1",
"svelte": "^3.54.0",
"vite": "^4.3.0"
}
@ -832,6 +834,19 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -844,6 +859,15 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -854,6 +878,18 @@
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
@ -903,6 +939,45 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/chokidar/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1301,6 +1376,18 @@
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -1457,6 +1544,12 @@
"node": ">= 4"
}
},
"node_modules/immutable": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
"dev": true
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -1508,6 +1601,18 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-builtin-module": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
@ -1562,6 +1667,15 @@
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
"dev": true
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@ -1752,6 +1866,20 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/normalize.css": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -2007,6 +2135,18 @@
}
]
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
@ -2109,6 +2249,23 @@
"node": ">=6"
}
},
"node_modules/sass": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/set-cookie-parser": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
@ -2278,6 +2435,18 @@
"globrex": "^0.1.2"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",

View File

@ -18,11 +18,13 @@
"eslint-plugin-svelte": "^2.26.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.8.1",
"sass": "^1.62.1",
"svelte": "^3.54.0",
"vite": "^4.3.0"
},
"type": "module",
"dependencies": {
"dotenv": "^16.0.3"
"dotenv": "^16.0.3",
"normalize.css": "^8.0.1"
}
}

View File

@ -3,6 +3,8 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="stylesheet" href="https://file.brz9.dev/cdn/fonts/base/inter.css">
<link rel="stylesheet" href="https://file.brz9.dev/cdn/fonts/brz9-v2.2/brz9-icon-v2.2.css">
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>

View File

@ -0,0 +1,67 @@
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let modalMessage = '';
function close() {
dispatch('close');
}
</script>
<div class="overlay"></div>
<div class="modal">
<header>
<button on:click={close} aria-label="close"><span class="brz9-icon-cross"></span></button>
</header>
<div class="modal-content">
<p>{modalMessage}</p>
</div>
</div>
<style lang="scss">
@import '../styles/variables';
.overlay {
position: fixed;
top: 0;
left: 0;
z-index: 1000;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal {
position: fixed;
z-index: 1001;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 30vw;
min-height: 30vh;
background-color: $bg-color;
box-shadow: 30px 30px 0 0 black;
display: flex;
justify-content: center;
align-items: center;
.modal-content {
font-size: 1.6rem;
}
}
button {
position: absolute;
top: 20px;
right: 20px;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
span {
font-size: 1.5rem;
color: $fg-color;
}
}
</style>

43
src/lib/api.js Normal file
View File

@ -0,0 +1,43 @@
export async function signup(email, password) {
const apiUrl = import.meta.env.VITE_API_URL;
const response = await fetch(apiUrl + '/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (!response.ok || data.error) {
throw new Error(data.error || `Signup failed with status ${response.status}`);
}
return data;
}
export async function login(email, password) {
const apiUrl = import.meta.env.VITE_API_URL;
const response = await fetch(apiUrl + '/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password
})
});
const data = await response.json();
if (!response.ok || data.error) {
throw new Error(data.error || `Login failed with status ${response.status}`);
}
// Here you could do something with the login response, like storing a user token
return data;
}

8
src/lib/utils.js Normal file
View File

@ -0,0 +1,8 @@
export function isValidEmail(email) {
return /\S+@\S+\.\S+/.test(email);
}
export function isValidPassword(password) {
return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$?@!_%-])[A-Za-z\d$?@!_%-]{8,}$/.test(password);
}

View File

@ -0,0 +1,6 @@
<script>
import "../styles/master.scss";
import 'normalize.css';
</script>
<slot></slot>

View File

@ -1,9 +1,13 @@
<svelte:head>
<title>Home</title>
</svelte:head>
<script>
let text = '';
const apiUrl = import.meta.env.VITE_API_URL;
async function createNote() {
const response = await fetch('https://api.brz9.dev/notes', {
const response = await fetch(apiUrl + '/notes', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
@ -24,7 +28,7 @@
let notes = [];
async function fetchNotes() {
const response = await fetch('https://api.brz9.dev/getnotes');
const response = await fetch(apiUrl + '/getnotes');
if (response.ok) {
notes = await response.json();
@ -32,19 +36,18 @@
console.error('Failed to fetch notes');
}
}
// Fetch notes when the component is first rendered
fetchNotes();
</script>
<main>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
<ul>
<li><a href="/about">About</a></li>
<li><a href="/login">Login</a></li>
<li><a href="/signup">Signup</a></li>
</ul>
<input bind:value={text} type="text" placeholder="Enter note text" />
@ -58,4 +61,6 @@
{/each}
</ul>
<h4>Just to check, the current API endpoint is : {apiUrl}</h4>
<h4>Just to check, the current API endpoint is : {apiUrl}</h4>
</main>

View File

@ -2,4 +2,29 @@
<title>Login</title>
</svelte:head>
<h1>Login page</h1>
<script>
import { login } from '$lib/api';
let email = '';
let password = '';
async function handleLogin() {
try {
const user = await login(email, password);
alert('Login successful');
} catch (err) {
alert('Login failed because of : ' + err);
}
}
</script>
<main>
<form class="colonel">
<input type="email" placeholder="Email" bind:value={email} required>
<input type="password" placeholder="Password" bind:value={password} required>
<button class="btn-fly" on:click={handleLogin}>Log in</button>
</form>
</main>

View File

@ -0,0 +1,56 @@
<svelte:head>
<title>Sign Up</title>
</svelte:head>
<script>
import { signup } from '$lib/api';
import { isValidEmail, isValidPassword } from '$lib/utils';
import Modal from '$components/Modal.svelte';
let showModal = true;
let modalMessage = 'Test message';
let email = '';
let password = '';
async function handleSignup() {
try {
const user = await signup(email, password);
alert('Signup successful');
} catch (err) {
alert('Signup failed because of : ' + err);
}
}
async function handleSubmit(event) {
event.preventDefault(); // prevent the form from refreshing the page
await handleSignup();
}
function closeModal() {
showModal = false;
}
</script>
<main>
<form class="colonel" on:submit={handleSubmit}>
<input
type="email"
bind:value={email}
placeholder="Email"
class:valid={isValidEmail(email)}
>
<input
type="password"
bind:value={password}
placeholder="Pas$w0rd"
class:valid={isValidPassword(password)}
>
<button type="submit" class="btn-fly" on:click={handleSignup}>Sign Up</button>
</form>
{#if showModal}
<Modal {modalMessage} on:close={closeModal} />
{/if}
</main>

11
src/styles/color.scss Normal file
View File

@ -0,0 +1,11 @@
html {
background-color: $bg-color;
color: $fg-color;
}
a {
color: $fg-color;
&:hover {
color: $red;
}
}

3
src/styles/fonts.scss Normal file
View File

@ -0,0 +1,3 @@
html {
font-family: Inter;
}

34
src/styles/forms.scss Normal file
View File

@ -0,0 +1,34 @@
.btn-fly {
background-color: $fg-color;
color: $bg-color;
border: none;
border-radius: 0;
font-size: 1.2rem;
font-weight: 600;
padding: 15px;
box-shadow: 15px 15px 0px 0px black;
cursor: pointer;
&:hover {
box-shadow: 17px 17px 0px 0px black;
}
}
input[type=text], input[type=password], input[type=email], input[type=number], input[type=date], select {
padding: 12px 0px;
margin: 8px 0;
box-sizing: border-box;
border: none;
border-bottom: 5px solid $fg-color;
background-color: $bg-color;
color: $fg-color;
font-size: 1.2rem;
font-weight: 400;
&:focus {
outline: none;
border-bottom: 5px solid $red;
}
&.valid {
border-bottom: 5px solid $fg-color;
}
}

46
src/styles/layout.scss Normal file
View File

@ -0,0 +1,46 @@
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.row {
width: 100%;
display: flex;
justify-content: space-between;
}
.column {
flex: 1;
padding: 1em;
}
.column.half {
flex: 0.5;
}
.column.third {
flex: 0.333;
}
.column.quarter {
flex: 0.25;
}
.centered-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; // this makes the container take up the full viewport height
}
.colonel {
margin: 50px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
*{
margin-top: 50px;
}
}

6
src/styles/master.scss Normal file
View File

@ -0,0 +1,6 @@
@import 'variables';
@import 'color';
@import 'fonts';
@import 'layout';
@import 'responsive';
@import 'forms';

View File

@ -0,0 +1,38 @@
@mixin respond-to($breakpoint) {
@if $breakpoint == small {
@media (max-width: 600px) {
@content;
}
}
@if $breakpoint == medium {
@media (max-width: 900px) {
@content;
}
}
@if $breakpoint == large {
@media (min-width: 900px) {
@content;
}
}
}
main {
@include respond-to(small) {
padding-left: 5vw;
padding-right: 5vw;
}
@include respond-to(medium) {
padding-left: 10vw;
padding-right: 10vw;
}
@include respond-to(large) {
padding-left: 20vw;
padding-right: 20vw;
}
}

View File

@ -0,0 +1,4 @@
$bg-color : #1C3137;
$fg-color : #F2DFD0;
$red: #C62F00;
$green: #0A9C25;

View File

@ -1,7 +1,12 @@
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';
export default {
kit: {
adapter: adapter()
}
adapter: adapter(),
alias: {
$components: 'src/components',
}
},
preprocess: [vitePreprocess()],
};