convo/src/App.svelte
Badri Sunderarajan 26e344e28c
Set up OptionsMenu component with its own navigation
This navigation overrides the main navigation, making it act as a
modal. This is complicated, so let's not try to do it again
anywhere else besides these options menus :P

Well actually not that complicated, but it is a bit of duplicated
work and feels a little hacky so I'm not entirely comfortable with
it. Maybe there's a DRYer way to get it working though?
2024-03-24 16:44:57 +05:30

168 lines
4.4 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte'
import Router, { location, pop } from 'svelte-spa-router'
import SoftKey from './components/SoftKey.svelte'
import Home from './routes/Home.svelte'
import Login from './routes/Login.svelte'
import Messages from './routes/Messages.svelte'
import Contacts from './routes/Contacts.svelte'
import Chat from './routes/Chat.svelte'
import Redirect from './routes/Redirect.svelte'
import {
titleStore,
softkeysStore,
} from './stores.ts'
let title
titleStore.subscribe(value => title = value)
let softkeys
softkeysStore.subscribe(value => softkeys = value)
// Navigation
const routes = {
'/': Home,
'/login': Login,
'/messages': Messages,
'/contacts': Contacts,
'/chat/:chatID': Chat,
'*': Redirect,
}
// Go back
function goBack() {
// exit if we're on the main screen
if ($location === '/') {
window.close()
}
// otherwise, go back
pop()
}
// Account creation (or not)
function createAccount() {
alert('Unfortunately, you cannot create an account yet :(')
}
// For D-pad navigation
function nav(move) {
let currentIndex = document.activeElement.tabIndex
let next = currentIndex + move
let items = document.querySelectorAll('.focusable')
// Loop around if at end
if (next < 0) next = items.length - 1
if (next > items.length - 1) next = 0
let targetElement = items[next]
targetElement.focus()
}
/**
* Okay, so here's a slightly complicated function.
* What we're trying to do is scroll down (in the case
* of a long element that overflows the screen), or, if
* we've got to the end of that element, then to move on
* to the next one. This may not be the neatest way to
* do it but let's start with this and see how it goes...
*/
function navDown() {
// list.scrollTop > dong.offsetTop + dong.offsetHeight - (list.offsetHeight) // when this turns true, it means we've gone past
// Check if the parent scrolls
if (document.activeElement?.parentElement?.scrollTop > 0) {
// Yes it does! Okay, we've got to handle this carefully
let el = document.activeElement
let scrollEl = el.parentElement
// If we're already maxed out, time to navigate on
if (scrollEl.scrollTop == scrollEl.scrollTopMax) {
nav(1)
return
}
// First, scroll down a bit
scrollEl.scrollTop += scrollEl.offsetHeight * 0.5
// Now, check if we're still in view
if (scrollEl.scrollTop > // current scroll greater than
el.offsetTop // place where element starts
+ el.offsetHeight // plus height of element
- (scrollEl.offsetHeight * 0.4) // minus a wee bit
) {
// Now the previous thing's scrolled reasonably away
// so we can safely focus on the next one
nav(1)
// But let's just scroll back up a bit to make sure
// everything's still in view
scrollEl.scrollTop -= scrollEl.offsetHeight * 0.5
}
} else {
// Viewport not scrollable; just navigate without
// any funky stuff
nav(1)
}
}
// Key-down handler
function handleKeydown(e) {
switch(e.key) {
case 'ArrowUp':
nav(-1)
break
case 'ArrowDown':
navDown()
break
case 'SoftLeft':
case '[':
softkeys.left.callback()
break
case 'Enter':
softkeys.center.callback()
break
case 'SoftRight':
case ']':
softkeys.right.callback()
break
case 'Backspace':
goBack()
e.preventDefault()
break
}
}
// Listen for keys
document
.addEventListener('keydown', handleKeydown)
// Get rid of the splash screen
onMount(() => {
let splash = document.getElementById('splash')
if (splash) splash.remove()
})
</script>
<main id="app">
<div id="header">
<div name="header">{title}</div>
</div>
<div id="content">
<Router {routes}/>
</div>
<div class="softkeys">
{#if softkeys.left && softkeys.left.label}
<SoftKey side="left">{softkeys.left.label}</SoftKey>
{/if}
{#if softkeys.center && softkeys.center.label}
<SoftKey side="center">{softkeys.center.label}</SoftKey>
{/if}
{#if softkeys.right && softkeys.right.label}
<SoftKey side="right">{softkeys.right.label}</SoftKey>
{/if}
</div>
</main>