Daniel Bohry 9 miesięcy temu
rodzic
commit
51548519ae

+ 3 - 6
src/app.css

@@ -1,7 +1,7 @@
 @import '@fontsource/fira-mono';
 
 :root {
-	--font-body: "Roboto", Arial, AppleGothic, serif;
+	--font-body: 'Roboto', Arial, AppleGothic, serif;
 	--font-mono: 'Fira Mono', monospace;
 	--color-bg-0: rgb(202, 216, 228);
 	--color-bg-1: hsl(209, 36%, 86%);
@@ -21,11 +21,8 @@ body {
 	background-attachment: fixed;
 	background-color: var(--color-bg-1);
 	background-size: 100vw 100vh;
-	background-image: radial-gradient(
-			50% 50% at 50% 50%,
-			rgba(255, 255, 255, 0.75) 0%,
-			rgba(255, 255, 255, 0) 100%
-		),
+	background-image:
+		radial-gradient(50% 50% at 50% 50%, rgba(255, 255, 255, 0.75) 0%, rgba(255, 255, 255, 0) 100%),
 		linear-gradient(180deg, var(--color-bg-0) 0%, var(--color-bg-1) 15%, var(--color-bg-2) 50%);
 }
 

+ 4 - 1
src/app.html

@@ -3,7 +3,10 @@
 	<head>
 		<meta charset="utf-8" />
 		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
-		<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
+		<link
+			href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
+			rel="stylesheet"
+		/>
 		<link rel="stylesheet" href="./css/main.css" />
 		<link rel="stylesheet" href="./css/form.css" />
 		<meta name="viewport" content="width=device-width, initial-scale=1" />

+ 29 - 16
src/components/Chart.svelte

@@ -10,22 +10,36 @@
 		Chart.register(ArcElement, Tooltip, Legend, Title, DoughnutController);
 
 		if (data && data.stocks) {
-			const stockNames = data.stocks.map(stock => stock.name);
-			const stockTotals = data.stocks.map(stock => stock.total);
+			const stockNames = data.stocks.map((stock) => stock.name);
+			const stockTotals = data.stocks.map((stock) => stock.total);
 
 			const chartData = {
 				labels: stockNames,
-				datasets: [{
-					label: 'Stock Distribution',
-					data: stockTotals,
-					backgroundColor: [
-						'#FF6F61', '#6B8E23', '#FFD700', '#20B2AA', '#87CEFA',
-						'#D2691E', '#FF6347', '#98FB98', '#D8BFD8', '#20B2AA',
-						'#FF4500', '#8A2BE2', '#A52A2A', '#DEB887', '#5F9EA0'
-					],
-					borderColor: '#fff',
-					borderWidth: 1
-				}]
+				datasets: [
+					{
+						label: 'Stock Distribution',
+						data: stockTotals,
+						backgroundColor: [
+							'#FF6F61',
+							'#6B8E23',
+							'#FFD700',
+							'#20B2AA',
+							'#87CEFA',
+							'#D2691E',
+							'#FF6347',
+							'#98FB98',
+							'#D8BFD8',
+							'#20B2AA',
+							'#FF4500',
+							'#8A2BE2',
+							'#A52A2A',
+							'#DEB887',
+							'#5F9EA0'
+						],
+						borderColor: '#fff',
+						borderWidth: 1
+					}
+				]
 			};
 
 			const chartOptions = {
@@ -36,7 +50,7 @@
 					},
 					tooltip: {
 						callbacks: {
-							label: function(tooltipItem) {
+							label: function (tooltipItem) {
 								return `${tooltipItem.label}: $${tooltipItem.raw.toFixed(2)}`;
 							}
 						}
@@ -57,7 +71,6 @@
 	{#if data.stocks.length > 0}
 		<canvas bind:this={chartContainer}></canvas>
 	{:else}
-			<p>No insights available.</p>
+		<p>No insights available.</p>
 	{/if}
-
 </div>

+ 142 - 143
src/components/Header.svelte

@@ -1,151 +1,150 @@
 <script>
-    import {page} from '$app/stores';
-    import profile from '$lib/images/profile.png';
-    import {authentication} from "../routes/store.js";
-    import {onMount} from "svelte";
-
-    let username = undefined;
-    let profileTitle = undefined;
-
-    const unsubscribe = authentication.subscribe(value => {
-        username = value ? value.username : "";
-        profileTitle = value ? `You are logged in as ${value.username}` : "Login";
-    });
-
-    onMount(() => {
-        const storedAuth = localStorage.getItem('authentication');
-        if (storedAuth) {
-            try {
-                authentication.set(JSON.parse(storedAuth));
-            } catch (e) {
-                console.error("Failed to parse auth from localStorage", e);
-            }
-        }
-
-        return () => {
-            unsubscribe();
-        };
-    });
-
+	import { page } from '$app/stores';
+	import profile from '$lib/images/profile.png';
+	import { authentication } from '../routes/store.js';
+	import { onMount } from 'svelte';
+
+	let username = undefined;
+	let profileTitle = undefined;
+
+	const unsubscribe = authentication.subscribe((value) => {
+		username = value ? value.username : '';
+		profileTitle = value ? `You are logged in as ${value.username}` : 'Login';
+	});
+
+	onMount(() => {
+		const storedAuth = localStorage.getItem('authentication');
+		if (storedAuth) {
+			try {
+				authentication.set(JSON.parse(storedAuth));
+			} catch (e) {
+				console.error('Failed to parse auth from localStorage', e);
+			}
+		}
+
+		return () => {
+			unsubscribe();
+		};
+	});
 </script>
 
 <header>
-    <div class="corner">
-        <!-- logo -->
-    </div>
-
-    <nav>
-        <ul>
-            <li aria-current={$page.url.pathname === '/' ? 'page' : undefined}>
-                <a href="/static">Home</a>
-            </li>
-            {#if username !== ""}
-                <li aria-current={$page.url.pathname === '/stocks' ? 'page' : undefined}>
-                    <a href="/stocks">Stocks</a>
-                </li>
-                <li aria-current={$page.url.pathname === '/portfolio' ? 'page' : undefined}>
-                    <a href="/portfolio">Portfolio</a>
-                </li>
-                <li aria-current={$page.url.pathname === '/insights' ? 'page' : undefined}>
-                    <a href="/insights">Insights</a>
-                </li>
-            {/if}
-            <li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
-                <a href="/about">About</a>
-            </li>
-        </ul>
-    </nav>
-
-    <div class="corner">
-        <div class="login-message">{username}</div>
-        <a href="/login">
-            <img src={profile} alt="Profile" style="width: 16px; height: 16px;" title="{profileTitle}"/>
-        </a>
-    </div>
+	<div class="corner">
+		<!-- logo -->
+	</div>
+
+	<nav>
+		<ul>
+			<li aria-current={$page.url.pathname === '/' ? 'page' : undefined}>
+				<a href="/">Home</a>
+			</li>
+			{#if username !== ''}
+				<li aria-current={$page.url.pathname === '/stocks' ? 'page' : undefined}>
+					<a href="/stocks">Stocks</a>
+				</li>
+				<li aria-current={$page.url.pathname === '/portfolio' ? 'page' : undefined}>
+					<a href="/portfolio">Portfolio</a>
+				</li>
+				<li aria-current={$page.url.pathname === '/insights' ? 'page' : undefined}>
+					<a href="/insights">Insights</a>
+				</li>
+			{/if}
+			<li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
+				<a href="/about">About</a>
+			</li>
+		</ul>
+	</nav>
+
+	<div class="corner">
+		<div class="login-message">{username}</div>
+		<a href="/login">
+			<img src={profile} alt="Profile" style="width: 16px; height: 16px;" title={profileTitle} />
+		</a>
+	</div>
 </header>
 
 <style>
-    header {
-        display: flex;
-        justify-content: space-between;
-        background-color: #a5b1c2;
-        width: 100%;
-    }
-
-    .corner {
-        padding-right: 1em;
-        height: 3em;
-        display: flex; /* Enable flexbox layout */
-        align-items: center; /* Center items vertically */
-    }
-
-    .login-message {
-        margin-right: 8px; /* Add some space between the message and the profile image */
-        color: var(--color-text); /* Ensure the text color is set */
-    }
-
-    .corner a {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        width: 100%;
-        height: 100%;
-    }
-
-    .corner img {
-        width: 2em;
-        height: 2em;
-        object-fit: contain;
-    }
-
-    nav {
-        flex-grow: 1;
-        justify-content: flex-start; /* Aligns the menu to the left */
-    }
-
-    ul {
-        padding: 0;
-        margin: 0;
-        height: 3em;
-        display: flex;
-        align-items: center;
-        list-style: none;
-        background: var(--background);
-        background-size: contain;
-    }
-
-    li {
-        position: relative;
-        height: 100%;
-    }
-
-    li[aria-current='page']::before {
-        --size: 6px;
-        content: '';
-        width: 0;
-        height: 0;
-        position: absolute;
-        top: 0;
-        left: calc(50% - var(--size));
-        border: var(--size) solid transparent;
-        border-top: var(--size) solid var(--color-theme-1);
-    }
-
-    nav a {
-        display: flex;
-        height: 100%;
-        align-items: center;
-        padding: 0 0.5rem;
-        color: var(--color-text);
-        font-weight: 700;
-        font-size: 0.8rem;
-        text-transform: uppercase;
-        letter-spacing: 0.1em;
-        text-decoration: none;
-        transition: color 0.2s linear;
-    }
-
-    a:hover {
-        color: var(--color-theme-1);
-    }
+	header {
+		display: flex;
+		justify-content: space-between;
+		background-color: #a5b1c2;
+		width: 100%;
+	}
+
+	.corner {
+		padding-right: 1em;
+		height: 3em;
+		display: flex; /* Enable flexbox layout */
+		align-items: center; /* Center items vertically */
+	}
+
+	.login-message {
+		margin-right: 8px; /* Add some space between the message and the profile image */
+		color: var(--color-text); /* Ensure the text color is set */
+	}
+
+	.corner a {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		width: 100%;
+		height: 100%;
+	}
+
+	.corner img {
+		width: 2em;
+		height: 2em;
+		object-fit: contain;
+	}
+
+	nav {
+		flex-grow: 1;
+		justify-content: flex-start; /* Aligns the menu to the left */
+	}
+
+	ul {
+		padding: 0;
+		margin: 0;
+		height: 3em;
+		display: flex;
+		align-items: center;
+		list-style: none;
+		background: var(--background);
+		background-size: contain;
+	}
+
+	li {
+		position: relative;
+		height: 100%;
+	}
+
+	li[aria-current='page']::before {
+		--size: 6px;
+		content: '';
+		width: 0;
+		height: 0;
+		position: absolute;
+		top: 0;
+		left: calc(50% - var(--size));
+		border: var(--size) solid transparent;
+		border-top: var(--size) solid var(--color-theme-1);
+	}
+
+	nav a {
+		display: flex;
+		height: 100%;
+		align-items: center;
+		padding: 0 0.5rem;
+		color: var(--color-text);
+		font-weight: 700;
+		font-size: 0.8rem;
+		text-transform: uppercase;
+		letter-spacing: 0.1em;
+		text-decoration: none;
+		transition: color 0.2s linear;
+	}
+
+	a:hover {
+		color: var(--color-theme-1);
+	}
 </style>

+ 0 - 1
src/routes/+layout.svelte

@@ -3,7 +3,6 @@
 	import '../app.css';
 
 	let year = new Date().getFullYear();
-
 </script>
 
 <div class="app">

+ 4 - 4
src/routes/+page.svelte

@@ -9,7 +9,7 @@
 
 <section>
 	<div id="content">
-		<img id="bounce-image" src="{logo}" alt="OQuokka">
+		<img id="bounce-image" src={logo} alt="OQuokka" />
 	</div>
 </section>
 
@@ -32,12 +32,12 @@
 	}
 
 	@keyframes bounce {
-		0%, 100% {
+		0%,
+		100% {
 			transform: translateY(0);
 		}
 		50% {
 			transform: translateY(-50px);
 		}
 	}
-
-</style>
+</style>

+ 83 - 85
src/routes/login/+page.svelte

@@ -1,103 +1,101 @@
 <script>
-    import {onMount} from 'svelte';
-    import {authentication} from '../store.js';
+	import { onMount } from 'svelte';
+	import { authentication } from '../store.js';
 
-    let isAuthenticated = false;
-    let isLoading = true;
-    let user = null;
+	let isAuthenticated = false;
+	let isLoading = true;
+	let user = null;
 
-    $: authentication.subscribe(value => {
-        isAuthenticated = !!value;
-        if (value) {
-            user = value;
-        }
-    });
+	$: authentication.subscribe((value) => {
+		isAuthenticated = !!value;
+		if (value) {
+			user = value;
+		}
+	});
 
-    onMount(() => {
-        try {
-            const storedAuth = localStorage.getItem('authentication');
-            if (storedAuth) {
-                authentication.set(JSON.parse(storedAuth));
-            }
-        } catch (error) {
-            console.error('Error parsing stored auth:', error);
-        } finally {
-            isLoading = false;
-        }
-    });
+	onMount(() => {
+		try {
+			const storedAuth = localStorage.getItem('authentication');
+			if (storedAuth) {
+				authentication.set(JSON.parse(storedAuth));
+			}
+		} catch (error) {
+			console.error('Error parsing stored auth:', error);
+		} finally {
+			isLoading = false;
+		}
+	});
 
-    async function submit(event) {
-        event.preventDefault();
+	async function submit(event) {
+		event.preventDefault();
 
-        const formData = new FormData(event.target);
-        const username = formData.get("username");
-        const password = formData.get("password");
+		const formData = new FormData(event.target);
+		const username = formData.get('username');
+		const password = formData.get('password');
 
-        if (!username || !password) {
-            alert("Please enter both username and password.");
-            return;
-        }
+		if (!username || !password) {
+			alert('Please enter both username and password.');
+			return;
+		}
 
-        const data = {
-            username: username,
-            password: password
-        };
+		const data = {
+			username: username,
+			password: password
+		};
 
-        try {
-            const response = await fetch(import.meta.env.VITE_AUTH_HOST + '/api/authenticate', {
-                method: 'POST',
-                headers: {
-                    'Content-Type': 'application/json',
-                },
-                body: JSON.stringify(data),
-            });
+		try {
+			const response = await fetch(import.meta.env.VITE_AUTH_HOST + '/api/authenticate', {
+				method: 'POST',
+				headers: {
+					'Content-Type': 'application/json'
+				},
+				body: JSON.stringify(data)
+			});
 
-            if (response.ok) {
-                const result = await response.json();
-                authentication.set(result);
-                localStorage.setItem('authentication', JSON.stringify(result));
-            } else {
-                const error = await response.json();
-                console.error('Login failed:', error);
-                alert('Login failed: ' + error.message);
-            }
-        } catch (err) {
-            console.error('Error during login:', err);
-            alert('An error occurred. Please try again.');
-        }
-    }
+			if (response.ok) {
+				const result = await response.json();
+				authentication.set(result);
+				localStorage.setItem('authentication', JSON.stringify(result));
+			} else {
+				const error = await response.json();
+				console.error('Login failed:', error);
+				alert('Login failed: ' + error.message);
+			}
+		} catch (err) {
+			console.error('Error during login:', err);
+			alert('An error occurred. Please try again.');
+		}
+	}
 
-    function logout() {
-        window.location.href = "/logout";
-    }
-
-    function navigateToRegister() {
-        window.location.href = "/register";
-    }
+	function logout() {
+		window.location.href = '/logout';
+	}
 
+	function navigateToRegister() {
+		window.location.href = '/register';
+	}
 </script>
 
 <svelte:head>
-    <title>Login</title>
-    <meta name="description" content="Login page"/>
+	<title>Login</title>
+	<meta name="description" content="Login page" />
 </svelte:head>
 
 <div class="text-column">
-    {#if isLoading}
-        <p>Loading...</p>
-    {:else}
-        {#if !isAuthenticated}
-            <div class="card">
-                <form on:submit={submit}>
-                    <input type="text" name="username" placeholder="username" class="input-field"/>
-                    <input type="password" name="password" placeholder="password" class="input-field"/>
-                    <button type="submit" class="add-button">Login</button>
-                    <button type="button" class="register-button" on:click={navigateToRegister}>Register</button>
-                </form>
-            </div>
-        {:else}
-            <p>You are logged in as {user.username}!</p>
-            <button class="logout-button" on:click={logout}>Logout</button>
-        {/if}
-    {/if}
-</div>
+	{#if isLoading}
+		<p>Loading...</p>
+	{:else if !isAuthenticated}
+		<div class="card">
+			<form on:submit={submit}>
+				<input type="text" name="username" placeholder="username" class="input-field" />
+				<input type="password" name="password" placeholder="password" class="input-field" />
+				<button type="submit" class="add-button">Login</button>
+				<button type="button" class="register-button" on:click={navigateToRegister}>Register</button
+				>
+			</form>
+		</div>
+	{:else}
+		<p>You are logged in as {user.username}!</p>
+		<button class="logout-button" on:click={logout}>Logout</button>
+	{/if}
+</div>

+ 15 - 15
src/routes/logout/+page.svelte

@@ -1,25 +1,25 @@
 <script>
-    import {onMount} from "svelte";
-    import {authentication} from '../store.js';
+	import { onMount } from 'svelte';
+	import { authentication } from '../store.js';
 
-    function logout() {
-        localStorage.removeItem('authentication');
-        authentication.set(null);
-        localStorage.clear();
-        window.location.href = "/login";
-    }
+	function logout() {
+		localStorage.removeItem('authentication');
+		authentication.set(null);
+		localStorage.clear();
+		window.location.href = '/login';
+	}
 
-    onMount(() => {
-        logout();
-    });
+	onMount(() => {
+		logout();
+	});
 </script>
 
 <svelte:head>
-    <title>Logout</title>
-    <meta name="description" content="Logout page"/>
+	<title>Logout</title>
+	<meta name="description" content="Logout page" />
 </svelte:head>
 
 <div class="text-column">
-    <p>Logging you out...</p>
-    <p>Please wait...</p>
+	<p>Logging you out...</p>
+	<p>Please wait...</p>
 </div>

+ 388 - 366
src/routes/portfolio/+page.svelte

@@ -14,7 +14,7 @@
 	let orderBy = 'total';
 
 	onMount(() => {
-		const unsubscribe = authentication.subscribe(value => {
+		const unsubscribe = authentication.subscribe((value) => {
 			if (value?.token) {
 				authToken = value.token;
 				fetchPortfolio();
@@ -26,15 +26,12 @@
 
 	async function fetchPortfolio() {
 		try {
-			const response = await fetch(
-				`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios`,
-				{
-					method: 'GET',
-					headers: {
-						Authorization: 'Bearer ' + authToken
-					}
+			const response = await fetch(`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios`, {
+				method: 'GET',
+				headers: {
+					Authorization: 'Bearer ' + authToken
 				}
-			);
+			});
 
 			if (response.ok) {
 				await update(response.json());
@@ -97,14 +94,17 @@
 
 	async function updatePortfolio(stocks) {
 		try {
-			const response = await fetch(`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios/${portfolioId}`, {
-				method: 'PUT',
-				headers: {
-					Authorization: 'Bearer ' + authToken,
-					'Content-Type': 'application/json'
-				},
-				body: JSON.stringify({ stocks })
-			});
+			const response = await fetch(
+				`${import.meta.env.VITE_STOCKS_HOST}/api/portfolios/${portfolioId}`,
+				{
+					method: 'PUT',
+					headers: {
+						Authorization: 'Bearer ' + authToken,
+						'Content-Type': 'application/json'
+					},
+					body: JSON.stringify({ stocks })
+				}
+			);
 
 			if (response.status === 400) {
 				alert('Bad request. Invalid code.');
@@ -140,7 +140,7 @@
 		}
 
 		searchStockResult = data;
-		const alreadyInPortfolio = result.some(s => s.code === data[0]?.code);
+		const alreadyInPortfolio = result.some((s) => s.code === data[0]?.code);
 
 		if (data.length === 1 && !alreadyInPortfolio) {
 			await addSelectedStock(data[0]);
@@ -149,7 +149,7 @@
 	}
 
 	async function addSelectedStock(newStock) {
-		const exists = result.some(stock => stock.code === newStock.code);
+		const exists = result.some((stock) => stock.code === newStock.code);
 		if (exists) return;
 
 		result = [
@@ -170,7 +170,7 @@
 	}
 
 	function remove(code) {
-		result = result.filter(stock => stock.code !== code);
+		result = result.filter((stock) => stock.code !== code);
 		updatePortfolio(result);
 	}
 
@@ -191,9 +191,7 @@
 		const code = form.get('code');
 		const quantity = parseInt(form.get('quantity')) || 0;
 
-		result = result.map(stock =>
-			stock.code === code ? { ...stock, quantity } : stock
-		);
+		result = result.map((stock) => (stock.code === code ? { ...stock, quantity } : stock));
 
 		updatePortfolio(result);
 	}
@@ -215,9 +213,7 @@
 		const quantity = parseInt(form.get('quantity')) || 0;
 
 		// Update the stock array with the new quantity
-		result = result.map(stock =>
-			stock.code === code ? { ...stock, quantity } : stock
-		);
+		result = result.map((stock) => (stock.code === code ? { ...stock, quantity } : stock));
 
 		// Manually trigger form submission
 		event.target.form.requestSubmit();
@@ -233,7 +229,12 @@
 	<div in:fade>Loading...</div>
 {:else if portfolioId}
 	<div class="button-container">
-		<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#exampleModal" on:click={closeOrOpenModal}>
+		<button
+			class="btn btn-primary btn-sm"
+			data-toggle="modal"
+			data-target="#exampleModal"
+			on:click={closeOrOpenModal}
+		>
 			Add
 		</button>
 
@@ -251,13 +252,23 @@
 				<form on:submit|preventDefault={handleSubmit}>
 					<div class="row">
 						<div class="col">
-							<input type="text" class="form-control" placeholder="stock code or name"
-										 name="stock_code"
-										 oninput="this.value = this.value.toUpperCase()"
-										 autocomplete="off" autofocus>
+							<input
+								type="text"
+								class="form-control"
+								placeholder="stock code or name"
+								name="stock_code"
+								oninput="this.value = this.value.toUpperCase()"
+								autocomplete="off"
+								autofocus
+							/>
 						</div>
 						<div class="col">
-							<input type="reset" value="cancel" class="btn btn-danger" on:click={closeOrOpenModal} />
+							<input
+								type="reset"
+								value="cancel"
+								class="btn btn-danger"
+								on:click={closeOrOpenModal}
+							/>
 							<input type="submit" value="search" class="btn btn-primary" />
 						</div>
 					</div>
@@ -268,8 +279,10 @@
 						<div class="card" style="width: 100%;">
 							<ul class="list-group list-group-flush">
 								{#each searchStockResult as result}
-									<li class="list-group-item d-flex justify-content-between align-items-center"
-											on:click={addSelectedStock(result)}>
+									<li
+										class="list-group-item d-flex justify-content-between align-items-center"
+										on:click={addSelectedStock(result)}
+									>
 										({result.code}) {result.name}
 										<button class="btn btn-primary btn-sm">+</button>
 									</li>
@@ -285,16 +298,16 @@
 	<div in:fade class="table-container">
 		<table class="stock-table">
 			<thead>
-			<tr>
-				<th>Total Value</th>
-				<th>Total Assets</th>
-			</tr>
+				<tr>
+					<th>Total Value</th>
+					<th>Total Assets</th>
+				</tr>
 			</thead>
 			<tbody>
-			<tr>
-				<td class="code">{formatCurrency(totalValue)}</td>
-				<td class="code">{totalAssets}</td>
-			</tr>
+				<tr>
+					<td class="code">{formatCurrency(totalValue)}</td>
+					<td class="code">{totalAssets}</td>
+				</tr>
 			</tbody>
 		</table>
 	</div>
@@ -302,36 +315,42 @@
 	<div in:fade class="table-container">
 		<table class="stock-table">
 			<thead>
-			<tr>
-				<th>Code</th>
-				<th>Name</th>
-				<th>Qty</th>
-				<th>Price</th>
-				<th>Total</th>
-				<th>% of Portfolio</th>
-				<th scope="col"></th>
-			</tr>
-			</thead>
-			<tbody>
-			{#each result as stock}
 				<tr>
-					<td class="code">{stock.code}</td>
-					<td class="name">{stock.name}</td>
-					<td class="qty-edit">
-						<form id="updateQuantity" on:submit|preventDefault={updateStockQuantity}>
-							<input type="hidden" name="code" value="{stock.code}" />
-							<input type="number" class="qty-input" name="quantity" value="{stock.quantity}"
-										 on:input={handleInputChange} />
-						</form>
-					</td>
-					<td class="price">{formatCurrency(stock.price)}</td>
-					<td class="total">{formatCurrency(stock.total)}</td>
-					<td class="percent">{calculatePercentage(stock.total, totalValue)}%</td>
-					<td>
-						<button class="remove-btn" on:click={() => remove(stock.code)} title="remove"></button>
-					</td>
+					<th>Code</th>
+					<th>Name</th>
+					<th>Qty</th>
+					<th>Price</th>
+					<th>Total</th>
+					<th>% of Portfolio</th>
+					<th scope="col"></th>
 				</tr>
-			{/each}
+			</thead>
+			<tbody>
+				{#each result as stock}
+					<tr>
+						<td class="code">{stock.code}</td>
+						<td class="name">{stock.name}</td>
+						<td class="qty-edit">
+							<form id="updateQuantity" on:submit|preventDefault={updateStockQuantity}>
+								<input type="hidden" name="code" value={stock.code} />
+								<input
+									type="number"
+									class="qty-input"
+									name="quantity"
+									value={stock.quantity}
+									on:input={handleInputChange}
+								/>
+							</form>
+						</td>
+						<td class="price">{formatCurrency(stock.price)}</td>
+						<td class="total">{formatCurrency(stock.total)}</td>
+						<td class="percent">{calculatePercentage(stock.total, totalValue)}%</td>
+						<td>
+							<button class="remove-btn" on:click={() => remove(stock.code)} title="remove"
+							></button>
+						</td>
+					</tr>
+				{/each}
 			</tbody>
 		</table>
 	</div>
@@ -339,301 +358,304 @@
 	<div>No portfolio data available.</div>
 {/if}
 
-
 <style>
-    /* General Styles for Table (Unchanged) */
-    .table-container {
-        margin-top: 2rem;
-        overflow-x: auto;
-        border-radius: 12px;
-        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
-    }
-
-    .stock-table {
-        width: 100%;
-        border-collapse: collapse;
-        font-family: system-ui, sans-serif;
-        background-color: #fff;
-        border-radius: 12px;
-        overflow: hidden;
-        min-width: 600px;
-    }
-
-    th, td {
-        padding: 1rem 1.25rem;
-        text-align: left;
-        white-space: nowrap;
-    }
-
-    thead {
-        background-color: #f7f7f7;
-        border-bottom: 2px solid #e0e0e0;
-    }
-
-    th {
-        font-weight: 600;
-        font-size: 0.95rem;
-        color: #333;
-    }
-
-    tbody tr:nth-child(odd) {
-        background-color: #fafafa;
-    }
-
-    tbody tr:nth-child(even) {
-        background-color: #f0f4f8;
-    }
-
-    tbody tr:hover {
-        background-color: #e1ecf4;
-    }
-
-    td {
-        font-size: 0.95rem;
-        color: #555;
-        border-bottom: 1px solid #eee;
-    }
-
-    .code {
-        font-weight: 600;
-        color: #2c3e50;
-    }
-
-    .name {
-        color: #7f8c8d;
-    }
-
-    .qty-edit {
-        display: flex;
-        align-items: center;
-        gap: 0.5rem;
-    }
-
-    .qty-input {
-        width: 60px;
-        padding: 0.4rem 0.5rem;
-        font-size: 0.9rem;
-        border: 1px solid #ccc;
-        border-radius: 6px;
-        text-align: right;
-        background-color: #fff;
-        color: #333;
-        transition: border-color 0.2s ease;
-    }
-
-    .qty-input:focus {
-        outline: none;
-        border-color: #2980b9;
-    }
-
-    .remove-btn {
-        height: 15px;
-        width: 15px;
-        background-color: #e74c3c;
-        border-radius: 50%;
-        display: inline-block;
-        border: 0;
-    }
-
-    .price {
-        color: #27ae60;
-        font-weight: bold;
-    }
-
-    .total {
-        font-weight: 500;
-        color: #34495e;
-    }
-
-    .percent {
-        color: #2980b9;
-    }
-
-    /* Responsive design */
-    @media (max-width: 768px) {
-        .modal-content {
-            width: 90%;
-            padding: 1.5rem;
-        }
-
-        input[type="text"],
-        input[type="number"] {
-            font-size: 0.9rem;
-        }
-
-        .modal-result {
-            max-height: 200px;
-        }
-
-        .list-group-item {
-            font-size: 0.9rem;
-        }
-    }
-
-    @media (max-width: 768px) {
-        .stock-table {
-            font-size: 0.875rem;
-        }
-
-        th, td {
-            padding: 0.75rem 1rem;
-        }
-    }
-
-    /* Modal Styling */
-    .modal-container {
-        position: fixed;
-        top: 20%;
-        left: 0;
-        right: 0;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        z-index: 9999;
-        animation: fadeIn 0.3s ease;
-    }
-
-    /* Modal content styling */
-    .modal-content {
-        background-color: #fff;
-        color: #333;
-        width: 450px;
-        height: auto;
-        max-width: 500px;
-        border-radius: 10px;
-        padding: 2rem;
-        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
-        transition: transform 0.3s ease-in-out;
-    }
-
-    /* Button container for Add and Dropdown */
-    .button-container {
-        display: flex;
-        gap: 10px;
-        margin-bottom: 1rem;
-        align-items: center;
-    }
-
-    .order-select {
-        width: 200px;
-        padding: 0.5rem;
-        border-radius: 8px;
-        border: 1px solid #ddd;
-        font-size: 1rem;
-        background-color: #f9f9f9;
-        transition: border-color 0.3s ease;
-    }
-
-    .order-select:focus {
-        border-color: #2980b9;
-        outline: none;
-    }
-
-    /* Input Fields (Stock code and search) */
-    input[type="text"], input[type="number"] {
-        width: 100%;
-        padding: 0.8rem;
-        font-size: 1rem;
-        border-radius: 8px;
-        border: 1px solid #ddd;
-        margin-bottom: 10px;
-        background-color: #f9f9f9;
-        color: #333;
-        transition: border-color 0.3s ease;
-    }
-
-    input[type="text"]:focus, input[type="number"]:focus {
-        border-color: #2980b9;
-        outline: none;
-    }
-
-    /* Button styles */
-    .btn {
-        padding: 0.6rem 1.2rem;
-        font-size: 1rem;
-        border-radius: 8px;
-        border: none;
-        cursor: pointer;
-        transition: background-color 0.3s ease;
-    }
-
-    .btn-primary {
-        background-color: #2980b9;
-        color: white;
-    }
-
-    .btn-primary:hover {
-        background-color: #3498db;
-    }
-
-    .btn-danger {
-        background-color: #e74c3c;
-        color: white;
-    }
-
-    .btn-danger:hover {
-        background-color: #c0392b;
-    }
-
-    /* Reset Button (Modal) */
-    input[type="reset"] {
-        background-color: #e74c3c;
-        color: white;
-        font-size: 1rem;
-        padding: 0.6rem 1.2rem;
-        border-radius: 8px;
-        cursor: pointer;
-        border: none;
-    }
-
-    /* Modal result items */
-    .modal-result {
-        max-width: 100%;
-        max-height: 300px;
-        overflow-y: auto;
-        padding: 0.8rem;
-        background-color: #fafafa;
-        border-radius: 10px;
-        margin-top: 1rem;
-    }
-
-    .list-group-item {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        padding: 10px;
-        border: 1px solid #ddd;
-        margin-bottom: 0.5rem;
-        border-radius: 8px;
-        background-color: #f9f9f9;
-        transition: background-color 0.3s ease;
-    }
-
-    .list-group-item:hover {
-        background-color: #f1f1f1;
-    }
-
-    .list-group-item .btn-primary {
-        background-color: #2980b9;
-        color: white;
-        border-radius: 50%;
-        height: 30px;
-        width: 30px;
-        padding: 0;
-        border: none;
-    }
-
-    .list-group-item .btn-primary:hover {
-        background-color: #3498db;
-    }
-
-    /* Modal transition */
-    @keyframes fadeIn {
-        from {
-            opacity: 0;
-        }
-        to {
-            opacity: 1;
-        }
-    }
+	/* General Styles for Table (Unchanged) */
+	.table-container {
+		margin-top: 2rem;
+		overflow-x: auto;
+		border-radius: 12px;
+		box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+	}
+
+	.stock-table {
+		width: 100%;
+		border-collapse: collapse;
+		font-family: system-ui, sans-serif;
+		background-color: #fff;
+		border-radius: 12px;
+		overflow: hidden;
+		min-width: 600px;
+	}
+
+	th,
+	td {
+		padding: 1rem 1.25rem;
+		text-align: left;
+		white-space: nowrap;
+	}
+
+	thead {
+		background-color: #f7f7f7;
+		border-bottom: 2px solid #e0e0e0;
+	}
+
+	th {
+		font-weight: 600;
+		font-size: 0.95rem;
+		color: #333;
+	}
+
+	tbody tr:nth-child(odd) {
+		background-color: #fafafa;
+	}
+
+	tbody tr:nth-child(even) {
+		background-color: #f0f4f8;
+	}
+
+	tbody tr:hover {
+		background-color: #e1ecf4;
+	}
+
+	td {
+		font-size: 0.95rem;
+		color: #555;
+		border-bottom: 1px solid #eee;
+	}
+
+	.code {
+		font-weight: 600;
+		color: #2c3e50;
+	}
+
+	.name {
+		color: #7f8c8d;
+	}
+
+	.qty-edit {
+		display: flex;
+		align-items: center;
+		gap: 0.5rem;
+	}
+
+	.qty-input {
+		width: 60px;
+		padding: 0.4rem 0.5rem;
+		font-size: 0.9rem;
+		border: 1px solid #ccc;
+		border-radius: 6px;
+		text-align: right;
+		background-color: #fff;
+		color: #333;
+		transition: border-color 0.2s ease;
+	}
+
+	.qty-input:focus {
+		outline: none;
+		border-color: #2980b9;
+	}
+
+	.remove-btn {
+		height: 15px;
+		width: 15px;
+		background-color: #e74c3c;
+		border-radius: 50%;
+		display: inline-block;
+		border: 0;
+	}
+
+	.price {
+		color: #27ae60;
+		font-weight: bold;
+	}
+
+	.total {
+		font-weight: 500;
+		color: #34495e;
+	}
+
+	.percent {
+		color: #2980b9;
+	}
+
+	/* Responsive design */
+	@media (max-width: 768px) {
+		.modal-content {
+			width: 90%;
+			padding: 1.5rem;
+		}
+
+		input[type='text'],
+		input[type='number'] {
+			font-size: 0.9rem;
+		}
+
+		.modal-result {
+			max-height: 200px;
+		}
+
+		.list-group-item {
+			font-size: 0.9rem;
+		}
+	}
+
+	@media (max-width: 768px) {
+		.stock-table {
+			font-size: 0.875rem;
+		}
+
+		th,
+		td {
+			padding: 0.75rem 1rem;
+		}
+	}
+
+	/* Modal Styling */
+	.modal-container {
+		position: fixed;
+		top: 20%;
+		left: 0;
+		right: 0;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		z-index: 9999;
+		animation: fadeIn 0.3s ease;
+	}
+
+	/* Modal content styling */
+	.modal-content {
+		background-color: #fff;
+		color: #333;
+		width: 450px;
+		height: auto;
+		max-width: 500px;
+		border-radius: 10px;
+		padding: 2rem;
+		box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+		transition: transform 0.3s ease-in-out;
+	}
+
+	/* Button container for Add and Dropdown */
+	.button-container {
+		display: flex;
+		gap: 10px;
+		margin-bottom: 1rem;
+		align-items: center;
+	}
+
+	.order-select {
+		width: 200px;
+		padding: 0.5rem;
+		border-radius: 8px;
+		border: 1px solid #ddd;
+		font-size: 1rem;
+		background-color: #f9f9f9;
+		transition: border-color 0.3s ease;
+	}
+
+	.order-select:focus {
+		border-color: #2980b9;
+		outline: none;
+	}
+
+	/* Input Fields (Stock code and search) */
+	input[type='text'],
+	input[type='number'] {
+		width: 100%;
+		padding: 0.8rem;
+		font-size: 1rem;
+		border-radius: 8px;
+		border: 1px solid #ddd;
+		margin-bottom: 10px;
+		background-color: #f9f9f9;
+		color: #333;
+		transition: border-color 0.3s ease;
+	}
+
+	input[type='text']:focus,
+	input[type='number']:focus {
+		border-color: #2980b9;
+		outline: none;
+	}
+
+	/* Button styles */
+	.btn {
+		padding: 0.6rem 1.2rem;
+		font-size: 1rem;
+		border-radius: 8px;
+		border: none;
+		cursor: pointer;
+		transition: background-color 0.3s ease;
+	}
+
+	.btn-primary {
+		background-color: #2980b9;
+		color: white;
+	}
+
+	.btn-primary:hover {
+		background-color: #3498db;
+	}
+
+	.btn-danger {
+		background-color: #e74c3c;
+		color: white;
+	}
+
+	.btn-danger:hover {
+		background-color: #c0392b;
+	}
+
+	/* Reset Button (Modal) */
+	input[type='reset'] {
+		background-color: #e74c3c;
+		color: white;
+		font-size: 1rem;
+		padding: 0.6rem 1.2rem;
+		border-radius: 8px;
+		cursor: pointer;
+		border: none;
+	}
+
+	/* Modal result items */
+	.modal-result {
+		max-width: 100%;
+		max-height: 300px;
+		overflow-y: auto;
+		padding: 0.8rem;
+		background-color: #fafafa;
+		border-radius: 10px;
+		margin-top: 1rem;
+	}
+
+	.list-group-item {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 10px;
+		border: 1px solid #ddd;
+		margin-bottom: 0.5rem;
+		border-radius: 8px;
+		background-color: #f9f9f9;
+		transition: background-color 0.3s ease;
+	}
+
+	.list-group-item:hover {
+		background-color: #f1f1f1;
+	}
+
+	.list-group-item .btn-primary {
+		background-color: #2980b9;
+		color: white;
+		border-radius: 50%;
+		height: 30px;
+		width: 30px;
+		padding: 0;
+		border: none;
+	}
+
+	.list-group-item .btn-primary:hover {
+		background-color: #3498db;
+	}
+
+	/* Modal transition */
+	@keyframes fadeIn {
+		from {
+			opacity: 0;
+		}
+		to {
+			opacity: 1;
+		}
+	}
 </style>

+ 58 - 54
src/routes/register/+page.svelte

@@ -1,68 +1,72 @@
 <script>
-    import {authentication} from "../store.js";
+	import { authentication } from '../store.js';
 
-    async function submit(event) {
-        event.preventDefault();
+	async function submit(event) {
+		event.preventDefault();
 
-        const formData = new FormData(event.target);
-        const username = formData.get("username");
-        const password = formData.get("password");
-        const passwordConfirm = formData.get("passwordConfirm");
+		const formData = new FormData(event.target);
+		const username = formData.get('username');
+		const password = formData.get('password');
+		const passwordConfirm = formData.get('passwordConfirm');
 
-        if (!username || !password) {
-            alert("Please enter both username and password.");
-            return;
-        }
+		if (!username || !password) {
+			alert('Please enter both username and password.');
+			return;
+		}
 
-        if (password !== passwordConfirm) {
-            alert("Passwords don't match");
-            return;
-        }
+		if (password !== passwordConfirm) {
+			alert("Passwords don't match");
+			return;
+		}
 
-        const data = {
-            username: username,
-            password: password
-        };
+		const data = {
+			username: username,
+			password: password
+		};
 
-        try {
-            const response = await fetch(import.meta.env.VITE_AUTH_HOST + '/api/register', {
-                method: 'POST',
-                headers: {
-                    'Content-Type': 'application/json',
-                },
-                body: JSON.stringify(data),
-            });
-
-            if (response.ok) {
-                const result = await response.json();
-                authentication.set(result);
-                localStorage.setItem('authentication', JSON.stringify(result));
-                window.location.href = "/login";
-            } else {
-                const error = await response.json();
-                console.error('Registration failed:', error);
-                alert('Registration failed: ' + error.message);
-            }
-        } catch (err) {
-            console.error('Error during registration:', err);
-            alert('An error occurred. Please try again.');
-        }
-    }
+		try {
+			const response = await fetch(import.meta.env.VITE_AUTH_HOST + '/api/register', {
+				method: 'POST',
+				headers: {
+					'Content-Type': 'application/json'
+				},
+				body: JSON.stringify(data)
+			});
 
+			if (response.ok) {
+				const result = await response.json();
+				authentication.set(result);
+				localStorage.setItem('authentication', JSON.stringify(result));
+				window.location.href = '/login';
+			} else {
+				const error = await response.json();
+				console.error('Registration failed:', error);
+				alert('Registration failed: ' + error.message);
+			}
+		} catch (err) {
+			console.error('Error during registration:', err);
+			alert('An error occurred. Please try again.');
+		}
+	}
 </script>
 
 <svelte:head>
-    <title>Register</title>
-    <meta name="description" content="Registration page"/>
+	<title>Register</title>
+	<meta name="description" content="Registration page" />
 </svelte:head>
 
 <div class="text-column">
-    <div class="card">
-        <form on:submit={submit}>
-            <input type="text" name="username" placeholder="username" class="input-field"/>
-            <input type="password" name="password" placeholder="password" class="input-field"/>
-            <input type="password" name="passwordConfirm" placeholder="repeat password" class="input-field"/>
-            <button type="submit" class="register-button">Register</button>
-        </form>
-    </div>
-</div>
+	<div class="card">
+		<form on:submit={submit}>
+			<input type="text" name="username" placeholder="username" class="input-field" />
+			<input type="password" name="password" placeholder="password" class="input-field" />
+			<input
+				type="password"
+				name="passwordConfirm"
+				placeholder="repeat password"
+				class="input-field"
+			/>
+			<button type="submit" class="register-button">Register</button>
+		</form>
+	</div>
+</div>

+ 152 - 147
src/routes/stocks/+page.svelte

@@ -1,158 +1,163 @@
 <script>
-    import {onMount} from "svelte";
-
-    let myStocks = ["AAPL", "AME", "BVMF:ABEV3"];
-    let result = [];
-
-    onMount(async () => {
-        if (myStocks.length !== 0) {
-            for (const code of myStocks) {
-                const stockInfo = await get(code);
-                if (stockInfo) {
-                    result = [...result, stockInfo[0]];
-                }
-            }
-        }
-    });
-
-    async function get(stock) {
-        try {
-            const response = await fetch(import.meta.env.VITE_STOCKS_HOST + '/api/stocks?q=' + stock, {
-                method: 'GET'
-            });
-
-            if (response.ok) {
-                return await response.json();
-            } else {
-                const error = await response.json();
-                console.error('Failed to find stock info:', error);
-                alert('Failed to find stock info: ' + error.message);
-            }
-        } catch (err) {
-            console.error('Error during login:', err);
-            alert('An error occurred. Please try again.');
-        }
-    }
-
-    async function add(event) {
-        event.preventDefault();
-
-        const formData = new FormData(event.target);
-        const stock = formData.get("stock");
-
-        if (!stock) {
-            alert("Please enter a stock code.");
-            return;
-        }
-
-        const stockInfo = await get(stock);
-
-        if (stockInfo) {
-            if (result.some(item => item.code === stockInfo[0].code)) return;
-            result = [...result, stockInfo[0]];
-            event.target.reset();
-        }
-    }
+	import { onMount } from 'svelte';
+
+	let myStocks = ['AAPL', 'AME', 'BVMF:ABEV3'];
+	let result = [];
+
+	onMount(async () => {
+		if (myStocks.length !== 0) {
+			for (const code of myStocks) {
+				const stockInfo = await get(code);
+				if (stockInfo) {
+					result = [...result, stockInfo[0]];
+				}
+			}
+		}
+	});
+
+	async function get(stock) {
+		try {
+			const response = await fetch(import.meta.env.VITE_STOCKS_HOST + '/api/stocks?q=' + stock, {
+				method: 'GET'
+			});
+
+			if (response.ok) {
+				return await response.json();
+			} else {
+				const error = await response.json();
+				console.error('Failed to find stock info:', error);
+				alert('Failed to find stock info: ' + error.message);
+			}
+		} catch (err) {
+			console.error('Error during login:', err);
+			alert('An error occurred. Please try again.');
+		}
+	}
+
+	async function add(event) {
+		event.preventDefault();
+
+		const formData = new FormData(event.target);
+		const stock = formData.get('stock');
+
+		if (!stock) {
+			alert('Please enter a stock code.');
+			return;
+		}
+
+		const stockInfo = await get(stock);
+
+		if (stockInfo) {
+			if (result.some((item) => item.code === stockInfo[0].code)) return;
+			result = [...result, stockInfo[0]];
+			event.target.reset();
+		}
+	}
 </script>
 
 <svelte:head>
-    <title>Stocks</title>
-    <meta name="description" content="About"/>
+	<title>Stocks</title>
+	<meta name="description" content="About" />
 </svelte:head>
 
 <div>
-    <div class="card">
-        <form on:submit={add}>
-            <input type="text" name="stock" placeholder="Enter a stock name or code" class="input-field"/>
-            <button type="submit" class="add-button">Add</button>
-        </form>
-    </div>
-
-    {#if result.length !== 0}
-        <div class="result">
-            {#each result as stock}
-                <div class="card card2">
-                    <div class="stock-info">
-                        <div class="stock-code">{stock.code}</div>
-                        <div class="stock-name">{stock.name}</div>
-                    </div>
-                    <div class="stock-details">
-                        <div class="stock-currency">{stock.currency}</div>
-                        <div class="stock-price">{stock.price}</div>
-                    </div>
-                </div>
-            {/each}
-        </div>
-    {/if}
+	<div class="card">
+		<form on:submit={add}>
+			<input
+				type="text"
+				name="stock"
+				placeholder="Enter a stock name or code"
+				class="input-field"
+			/>
+			<button type="submit" class="add-button">Add</button>
+		</form>
+	</div>
+
+	{#if result.length !== 0}
+		<div class="result">
+			{#each result as stock}
+				<div class="card card2">
+					<div class="stock-info">
+						<div class="stock-code">{stock.code}</div>
+						<div class="stock-name">{stock.name}</div>
+					</div>
+					<div class="stock-details">
+						<div class="stock-currency">{stock.currency}</div>
+						<div class="stock-price">{stock.price}</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	{/if}
 </div>
 
 <style>
-    .result {
-        margin-top: 1rem;
-        display: flex;
-        flex-wrap: wrap;
-        gap: 2rem;
-    }
-
-    .card {
-        flex: 1 1 300px;
-    }
-
-    .card2 {
-        background-color: #fafafa;
-        border: 1px solid #eee;
-        border-radius: 12px;
-        max-width: 267px;
-    }
-
-    .card:hover {
-        transform: translateY(-10px);
-    }
-
-    .stock-info {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-bottom: 10px;
-    }
-
-    .stock-code {
-        font-size: 1.5rem;
-        font-weight: bold;
-        color: #333;
-    }
-
-    .stock-name {
-        font-size: 1.1rem;
-        font-weight: normal;
-        color: #555;
-        text-align: right;
-    }
-
-    .stock-info:after {
-        content: '';
-        display: block;
-        width: 100%;
-        height: 1px;
-        background-color: #ddd;
-        margin-top: 10px;
-    }
-
-    .stock-details {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-top: 15px;
-    }
-
-    .stock-currency {
-        font-size: 1rem;
-        color: #888;
-    }
-
-    .stock-price {
-        font-size: 1.5rem;
-        font-weight: bold;
-        color: #27ae60;
-    }
+	.result {
+		margin-top: 1rem;
+		display: flex;
+		flex-wrap: wrap;
+		gap: 2rem;
+	}
+
+	.card {
+		flex: 1 1 300px;
+	}
+
+	.card2 {
+		background-color: #fafafa;
+		border: 1px solid #eee;
+		border-radius: 12px;
+		max-width: 267px;
+	}
+
+	.card:hover {
+		transform: translateY(-10px);
+	}
+
+	.stock-info {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 10px;
+	}
+
+	.stock-code {
+		font-size: 1.5rem;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.stock-name {
+		font-size: 1.1rem;
+		font-weight: normal;
+		color: #555;
+		text-align: right;
+	}
+
+	.stock-info:after {
+		content: '';
+		display: block;
+		width: 100%;
+		height: 1px;
+		background-color: #ddd;
+		margin-top: 10px;
+	}
+
+	.stock-details {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-top: 15px;
+	}
+
+	.stock-currency {
+		font-size: 1rem;
+		color: #888;
+	}
+
+	.stock-price {
+		font-size: 1.5rem;
+		font-weight: bold;
+		color: #27ae60;
+	}
 </style>

+ 1 - 1
src/routes/store.js

@@ -1,3 +1,3 @@
 import { writable } from 'svelte/store';
 
-export const authentication = writable(null);
+export const authentication = writable(null);

+ 32 - 32
static/css/form.css

@@ -1,57 +1,57 @@
 .text-column {
-    text-align: center; /* Center align text */
+	text-align: center; /* Center align text */
 }
 
 .card {
-    background-color: #ffffff; /* White background for the card */
-    border-radius: 12px; /* Rounded corners */
-    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
-    padding: 20px; /* Padding inside the card */
-    transition: transform 0.3s; /* Transition for hover effect */
+	background-color: #ffffff; /* White background for the card */
+	border-radius: 12px; /* Rounded corners */
+	box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
+	padding: 20px; /* Padding inside the card */
+	transition: transform 0.3s; /* Transition for hover effect */
 }
 
 .card:hover {
-    transform: translateY(-5px); /* Slight lift effect on hover */
+	transform: translateY(-5px); /* Slight lift effect on hover */
 }
 
 .input-field {
-    width: 100%; /* Full width for inputs */
-    padding: 12px 0; /* Padding for input fields */
-    margin: 10px 0; /* Margin between input fields */
-    border: 1px solid #ccc; /* Light border */
-    border-radius: 6px; /* Rounded corners for input fields */
-    font-size: 16px; /* Font size for input text */
-    outline: none; /* Remove outline on focus */
-    transition: border-color 0.3s; /* Transition for border color */
+	width: 100%; /* Full width for inputs */
+	padding: 12px 0; /* Padding for input fields */
+	margin: 10px 0; /* Margin between input fields */
+	border: 1px solid #ccc; /* Light border */
+	border-radius: 6px; /* Rounded corners for input fields */
+	font-size: 16px; /* Font size for input text */
+	outline: none; /* Remove outline on focus */
+	transition: border-color 0.3s; /* Transition for border color */
 }
 
 .input-field:focus {
-    border-color: #007bff; /* Change border color on focus */
+	border-color: #007bff; /* Change border color on focus */
 }
 
 button {
-    width: 100%; /* Full width for the button */
-    margin: 5px 0;
-    padding: 12px; /* Padding for the button */
-    background-color: #007bff; /* Button color */
-    color: white; /* White text color */
-    border: none; /* No border */
-    border-radius: 6px; /* Rounded corners for button */
-    font-size: 16px; /* Font size for button text */
-    cursor: pointer; /* Change cursor to pointer */
-    transition: background-color 0.3s; /* Transition for button color */
+	width: 100%; /* Full width for the button */
+	margin: 5px 0;
+	padding: 12px; /* Padding for the button */
+	background-color: #007bff; /* Button color */
+	color: white; /* White text color */
+	border: none; /* No border */
+	border-radius: 6px; /* Rounded corners for button */
+	font-size: 16px; /* Font size for button text */
+	cursor: pointer; /* Change cursor to pointer */
+	transition: background-color 0.3s; /* Transition for button color */
 }
 
 .add-button {
-    background-color: #007bff; /* Button color */
-    color: white; /* White text color */
+	background-color: #007bff; /* Button color */
+	color: white; /* White text color */
 }
 
 .register-button {
-    background-color: #20bf6b; /* Button color */
-    color: white; /* White text color */
+	background-color: #20bf6b; /* Button color */
+	color: white; /* White text color */
 }
 
 .add-button:hover {
-    background-color: #0056b3; /* Darker button color on hover */
-}
+	background-color: #0056b3; /* Darker button color on hover */
+}

+ 3 - 3
vite.config.js

@@ -4,7 +4,7 @@ import { defineConfig } from 'vite';
 export default defineConfig({
 	plugins: [sveltekit()],
 	server: {
-                port: 53303,
-                host: true
-        }
+		port: 53303,
+		host: true
+	}
 });