auth additions and website layout
All checks were successful
ci / docker_image (push) Successful in 1m28s
ci / deploy (push) Successful in 27s

This commit is contained in:
Drake Marino 2025-01-16 22:20:39 -06:00
parent f0fc8b09ab
commit cfde960e63
12 changed files with 110 additions and 40 deletions

View File

@ -2,8 +2,9 @@
| Permission Value | Description | | Permission Value | Description |
|------------------|------------------------| |------------------|------------------------|
| `00000001` | Read access | | `00000001` | View postings |
| `00000010` | Submit postings access | | `00000010` | View account |
| `00000100` | Manage postings | | `00000100` | Submit postings access |
| `00001000` | Manage users | | `00001000` | Manage postings |
| `00010000` | Apply | | `00010000` | Manage users |
| `00100000` | Apply |

View File

@ -6,12 +6,18 @@
--text-color: #000000; --text-color: #000000;
--bg-color: #f4f4f4; --bg-color: #f4f4f4;
--hover-bg-color: #e4e4f0; --hover-bg-color: #e4e4f0;
--elevated-bg-color: #ffffff;
--low-emphasis-text-color: #6b6b6b;
--primary-color: #1F96F3;
} }
[data-theme='dark'] { [data-theme='dark'] {
--text-color: #f4f4f4; --text-color: #f4f4f4;
--bg-color: #010101; --bg-color: #080808;
--hover-bg-color: #1f2937; --hover-bg-color: #1f2937;
--elevated-bg-color: #1a202c;
--low-emphasis-text-color: #999999;
--primary-color: #1F96F3;
} }
body { body {
@ -24,23 +30,41 @@ h1 {
@apply text-4xl @apply text-4xl
} }
.nav-item { .elevated {
@apply rounded px-3 py-2 text-sm mr-1 background-color: var(--elevated-bg-color);
@apply shadow-lg
} }
.nav-item:hover { .hover-bg-color:hover {
background-color: var(--hover-bg-color); background-color: var(--hover-bg-color);
} }
.nav-trailing { .low-emphasis-text {
@apply rounded-full p-1 color: var(--low-emphasis-text-color);
} }
.nav-trailing:hover { .low-emphasis-text:hover {
background-color: var(--hover-bg-color); color: var(--text-color);
} }
.nav-logo:hover { .primary-underline {
background-color: var(--hover-bg-color); border-bottom: 2px solid var(--primary-color);
}
.top-border {
border-top: 1px solid var(--elevated-bg-color);
}
.bottom-border {
border-bottom: 1px solid var(--elevated-bg-color);
}
.small-icon {
font-size: 24px !important;
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 20
} }

View File

@ -6,9 +6,8 @@ export async function createUser(username: string, password: string): Promise<vo
const response = await sql` const response = await sql`
INSERT INTO users (username, password_hash, perms) INSERT INTO users (username, password_hash, perms)
VALUES (${username}, ${password_hash}, 2); VALUES (${username}, ${password_hash}, 3);
`; `;
console.log(response);
} }
export async function checkUserCreds(username: string, password: string): Promise<number> { export async function checkUserCreds(username: string, password: string): Promise<number> {

View File

@ -1 +1 @@
export let userState = $state({ permissions: 0b00000001 }); export let userState = $state({ perms: 0b00000001 });

View File

@ -33,25 +33,21 @@
const JWT = getCookieValue('jwt'); const JWT = getCookieValue('jwt');
if (JWT !== '') { if (JWT !== '') {
userState.permissions = JSON.parse(JWT.split('.')[1]).permissions; userState.perms = JSON.parse(atob(JWT.split('.')[1])).perms;
} }
console.log(userState.permissions);
}); });
// userState.permissions = 0b00000011;
// console.log(userState.permissions);
let { children } = $props(); let { children } = $props();
</script> </script>
<link <link
rel="stylesheet" rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@40,400,0,0&icon_names=account_circle,dark_mode,light_mode,login" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..40,400,0,0&display=block&icon_names=account_circle,dark_mode,group,light_mode,login,sell,work"
/> />
<div class="mx-2 flex h-14 justify-between p-3"> <div class="bottom-border mx-2 flex h-16 justify-between p-4 align-middle">
<nav> <nav class="pt-1">
<a href="/" class="nav-logo mr-1 rounded-md px-2 pb-2 pt-1.5"> <a href="/" class="hover-bg-color mr-1 rounded-md px-2 pb-2 pt-1.5">
<img <img
class="inline-block" class="inline-block"
src="/mdevtriangle.svg" src="/mdevtriangle.svg"
@ -60,27 +56,38 @@
width="24" width="24"
/> />
</a> </a>
<a href="/about" class="nav-item">About</a> <a href="/about" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">About</a>
<a href="/listings" class="nav-item">Listings</a> {#if (userState.perms & 0b00000001) !== 0}
<a href="/administration" class="nav-item">Administration</a> <a href="/listings" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Listings</a>
{/if}
{#if (userState.perms & 0b00001000) !== 0}
<a href="/administration/postings" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm"
>Administration</a
>
{/if}
</nav> </nav>
<div> <div>
<button onclick={toggleTheme} class="pr-2"> <button onclick={toggleTheme} class="">
<span class="material-symbols-outlined nav-trailing dark:invisible"> <span class="material-symbols-outlined rounded-full p-1 dark:invisible">
{'light_mode'} {'light_mode'}
</span> </span>
</button> </button>
<button onclick={toggleTheme} class="pr-2"> <button onclick={toggleTheme} class="">
<span class="material-symbols-outlined nav-trailing invisible dark:visible"> <span class="material-symbols-outlined invisible rounded-full p-1 dark:visible">
{'dark_mode'} {'dark_mode'}
</span> </span>
</button> </button>
<button onclick={() => (window.location.href = '/signin')}> <button
<span class="material-symbols-outlined nav-trailing">{'account_circle'}</span> onclick={() =>
(window.location.href = (userState.perms & 0b00000010) !== 0 ? '/account' : '/signin')}
>
<span class="material-symbols-outlined rounded-full p-1">
{(userState.perms & 0b00000010) !== 0 ? 'account_circle' : 'login'}
</span>
</button> </button>
</div> </div>
</div> </div>
<div class="p-4"> <div>
{@render children()} {@render children()}
</div> </div>

View File

@ -1 +1,5 @@
<p>hola</p> <h1>About</h1>
<p>
This is my submission for the 2025 FBLA Website Coding & Development event. It was built using
<a href="https://svelte.dev/docs/kit/introduction" class="text-blue-600">SvelteKit</a>.
</p>

View File

@ -0,0 +1,34 @@
<script lang="ts">
import '../../app.css';
import { page } from '$app/stores';
let { children } = $props();
</script>
<div class="pt-2 text-center">
<a
href="/administration/postings"
class="p-2 {$page.url.pathname === '/administration/postings'
? 'primary-underline font-bold'
: 'low-emphasis-text'}"
><span class="material-symbols-outlined small-icon align-bottom">work</span> Postings</a
>
<a
href="/administration/users"
class="p-2 {$page.url.pathname === '/administration/users'
? 'primary-underline font-bold'
: 'low-emphasis-text'}"
><span class="material-symbols-outlined small-icon align-bottom">group</span> Users</a
>
<a
href="/administration/tags"
class="{$page.url.pathname === '/administration/tags'
? 'primary-underline font-bold'
: 'low-emphasis-text'} p-2"
><span class="material-symbols-outlined small-icon align-bottom">sell</span> Tags</a
>
</div>
<div>
{@render children()}
</div>

View File

View File

@ -16,8 +16,9 @@ function setJWT(cookies: Cookies, username: string, perms: number) {
} }
const maxAge = 60 * 60 * 24 * 30; // 30 days const maxAge = 60 * 60 * 24 * 30; // 30 days
const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30m' }); const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30d' });
cookies.set('jwt', JWT, { maxAge, path: '/' }); cookies.set('jwt', JWT, { maxAge, path: '/', httpOnly: false });
console.log(cookies.get('jwt'));
} }
export const actions: Actions = { export const actions: Actions = {