Improved navigation and navbar
This commit is contained in:
@@ -1,36 +1,84 @@
|
||||
<script lang="ts">
|
||||
import I18n from './lib/components/Lang/I18n.svelte';
|
||||
import { Link, Route, Router } from 'svelte-navigator';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { Link, navigate, Route, Router } from 'svelte-navigator';
|
||||
import { Container, handleKeyboardNavigation } from './lib/actions/focusAction';
|
||||
import HomePage from './lib/pages/HomePage.svelte';
|
||||
import SeriesPage from './lib/pages/SeriesPage.svelte';
|
||||
import MoviesPage from './lib/pages/MoviesPage.svelte';
|
||||
import LibraryPage from './lib/pages/LibraryPage.svelte';
|
||||
import ManagePage from './lib/pages/ManagePage.svelte';
|
||||
import SearchPage from './lib/pages/SearchPage.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import classNames from 'classnames';
|
||||
import { Bookmark, CardStack, Gear, Laptop, MagnifyingGlass } from 'radix-icons-svelte';
|
||||
import NavbarItem from './lib/components-new/NavbarItem.svelte';
|
||||
|
||||
const mainContainer = new Container('main').setDirection('horizontal').setFocusByDefault(true);
|
||||
|
||||
const navBarContainer = mainContainer.createChild('nav').setDirection('vertical');
|
||||
const isNavBarOpen = navBarContainer.hasFocusWithin;
|
||||
|
||||
const contentContainer = mainContainer.createChild('content').setDirection('vertical');
|
||||
|
||||
const navBarRegisterer = navBarContainer.getRegisterer();
|
||||
onMount(() => navigate('series'));
|
||||
</script>
|
||||
|
||||
<I18n />
|
||||
<main class="bg-stone-950 text-white flex flex-1 w-screen">
|
||||
<Router>
|
||||
<nav class="border">
|
||||
<Link to="/">
|
||||
<div use:navBarRegisterer tabindex="0">Home</div>
|
||||
</Link>
|
||||
<nav
|
||||
class={classNames('flex flex-col', 'p-4', {
|
||||
border: $isNavBarOpen
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
<Link to="series" class="rounded-sm flex items-center">
|
||||
<div class="rounded-full bg-amber-300 h-4 w-4 mr-2" />
|
||||
<h1 class="font-display uppercase font-semibold tracking-wider text-xl">Reiverr</h1>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Link to="library">
|
||||
<div use:navBarRegisterer tabindex="0">Library</div>
|
||||
</Link>
|
||||
<div class="flex flex-col flex-1 justify-center">
|
||||
<NavbarItem parentContainer={navBarContainer} to="series">
|
||||
<Laptop class="w-8 h-8 mr-3" slot="icon" />
|
||||
<span class="text-xl" slot="text"> Series</span>
|
||||
</NavbarItem>
|
||||
<NavbarItem parentContainer={navBarContainer} to="movies">
|
||||
<CardStack class="w-8 h-8 mr-3" slot="icon" />
|
||||
<span class="text-xl" slot="text"> Movies</span>
|
||||
</NavbarItem>
|
||||
<NavbarItem parentContainer={navBarContainer} to="library">
|
||||
<Bookmark class="w-8 h-8 mr-3" slot="icon" />
|
||||
<span class="text-xl" slot="text"> Library</span>
|
||||
</NavbarItem>
|
||||
<NavbarItem parentContainer={navBarContainer} to="search">
|
||||
<MagnifyingGlass class="w-8 h-8 mr-3" slot="icon" />
|
||||
<span class="text-xl" slot="text"> Search</span>
|
||||
</NavbarItem>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<NavbarItem parentContainer={navBarContainer} to="manage">
|
||||
<Gear class="w-8 h-8 mr-3" slot="icon" />
|
||||
<span class="text-xl" slot="text"> Manage</span>
|
||||
</NavbarItem>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<Route path="/">
|
||||
<HomePage container={contentContainer} />
|
||||
<Route path="series">
|
||||
<SeriesPage container={contentContainer} />
|
||||
</Route>
|
||||
<Route path="movies">
|
||||
<MoviesPage container={contentContainer} />
|
||||
</Route>
|
||||
<Route path="library">
|
||||
<div transition:fade|global>about path</div>
|
||||
<LibraryPage container={contentContainer} />
|
||||
</Route>
|
||||
<Route path="manage">
|
||||
<ManagePage container={contentContainer} />
|
||||
</Route>
|
||||
<Route path="search">
|
||||
<SearchPage container={contentContainer} />
|
||||
</Route>
|
||||
</div>
|
||||
</Router>
|
||||
|
||||
@@ -142,7 +142,7 @@ export class Container {
|
||||
}
|
||||
}
|
||||
|
||||
getRegisterer(): Registerer {
|
||||
getChildRegisterer(): Registerer {
|
||||
return (htmlElement: HTMLElement) => {
|
||||
if (this.htmlElement) console.warn('Registering to a container that has an element.');
|
||||
|
||||
@@ -160,6 +160,35 @@ export class Container {
|
||||
};
|
||||
}
|
||||
|
||||
getHtmlElementRegisterer(): Registerer {
|
||||
return (htmlElement: HTMLElement) => {
|
||||
if (this.children.length > 0) {
|
||||
console.warn('Registering an html element to a container that has children.');
|
||||
for (const child of this.children) {
|
||||
this.removeChild(child);
|
||||
}
|
||||
}
|
||||
this.addHtmlElement(htmlElement);
|
||||
return {
|
||||
destroy: () => {
|
||||
this.removeHtmlElement();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
getStores(): {
|
||||
container: Container;
|
||||
hasFocus: Readable<boolean>;
|
||||
hasFocusWithin: Readable<boolean>;
|
||||
} {
|
||||
return {
|
||||
container: this,
|
||||
hasFocus: this.hasFocus,
|
||||
hasFocusWithin: this.hasFocusWithin
|
||||
};
|
||||
}
|
||||
|
||||
private addChild(child: Container) {
|
||||
this.children.push(child);
|
||||
child.parent = this;
|
||||
@@ -214,3 +243,5 @@ export function handleKeyboardNavigation(event: KeyboardEvent) {
|
||||
if (currentlyFocusedObject.giveFocus('right')) event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
export const focusedObject = Container.focusedObject;
|
||||
|
||||
31
src/lib/components-new/NavbarItem.svelte
Normal file
31
src/lib/components-new/NavbarItem.svelte
Normal file
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import Selectable from '../components/Selectable.svelte';
|
||||
import classNames from 'classnames';
|
||||
import { useNavigate } from 'svelte-navigator';
|
||||
import { get } from 'svelte/store';
|
||||
import { Container } from '../actions/focusAction';
|
||||
|
||||
export let to: string;
|
||||
export let parentContainer: Container;
|
||||
const { container, hasFocus } = parentContainer.createChild('navBarItem').getStores();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
function handleClick() {
|
||||
navigate(to);
|
||||
get(Container.focusedObject)?.giveFocus('right');
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={handleClick}>
|
||||
<Selectable {container}>
|
||||
<div
|
||||
class={classNames('flex items-center my-2', {
|
||||
'text-amber-200': $hasFocus
|
||||
})}
|
||||
>
|
||||
<slot name="icon" />
|
||||
<slot name="text" />
|
||||
</div>
|
||||
</Selectable>
|
||||
</button>
|
||||
@@ -13,7 +13,7 @@
|
||||
Container.focusedObject.subscribe((fo) => console.log('focusedObject', fo));
|
||||
carousel.hasFocus.subscribe((hf) => console.log('hasFocus', hf));
|
||||
|
||||
let registerer = carousel.getRegisterer();
|
||||
let registerer = carousel.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<p
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
<script lang="ts">
|
||||
export let;
|
||||
import { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
const registerer = container.getHtmlElementRegisterer();
|
||||
|
||||
export let handleClick = () => {
|
||||
container.focus();
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<button use:registerer tabindex="0" on:click={handleClick} class="outline-none ring-0">
|
||||
<slot />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
8
src/lib/pages/LibraryPage.svelte
Normal file
8
src/lib/pages/LibraryPage.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
let registerer = container.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<div use:registerer>LibraryPage</div>
|
||||
8
src/lib/pages/ManagePage.svelte
Normal file
8
src/lib/pages/ManagePage.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
let registerer = container.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<div use:registerer>ManagePage</div>
|
||||
8
src/lib/pages/MoviesPage.svelte
Normal file
8
src/lib/pages/MoviesPage.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
let registerer = container.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<div use:registerer>MoviesPage</div>
|
||||
8
src/lib/pages/SearchPage.svelte
Normal file
8
src/lib/pages/SearchPage.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
let registerer = container.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<div use:registerer>SearchPage</div>
|
||||
8
src/lib/pages/SeriesPage.svelte
Normal file
8
src/lib/pages/SeriesPage.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Container } from '../actions/focusAction';
|
||||
|
||||
export let container: Container;
|
||||
let registerer = container.getChildRegisterer();
|
||||
</script>
|
||||
|
||||
<div use:registerer>SeriesPage</div>
|
||||
Reference in New Issue
Block a user