ソースを参照

Add login page

Daniel Bohry 1 年間 前
コミット
af5e355a02
5 ファイル変更176 行追加9 行削除
  1. 1 0
      .gitignore
  2. BIN
      src/lib/images/profile.png
  3. 21 6
      src/routes/Header.svelte
  4. 151 3
      src/routes/login/+page.svelte
  5. 3 0
      src/routes/store.js

+ 1 - 0
.gitignore

@@ -21,3 +21,4 @@ vite.config.js.timestamp-*
 vite.config.ts.timestamp-*
 .idea
 package-lock.json
+*.iml

BIN
src/lib/images/profile.png


+ 21 - 6
src/routes/Header.svelte

@@ -1,6 +1,16 @@
 <script>
     import {page} from '$app/stores';
-    import profile from '$lib/images/github.svg';
+    import profile from '$lib/images/profile.png';
+    import {auth} from "./store.js";
+
+    let username = null;
+    let profileTitle = null;
+
+    $: auth.subscribe(value => {
+        username = value ? value.username : "";
+        profileTitle = value ? "You are logged in as " + value.username : "login";
+    });
+
 </script>
 
 <header>
@@ -16,15 +26,13 @@
             <li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
                 <a href="/about">About</a>
             </li>
-            <li aria-current={$page.url.pathname === '/login' ? 'page' : undefined}>
-                <a href="/login">Login</a>
-            </li>
         </ul>
     </nav>
 
     <div class="corner">
+        <div class="login-message">{username}</div>
         <a href="/login">
-            <img src={profile} alt="Profile"/>
+            <img src={profile} alt="Profile" style="width: 16px; height: 16px;" title="{profileTitle}"/>
         </a>
     </div>
 </header>
@@ -38,8 +46,15 @@
     }
 
     .corner {
-        width: 3em;
+        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 {

+ 151 - 3
src/routes/login/+page.svelte

@@ -1,8 +1,156 @@
+<script>
+    import {onMount} from 'svelte';
+    import {auth} from '../store.js';
+
+    let isAuthenticated = false;
+    let isLoading = true;
+    let user = null;
+
+    $: auth.subscribe(value => {
+        isAuthenticated = !!value;
+        if (value) {
+            user = value;
+        }
+    });
+
+    onMount(() => {
+        const storedAuth = localStorage.getItem('auth');
+        if (storedAuth) {
+            auth.set(JSON.parse(storedAuth));
+        }
+        isLoading = false;
+    });
+
+    async function submit(event) {
+        event.preventDefault();
+
+        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;
+        }
+
+        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),
+            });
+
+            if (response.ok) {
+                const result = await response.json();
+                auth.set(result);
+                localStorage.setItem('auth', 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() {
+        auth.set(null);
+        localStorage.removeItem('auth');
+    }
+
+</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">
-	<h1>Login</h1>
+    {#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="login-button">Login</button>
+                    <button type="button" class="register-button">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>
+
+<style>
+    .text-column {
+        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 */
+        width: 300px; /* Fixed width for the card */
+        transition: transform 0.3s; /* Transition for hover effect */
+    }
+
+    .card:hover {
+        transform: translateY(-5px); /* Slight lift effect on hover */
+    }
+
+    .input-field {
+        width: 90%; /* Full width for inputs */
+        padding: 12px; /* 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 */
+    }
+
+    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 */
+    }
+
+    .login-button {
+        background-color: #007bff; /* Button color */
+        color: white; /* White text color */
+    }
+
+    .register-button {
+        background-color: #20bf6b; /* Button color */
+        color: white; /* White text color */
+    }
+
+    .login-button:hover {
+        background-color: #0056b3; /* Darker button color on hover */
+    }
+</style>

+ 3 - 0
src/routes/store.js

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