Gonna try to start using git properly

This commit is contained in:
Eclypsed
2024-01-06 22:05:51 -05:00
parent b2790a7151
commit 0da467d1e0
57 changed files with 2592 additions and 341 deletions
+41
View File
@@ -0,0 +1,41 @@
<script>
export let alertType
export let alertMessage
import { onMount } from 'svelte'
import { slide } from 'svelte/transition'
import { fly } from 'svelte/transition'
import { createEventDispatcher } from 'svelte'
let show = false
const dispatch = createEventDispatcher()
const bgColors = {
info: 'bg-neutral-500',
success: 'bg-emerald-500',
caution: 'bg-amber-500',
warning: 'bg-red-500',
}
export const triggerClose = () => {
show = false
dispatch('closeAlert')
}
onMount(() => {
show = true
setTimeout(() => triggerClose(), 10000)
})
</script>
{#if show}
<div in:fly={{ duration: 300, x: 500 }} out:slide={{ duration: 300, axis: 'y' }} class="py-1">
<div class="flex gap-1 overflow-hidden rounded-md">
<div class="flex min-h-[3.5rem] w-full items-center px-4 py-2 {bgColors[alertType]}">
{alertMessage}
</div>
<button class="w-16 {bgColors[alertType]}" on:click={() => triggerClose()}>
<i class="fa-solid fa-x" />
</button>
</div>
</div>
{/if}
@@ -0,0 +1,30 @@
<script>
import Alert from './alert.svelte'
let alertBox
let alertQueue = []
export const addAlert = (alertType, alertMessage) => {
if (alertQueue.length > 5) {
alertQueue[0].triggerClose()
}
const alert = new Alert({
target: alertBox,
props: {
alertType: alertType,
alertMessage: alertMessage,
},
})
alert.$on('closeAlert', () => {
const index = alertQueue.indexOf(alert)
if (index > -1) alertQueue.splice(index, 1)
setTimeout(() => alert.$destroy(), 300)
})
alertQueue.push(alert)
}
</script>
<div bind:this={alertBox} class="fixed right-4 top-4 z-50 max-h-screen w-full max-w-sm overflow-hidden"></div>
@@ -0,0 +1,68 @@
<script>
import { fade, slide } from 'svelte/transition'
import { spin } from '$lib/utils/animations'
import { page } from '$app/stores'
let button,
icon,
open = false
$: $page.url, closeMenu()
const closeMenu = () => {
if (button && open) {
button.animate(spin(), 400)
open = false
}
}
</script>
<div class="relative aspect-square h-full">
<button
bind:this={button}
id="button"
class="grid h-full w-full place-items-center transition-transform duration-75 active:scale-90"
on:click={() => {
button.animate(spin(), 400)
open = !open
}}
>
{#if open}
<i id="menu-icon" transition:fade={{ duration: 300 }} bind:this={icon} class="fa-solid fa-xmark" />
{:else}
<i id="menu-icon" transition:fade={{ duration: 300 }} bind:this={icon} class="fa-solid fa-bars" />
{/if}
</button>
{#if open}
<section transition:slide={{ duration: 200, axis: 'y' }} id="dropdown" class="absolute w-screen max-w-sm">
<slot name="menu-items" />
</section>
{/if}
</div>
<style>
#dropdown {
top: calc(100% + 0.6rem);
}
#button::before {
content: '';
width: 0;
height: 0;
background-color: color-mix(in srgb, var(--lazuli-primary) 20%, transparent);
border-radius: 100%;
transition-property: width height;
transition-duration: 200ms;
position: absolute;
}
#menu-icon {
font-size: 1.5rem;
position: absolute;
transition: color 200ms;
}
#button:hover > i {
color: var(--lazuli-primary);
}
#button:hover::before {
width: 130%;
height: 130%;
}
</style>
@@ -0,0 +1,32 @@
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
</script>
<button class="relative grid aspect-square h-full place-items-center transition-transform duration-75 active:scale-90" on:click={() => dispatch('click')}>
<slot name="icon" />
</button>
<style>
button::before {
content: '';
width: 0;
height: 0;
background-color: color-mix(in srgb, var(--lazuli-primary) 20%, transparent);
border-radius: 100%;
transition-property: width height;
transition-duration: 200ms;
position: absolute;
}
button:hover::before {
width: 130%;
height: 130%;
}
button :global(> :first-child) {
transition: color 200ms;
}
button:hover :global(> :first-child) {
color: var(--lazuli-primary);
}
</style>
+48
View File
@@ -0,0 +1,48 @@
<script>
import HamburgerMenu from './hamburgerMenu.svelte'
import IconButton from './iconButton.svelte'
import SearchBar from './searchBar.svelte'
import { goto, afterNavigate } from '$app/navigation'
import { page } from '$app/stores'
import { fade } from 'svelte/transition'
let previousPage = null
afterNavigate(({ from }) => {
if (from) previousPage = from.url
})
let windowY = 0
</script>
<svelte:window bind:scrollY={windowY} />
<nav id="navbar" class="fixed left-0 top-0 isolate z-10 h-16 w-full">
<div class="grid h-full grid-cols-3">
<div class="flex h-full items-center gap-5 py-4 pl-6">
<HamburgerMenu>
<ol slot="menu-items" class="overflow-hidden rounded-lg border-2 border-neutral-800 bg-neutral-925 p-2">
<li>
<button class="w-full rounded-md px-3 py-2 text-left hover:bg-neutral-900" on:click={() => goto('/settings')}>
<i class="fa-solid fa-gear mr-1" />
Settings
</button>
</li>
</ol>
</HamburgerMenu>
{#if previousPage && $page.url.pathname !== '/'}
<IconButton on:click={() => history.back()}>
<i slot="icon" class="fa-solid fa-arrow-left text-xl" />
</IconButton>
{/if}
{#if $page.url.pathname !== '/'}
<IconButton on:click={() => goto('/')}>
<i slot="icon" class="fa-solid fa-house text-xl" />
</IconButton>
{/if}
</div>
<SearchBar />
</div>
{#if windowY > 0}
<div transition:fade={{ duration: 150 }} id="navbar-background" class="absolute left-0 top-0 -z-10 h-full w-full bg-neutral-925" />
<!-- This would be a cool place for personalization -->
{/if}
</nav>
@@ -0,0 +1,76 @@
<script>
let searchBar, searchInput
let searchOpen = false
let searchRecommendations = null
const toggleSearchMenu = (open) => {
searchOpen = open
if (open) {
searchBar.style.borderColor = 'rgb(100, 100, 100)'
searchRecommendations = ['Psycho Lily', 'Iceborn', 'HYPER4ID', 'Parousia', 'Ragnarok', 'Betwixt & Between']
} else {
searchBar.style.borderColor = 'transparent'
searchRecommendations = null
}
}
const triggerSearch = (searchQuery) => {
console.log(`Search for: ${searchQuery}`)
// Redirect To '/search' route with query parameter '?query=searchQuery'
}
</script>
<search
role="search"
bind:this={searchBar}
class="relative my-2.5 flex w-full items-center gap-2.5 justify-self-center rounded-full border-2 border-transparent px-4 py-1.5"
on:focusout={() => {
setTimeout(() => {
// This is a completely stupid thing you have to do, if there is not timeout, the active element will be the body of the document and not the newly focused element
if (!searchBar.contains(document.activeElement)) {
toggleSearchMenu(false)
}
}, 1)
}}
>
<button
on:click|preventDefault={(event) => {
if (searchInput.value.trim() === '') {
if (event.pointerType === 'mouse') toggleSearchMenu(!searchOpen)
if (searchOpen) searchInput.focus()
} else {
triggerSearch(searchInput.value)
}
}}
>
<i class="fa-solid fa-magnifying-glass transition-colors duration-200 hover:text-lazuli-primary" />
</button>
<input
bind:this={searchInput}
type="text"
name="search"
class="w-full bg-transparent outline-none"
placeholder="Let's find some music"
autocomplete="off"
on:focus={() => toggleSearchMenu(true)}
on:keypress={(event) => {
if (event.key === 'Enter') triggerSearch(searchInput.value)
}}
/>
{#if searchRecommendations}
<div class="absolute left-0 top-full flex w-full flex-col bg-neutral-950">
{#each searchRecommendations as recommendation}
<button class="w-full p-4 text-left" on:click|preventDefault={() => triggerSearch(recommendation)}>
{recommendation}
</button>
{/each}
</div>
{/if}
</search>
<style>
search {
background-color: rgba(100, 100, 100, 0.25);
}
</style>
+30
View File
@@ -0,0 +1,30 @@
<script>
export let toggled = false
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
let toggle, knob
const handleToggle = () => {
toggled = !toggled
if (toggled) {
toggle.style.backgroundColor = 'var(--lazuli-primary)'
knob.style.left = '100%'
knob.style.transform = 'translateX(-100%)'
} else {
toggle.style.backgroundColor = 'rgb(115, 115, 115)'
knob.style.left = 0
knob.style.transform = ''
}
dispatch('toggled', {
toggleState: toggled,
})
}
</script>
<button bind:this={toggle} aria-checked={toggle} role="checkbox" class="relative flex h-6 w-10 items-center rounded-full bg-neutral-500 transition-colors" on:click={handleToggle}>
<div bind:this={knob} class="absolute left-0 aspect-square h-full p-1 transition-all">
<div class="h-full w-full rounded-full bg-white"></div>
</div>
</button>