Mobile Compatibility
All checks were successful
ci / docker_image (push) Successful in 2m26s
ci / deploy (push) Successful in 24s

This commit is contained in:
Drake Marino 2025-06-19 20:17:11 -05:00
parent cbe002f4c4
commit 1474ba29db
9 changed files with 210 additions and 134 deletions

View File

@ -189,7 +189,7 @@ input[type='search']:-webkit-autofill, input[type='text']:-webkit-autofill, inpu
.content { .content {
width: 100%; width: 100%;
@apply px-6; @apply px-2;
} }

View File

@ -3,6 +3,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { updateUserState, userState } from '$lib/shared.svelte'; import { updateUserState, userState } from '$lib/shared.svelte';
import { PERMISSIONS } from '$lib/consts'; import { PERMISSIONS } from '$lib/consts';
import { MediaQuery } from 'svelte/reactivity';
let currentTheme: string = $state(''); let currentTheme: string = $state('');
@ -18,6 +19,15 @@
currentTheme = theme; currentTheme = theme;
} }
function toggleMenu() {
var menu = document.getElementById('mobile-menu')!;
if (menu.style.display === 'block') {
menu.style.display = 'none';
} else {
menu.style.display = 'block';
}
}
onMount(() => { onMount(() => {
const savedTheme = document.documentElement.getAttribute('data-theme'); const savedTheme = document.documentElement.getAttribute('data-theme');
if (savedTheme) { if (savedTheme) {
@ -31,11 +41,13 @@
updateUserState(); updateUserState();
}); });
const largeScreen = new MediaQuery('min-width: 640px');
let { children } = $props(); let { children } = $props();
</script> </script>
<link <link
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,arrow_drop_down,arrow_drop_up,calendar_today,call,check,close,cloud_upload,dark_mode,delete,description,edit,group,info,light_mode,login,mail,open_in_new,person,search,sell,store,upload,visibility,visibility_off,work" 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,arrow_drop_down,arrow_drop_up,calendar_today,call,check,close,cloud_upload,dark_mode,delete,description,edit,group,info,light_mode,login,mail,menu,open_in_new,person,search,sell,store,upload,visibility,visibility_off,work"
rel="stylesheet" rel="stylesheet"
/> />
@ -50,13 +62,12 @@
src="/mdevtriangle.svg" src="/mdevtriangle.svg"
width="24" width="24"
/> />
<div class="inline-block text-sm">Home</div> <!-- <div class="inline-block text-sm">Home</div>-->
</a> </a>
<!-- <a href="/about" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">About</a>--> <!-- <a href="/about" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">About</a>-->
{#if largeScreen.current}
{#if (userState.perms & PERMISSIONS.VIEW) > 0} {#if (userState.perms & PERMISSIONS.VIEW) > 0}
<a href="/postings" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Postings</a> <a href="/postings" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Postings</a>
{/if}
{#if (userState.perms & PERMISSIONS.VIEW) > 0}
<a href="/companies" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Companies</a> <a href="/companies" class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Companies</a>
{/if} {/if}
{#if (userState.perms & (PERMISSIONS.MANAGE_POSTINGS | PERMISSIONS.MANAGE_TAGS | PERMISSIONS.MANAGE_USERS)) > 0} {#if (userState.perms & (PERMISSIONS.MANAGE_POSTINGS | PERMISSIONS.MANAGE_TAGS | PERMISSIONS.MANAGE_USERS)) > 0}
@ -74,33 +85,77 @@
class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Administration</a class="hover-bg-color mr-1 rounded px-3 py-2 text-sm">Administration</a
> >
{/if} {/if}
{/if}
</nav> </nav>
<div> <div>
<button class="" onclick={toggleTheme}> <button
<span class="material-symbols-outlined hover-bg-color rounded-full p-1"> class="material-symbols-outlined hover-bg-color rounded-full p-1"
onclick={toggleTheme}
>
{currentTheme === 'light' ? 'light_mode' : 'dark_mode'} {currentTheme === 'light' ? 'light_mode' : 'dark_mode'}
</span>
</button> </button>
{#if largeScreen.current}
<a <a
class="hover-bg-color inline-block rounded p-1 align-top" class="hover-bg-color inline-block h-min rounded p-1 pr-2 align-top"
href={userState.id !== null ? '/account' : '/signin'} href={userState.id !== null ? '/account' : '/signin'}
> >
<span class="material-symbols-outlined inline-block h-min align-middle"> <span class="material-symbols-outlined inline-block h-min align-top">
{userState.id !== null ? 'account_circle' : 'login'} {userState.id !== null ? 'account_circle' : 'login'}
</span> </span>
<span class="inline-block h-min align-middle text-sm"> <span class="inline-block h-min align-top text-sm">
{userState.id !== null ? 'Account' : 'Sign-in'} {userState.id !== null ? 'Account' : 'Sign-in'}
</span> </span>
</a> </a>
{:else}
<button
class="material-symbols-outlined hover-bg-color rounded-full p-1"
onclick={toggleMenu}>menu</button
>
{/if}
</div> </div>
</div> </div>
<div id="mobile-menu" class="hidden">
{#if (userState.perms & PERMISSIONS.VIEW) > 0}
<a
href="/postings"
class="hover-bg-color mr-1 block rounded px-3 py-2 text-sm"
onclick={toggleMenu}>Postings</a
>
<a
href="/companies"
class="hover-bg-color mr-1 block rounded px-3 py-2 text-sm"
onclick={toggleMenu}>Companies</a
>
{/if}
{#if (userState.perms & (PERMISSIONS.MANAGE_POSTINGS | PERMISSIONS.MANAGE_TAGS | PERMISSIONS.MANAGE_USERS)) > 0}
<a
href={(userState.perms & PERMISSIONS.MANAGE_POSTINGS) > 0
? '/admin/postings'
: (userState.perms & PERMISSIONS.MANAGE_USERS) > 0
? '/admin/users'
: // TODO: Implement tags
// : (userState.perms & PERMISSIONS.MANAGE_TAGS) > 0
// ? '/admin/tags'
(userState.perms & PERMISSIONS.MANAGE_COMPANIES) > 0
? '/admin/companies'
: '/admin'}
class="hover-bg-color mr-1 block rounded px-3 py-2 text-sm"
onclick={toggleMenu}>Administration</a
>
{/if}
</div>
<div class="flex-grow"> <div class="flex-grow">
{@render children()} {@render children()}
</div> </div>
<footer class="top-border bg-color footer flex h-min w-full justify-between p-2 text-center"> <footer
<div class="inline-block text-left align-top"> class="top-border bg-color footer {largeScreen.current
? 'flex'
: 'block'} h-min w-full justify-between p-2 text-center"
>
<div class="{largeScreen.current ? 'inline-block' : 'block'} text-left align-top">
<!--{#if largeScreen.current}-->
<div class="inline-block pr-3"> <div class="inline-block pr-3">
<p class="font-semibold">Drake Marino:</p> <p class="font-semibold">Drake Marino:</p>
<a class="hyperlink-color hyperlink-underline" href="mailto:drake@marinodev.com" <a class="hyperlink-color hyperlink-underline" href="mailto:drake@marinodev.com"
@ -113,21 +168,29 @@
>chetan@marinodev.com</a >chetan@marinodev.com</a
> >
</div> </div>
<!--{/if}-->
</div> </div>
<div class="inline-block align-top font-semibold"> {#if largeScreen.current}
<div
class="{largeScreen.current ? 'inline-block' : 'block text-left'} align-top font-semibold"
>
<div class="font-semibold">MarinoDev</div> <div class="font-semibold">MarinoDev</div>
<div class="font-normal">2025</div> <div class="font-normal">2025</div>
</div> </div>
<div class="inline-block text-right align-top"> {/if}
<div class="{largeScreen.current ? 'inline-block text-right' : 'block text-left'} align-top">
<!--{#if largeScreen.current}-->
<div class="font-semibold">Source Code:</div> <div class="font-semibold">Source Code:</div>
<a <a
class="hyperlink-color hyperlink-underline" class="hyperlink-color hyperlink-underline"
href="https://git.marinodev.com/MarinoDev/FBLA25" href="https://git.marinodev.com/MarinoDev/FBLA25"
>https://git.marinodev.com/MarinoDev/FBLA25</a >https://git.marinodev.com/MarinoDev/FBLA25</a
> >
<!--{/if}-->
</div> </div>
</footer> </footer>
</div> </div>
<!--<h3 class="pt-16 font-semibold">Contact Information:</h3>--> <!--<h3 class="pt-16 font-semibold">Contact Information:</h3>-->
<!--<p>Drake Marino:</p>--> <!--<p>Drake Marino:</p>-->
<!--<a href="mailto:drake@marinodev.com" class="hyperlink-color hyperlink-underline"--> <!--<a href="mailto:drake@marinodev.com" class="hyperlink-color hyperlink-underline"-->

View File

@ -9,7 +9,7 @@
</script> </script>
<div class="content"> <div class="content">
<div class="elevated separator-borders m-4 rounded"> <div class="elevated separator-borders my-2 rounded">
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold"> <div class="p-3 font-semibold">
Company Management (Total: {data.companies?.length || 0}) Company Management (Total: {data.companies?.length || 0})

View File

@ -13,7 +13,7 @@
</script> </script>
<div class="content"> <div class="content">
<div class="elevated separator-borders m-4 rounded"> <div class="elevated separator-borders my-2 rounded">
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold"> <div class="p-3 font-semibold">
Posting Management (Total: {data.postings?.length || 0}) Posting Management (Total: {data.postings?.length || 0})

View File

@ -18,7 +18,7 @@
</script> </script>
<div class="content"> <div class="content">
<div class="elevated separator-borders m-4 rounded"> <div class="elevated separator-borders my-2 rounded">
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold"> <div class="p-3 font-semibold">
User Account Management (Total: {data.users?.length || 0}) User Account Management (Total: {data.users?.length || 0})

View File

@ -14,7 +14,7 @@
<div class="base-container-small"> <div class="base-container-small">
<div class="content"> <div class="content">
<div class="elevated separator-borders mb-4 mt-4 rounded"> <div class="elevated separator-borders my-2 rounded">
<div class="flex justify-between"> <div class="flex justify-between">
<div class="inline-block p-3 font-semibold">Companies</div> <div class="inline-block p-3 font-semibold">Companies</div>
{#if (userState.perms & PERMISSIONS.MANAGE_COMPANIES) > 0 || (userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0} {#if (userState.perms & PERMISSIONS.MANAGE_COMPANIES) > 0 || (userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0}

View File

@ -4,6 +4,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { employmentTypeDisplayName, userState } from '$lib/shared.svelte'; import { employmentTypeDisplayName, userState } from '$lib/shared.svelte';
import { PERMISSIONS } from '$lib/consts'; import { PERMISSIONS } from '$lib/consts';
import { MediaQuery } from 'svelte/reactivity';
let details: Posting | undefined = $state<Posting>(); let details: Posting | undefined = $state<Posting>();
@ -38,6 +39,8 @@
onMount(async () => { onMount(async () => {
await fetchDetails(data.postings[0].id); await fetchDetails(data.postings[0].id);
}); });
const wideScreen = new MediaQuery('min-width: 768px');
</script> </script>
<div class="base-container"> <div class="base-container">
@ -63,14 +66,18 @@
</div> </div>
</form> </form>
<div class="flex"> <div class="flex">
<div class="right-border inline-block w-1/3"> <div class="right-border inline-block {wideScreen.current ? 'w-1/3' : 'w-full'}">
{#each data.postings as posting} {#each data.postings as posting}
<button <button
class="bottom-border block w-full p-4 text-left {details?.id === posting.id class="bottom-border block w-full p-4 text-left {details?.id === posting.id
? 'accent-bg-color' ? 'accent-bg-color'
: 'hover-bg-color'}" : 'hover-bg-color'}"
onclick={() => { onclick={() => {
if (wideScreen.current) {
fetchDetails(posting.id); fetchDetails(posting.id);
} else {
window.location.href = `/postings/${posting.id}`;
}
}} }}
> >
<img <img
@ -88,9 +95,10 @@
</button> </button>
{/each} {/each}
</div> </div>
{#if wideScreen.current}
{#if details !== undefined} {#if details !== undefined}
<div <div
class="elevated separator-borders top-with-navbar sticky mb-4 ml-4 inline-block h-min w-2/3 rounded p-4" class="elevated separator-borders top-with-navbar sticky mb-2 ml-2 inline-block h-min w-2/3 rounded p-4"
> >
<div class="bottom-border flex justify-between pb-2"> <div class="bottom-border flex justify-between pb-2">
<div class="inline-block"> <div class="inline-block">
@ -139,8 +147,8 @@
{#if details.address} {#if details.address}
<a <a
href="https://www.google.com/maps/search/?api=1&query={details.address}" href="https://www.google.com/maps/search/?api=1&query={details.address}"
class="block w-max" class="block"
>Address: <span class="hover-hyperlink">{details.address}</span></a >Address: <span class="hover-hyperlink break-words">{details.address}</span></a
> >
{/if} {/if}
{#if details.wage} {#if details.wage}
@ -150,15 +158,16 @@
<p>Posted: {details.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p> <p>Posted: {details.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p>
{/if} {/if}
{#if details.link} {#if details.link}
<a href={details.link} class="block w-max" <a href={details.link} class="block"
>More information: <span class="hyperlink-color hyperlink-underline" >More information: <span class="hyperlink-color hyperlink-underline break-all"
>{details.link}</span >{details.link}</span
></a ></a
> >
{/if} {/if}
{#if details.flyerLink} {#if details.flyerLink}
<a href={details.flyerLink} class="block w-max" <a href={details.flyerLink} class="block"
>Flyer: <span class="hyperlink-color hyperlink-underline">{details.flyerLink}</span >Flyer: <span class="hyperlink-color hyperlink-underline break-all"
>{details.flyerLink}</span
></a ></a
> >
{/if} {/if}
@ -167,6 +176,7 @@
</div> </div>
</div> </div>
{/if} {/if}
{/if}
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
<div class="base-container-small"> <div class="base-container-small">
<div class="content"> <div class="content">
<div class="elevated separator-borders ml-4 mt-4 inline-block h-min w-full rounded p-4"> <div class="elevated separator-borders my-2 inline-block h-min w-full rounded p-4">
<div class="bottom-border elevated-bg flex justify-between pb-2"> <div class="bottom-border elevated-bg flex justify-between pb-2">
<div class="inline-block"> <div class="inline-block">
<img <img
@ -66,8 +66,8 @@
{#if data.posting.address} {#if data.posting.address}
<a <a
href="https://www.google.com/maps/search/?api=1&query={data.posting.address}" href="https://www.google.com/maps/search/?api=1&query={data.posting.address}"
class="block w-max" class="block"
>Address: <span class="hover-hyperlink">{data.posting.address}</span></a >Address: <span class="hover-hyperlink break-words">{data.posting.address}</span></a
> >
{/if} {/if}
{#if data.posting.wage} {#if data.posting.wage}
@ -77,20 +77,23 @@
<p>Posted: {data.posting.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p> <p>Posted: {data.posting.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p>
{/if} {/if}
{#if data.posting.link} {#if data.posting.link}
<a href={data.posting.link} class="block w-max" <a href={data.posting.link} class="block"
>More information: <span class="hyperlink-color hyperlink-underline" >More information: <span class="hyperlink-color hyperlink-underline break-all"
>{data.posting.link}</span >{data.posting.link}</span
></a ></a
> >
{/if} {/if}
{#if data.posting.flyerLink} {#if data.posting.flyerLink}
<a href={data.posting.flyerLink} class="block w-max" <a href={data.posting.flyerLink} class="block"
>Flyer: <span class="hyperlink-color hyperlink-underline">{data.posting.flyerLink}</span >Flyer: <span class="hyperlink-color hyperlink-underline break-all"
>{data.posting.flyerLink}</span
></a ></a
> >
{/if} {/if}
<h2 class="pt-2 font-semibold">Job Description</h2> <h2 class="pt-2 font-semibold">Job Description</h2>
<p class="whitespace-pre-wrap">{data.posting.description}</p> <p class="whitespace-pre-wrap break-words">
{data.posting.description}
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -39,7 +39,7 @@
</script> </script>
<div class="content"> <div class="content">
<div class="elevated separator-borders m-4 rounded"> <div class="elevated separator-borders my-2 rounded">
<div class="flex place-content-between"> <div class="flex place-content-between">
<div class="p-3 font-semibold"> <div class="p-3 font-semibold">
Application Management (Total: {data.applications?.length || 0}) Application Management (Total: {data.applications?.length || 0})
@ -70,7 +70,7 @@
</button> </button>
<div class="panel hidden p-2"> <div class="panel hidden p-2">
<div class="flex justify-between"> <div class="flex justify-between">
<div class="inline-block pr-4 min-w-max"> <div class="inline-block min-w-max pr-4">
{#if application.user?.email} {#if application.user?.email}
<p>Email: {application.user.email}</p> <p>Email: {application.user.email}</p>
{/if} {/if}