Skip to content

Commit

Permalink
Make the navigation configureable
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlurak committed Jun 24, 2024
1 parent daf9150 commit 4a5d692
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 2 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"open-holiday-js": "^1.0.3",
"svelte-bootstrap-icons": "^3.1.1",
"svelte-confetti": "^1.4.0",
"svelte-dnd-action": "^0.9.49",
"svelte-floating-ui": "^1.5.8",
"svocal": "^0.2.2",
"zod": "^3.23.5"
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/lib/components/layout/navigation/Navbar.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { navHeight } from '$lib/stores';
import { svocal } from '$lib/utils/store/svocal';
import { flip } from 'svelte/animate';
import NavigationButton from './NavigationButton.svelte';
const navEntries = svocal('settings.nav.entries');
Expand All @@ -20,8 +21,10 @@
</div>

<div class="flex w-full items-center justify-evenly sm:w-fit">
{#each $navEntries as navTarget}
<NavigationButton target={navTarget} />
{#each $navEntries as navTarget (navTarget)}
<span class="flex-1" animate:flip={{ duration: 300 }}>
<NavigationButton target={navTarget} />
</span>
{/each}
</div>
</nav>
Expand Down
60 changes: 60 additions & 0 deletions src/lib/components/settings/navigation/DropArea.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script lang="ts" context="module">
type ItemPool = {
name: NavigationTarget;
id: number;
};
</script>

<script lang="ts">
import { navbarEntries } from '$lib/constants/navbar';
import { dndzone } from 'svelte-dnd-action';
import NavbarSettingButton from './NavbarSettingButton.svelte';
import { flip } from 'svelte/animate';
import type { NavigationTarget } from '$lib/components/layout/navigation/types';
import { createEventDispatcher } from 'svelte';
export let items: ItemPool[];
export let flipDurationMs: number;
export let block = 0;
const dispatch = createEventDispatcher<{
final: ItemPool[];
}>();
</script>

<section
class="
flex flex-col gap-3
rounded px-4 py-3 outline outline-1 outline-zinc-300
dark:outline-zinc-600
"
use:dndzone={{
items,
flipDurationMs,
dropTargetStyle: {},
dragDisabled: items.length <= block
}}
on:consider={({ detail }) => {
items = detail.items;
}}
on:finalize={({ detail }) => {
items = detail.items;
dispatch('final', items);
}}
>
<div>
<slot name="pre-content" />
</div>

<div class="flex min-h-20 flex-wrap items-center justify-center gap-2">
{#each items as item (item.id)}
{@const obj = navbarEntries[item.name]}

<span animate:flip={{ duration: flipDurationMs }} class="flex-1">
<NavbarSettingButton label={obj.text} icon={obj.icon} />
</span>
{:else}
<slot name="empty" />
{/each}
</div>
</section>
52 changes: 52 additions & 0 deletions src/lib/components/settings/navigation/NavbarCustomizor.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script lang="ts" context="module">
const FLIP_DURATION = 300;
type ItemPool = {
name: NavigationTarget;
id: number;
};
const ITEM_POOL: ItemPool[] = (
['homework', 'calendar', 'notes', 'login', 'register', 'launcher'] as const
).map((name, id) => ({ name, id }));
function createItemsFromNames(names: NavigationTarget[]) {
return ITEM_POOL.filter(({ name }) => names.includes(name));
}
const isSelectedId = (id: number, selected: ItemPool[]) => !!selected.find((x) => x.id === id);
</script>

<script lang="ts">
import type { NavigationTarget } from '$lib/components/layout/navigation/types';
import { svocal } from '$lib/utils/store/svocal';
import { get } from 'svelte/store';
import DropArea from './DropArea.svelte';
import Store from '$lib/components/utils/Store.svelte';
import { i } from '$lib/i18n/store';
const selectedSvocal = svocal('settings.nav.entries');
let selectedPreview = createItemsFromNames(get(selectedSvocal));
let notSelectedPreview = ITEM_POOL.filter(({ id }) => !isSelectedId(id, selectedPreview));
</script>

<div class="flex flex-col gap-2 rounded px-4 py-2">
<DropArea
block={1}
flipDurationMs={FLIP_DURATION}
bind:items={selectedPreview}
on:final={({ detail }) => {
selectedSvocal.set(detail.map(({ name }) => name));
}}
>
<h4 slot="pre-content"><Store store={i('settings.general.nav.composer.your')} /></h4>
</DropArea>

<DropArea flipDurationMs={FLIP_DURATION} bind:items={notSelectedPreview}>
<h4 slot="pre-content"><Store store={i('settings.general.nav.composer.available')} /></h4>
<span class="text-gray-500" slot="empty">
<Store store={i('settings.general.nav.composer.empty')} />
</span>
</DropArea>
</div>
22 changes: 22 additions & 0 deletions src/lib/components/settings/navigation/NavbarSettingButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<svelte:options accessors />

<script lang="ts">
import Store from '$lib/components/utils/Store.svelte';
import { Icon } from 'svelte-hero-icons';
import type { Readable } from 'svelte/store';
import type { IconSource } from 'svelte-hero-icons';
export let label: Readable<string>;
export let icon: IconSource;
</script>

<div
class="
flex flex-col items-center gap-2 rounded-sm bg-zinc-200 bg-opacity-50 px-2 py-2 shadow outline outline-1 outline-zinc-300 backdrop-blur-md
dark:bg-zinc-700 dark:bg-opacity-50 dark:outline-zinc-600
"
>
<Icon src={icon} class="h-10 w-10" solid />

<Store store={label} />
</div>
3 changes: 3 additions & 0 deletions src/lib/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ const de = {
'settings.general': 'Allgemein',
'settings.general.nav': 'Navigation',
'settings.general.nav.texts': 'Texte in der Navigationsleiste anzeigen',
'settings.general.nav.composer.your': 'Deine Navigation',
'settings.general.nav.composer.available': 'Verfügbare Navigationseinheiten',
'settings.general.nav.composer.empty': 'Ziehe ein Rechteck hier her, um es zu aus der Navigation zu entfernen.',
'settings.general.calendar': 'Kalender',
'settings.general.calendar.weekStartsOn': 'Erster Tag der Woche',
'settings.general.assignments': 'Hausaufgaben',
Expand Down
3 changes: 3 additions & 0 deletions src/lib/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ const en = {
'settings.general': 'General',
'settings.general.nav': 'Navigation',
'settings.general.nav.texts': 'Texte in der Navigationsleiste anzeigen',
'settings.general.nav.composer.your': 'Your Navigation',
'settings.general.nav.composer.available': 'Available navigation units',
'settings.general.nav.composer.empty': 'Drag and drop one rectangle here to remove it from your navigation.',
'settings.general.calendar': 'Calendar',
'settings.general.calendar.weekStartsOn': 'First day of the week',
'settings.general.assignments': 'Assignments',
Expand Down
11 changes: 11 additions & 0 deletions src/lib/utils/dom/scroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { browser } from '$app/environment';

/**
* This function enables or disables scrolling on the entire document.
* @param isEnabled - A boolean value indicating whether scrolling should be enabled (true) or disabled (false).
*/
export function enableScrolling(isEnabled: boolean) {
if (!browser) return false;
document.body.style.overflow = isEnabled ? 'initial' : 'hidden';
return true;
}
6 changes: 6 additions & 0 deletions src/lib/utils/icons/navigationIcons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NavigationTarget } from "$lib/components/layout/navigation/types";
import type { IconSource } from "svelte-hero-icons"

export const iconMap: Record<NavigationTarget, IconSource> = {
login:
}
2 changes: 2 additions & 0 deletions src/routes/settings/general/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { readable } from 'svelte/store';
import { currentLang } from '$lib/stores';
import { Holiday } from 'open-holiday-js';
import NavbarCustomizor from '$lib/components/settings/navigation/NavbarCustomizor.svelte';
const navTexts = svocal('settings.nav.texts');
const weekStartsOn = svocal('settings.weekStartsOn');
Expand All @@ -34,6 +35,7 @@
<section class="flex flex-col gap-2">
<h3><Store store={i('settings.general.nav')} /></h3>

<NavbarCustomizor />
<BoolSetting label={i('settings.general.nav.texts')} bind:value={$navTexts} />
</section>

Expand Down

0 comments on commit 4a5d692

Please sign in to comment.