Improve menu swipe detection

This commit is contained in:
2026-02-26 14:47:23 +01:00
parent 00b432f3dc
commit 0851d16cac
2 changed files with 42 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
// Dead zone before the swipe action gets detected // Dead zone before the swipe action gets detected
const swipe_inital_offset = 25 const swipe_initial_offset = 25
// Amount of pixels after which the navigation triggers // Amount of pixels after which the navigation triggers
const swipe_trigger_offset = 75 const swipe_trigger_offset = 75
@@ -38,8 +38,8 @@ export const swipe_nav = (
// The cursor must have moved at least 50 pixels and three times as much // The cursor must have moved at least 50 pixels and three times as much
// on the x axis than the y axis for it to count as a swipe // on the x axis than the y axis for it to count as a swipe
if (abs_x > swipe_inital_offset && abs_y < abs_x / 3) { if (abs_x > swipe_initial_offset && abs_y < abs_x / 3) {
set_offset((abs_x - swipe_inital_offset) * neg, false) set_offset((abs_x - swipe_initial_offset) * neg, false)
} else { } else {
set_offset(0, true) set_offset(0, true)
} }

View File

@@ -18,8 +18,21 @@ import Tree from "./Tree.svelte";
import MenuEntry from "./MenuEntry.svelte"; import MenuEntry from "./MenuEntry.svelte";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
// The menu swipe will be detected if it was less than this much pixels from the
// screen edge
const screen_edge_offset = 50
// Dead zone before the swipe action gets detected
const swipe_dead_zone = screen_edge_offset/4
// If the screen is less wide than this, the menu will appear full screen
const min_screen_size_fullscreen_menu = 500
// If the screen is smaller than this the menu will be closed by default
const min_screen_size_menu_open = 800
onMount(() => { onMount(() => {
if (document.documentElement.clientWidth < 1000) { if (document.documentElement.clientWidth < min_screen_size_menu_open) {
menu_close() menu_close()
} }
@@ -33,21 +46,20 @@ onMount(() => {
}) })
}) })
// Dead zone before the swipe action gets detected
const swipe_initial_offset = 50
const min_screen_size_fullscreen_menu = 500
let menu: HTMLDivElement let menu: HTMLDivElement
let nav: HTMLElement let nav: HTMLElement
let dragging: boolean = false let dragging: boolean = false
let start_x: number let start_x: number
let start_y: number
let render_offset: number let render_offset: number
let initial_offset: number let initial_offset: number
const touchstart = (e: TouchEvent) => { const touchstart = (e: TouchEvent) => {
start_x = e.touches[0].clientX start_x = e.touches[0].clientX
start_y = e.touches[0].clientY
const rect = menu.getBoundingClientRect() const rect = menu.getBoundingClientRect()
if (start_x < Math.max(swipe_initial_offset, (rect.width+rect.left))) { if (start_x < Math.max(screen_edge_offset, (rect.width+rect.left))) {
dragging = true dragging = true
e.stopPropagation()
} }
render_offset = rect.left render_offset = rect.left
@@ -58,7 +70,19 @@ const touchmove = (e: TouchEvent) => {
if (!dragging) { if (!dragging) {
return return
} }
set_offset(initial_offset+(e.touches[0].clientX - start_x))
const x = e.touches[0].clientX - start_x
const y = e.touches[0].clientY - start_y
const abs_x = Math.abs(x)
const abs_y = Math.abs(y)
// The cursor must have moved at least swipe_dead_zone pixels and three
// times as much on the x axis than the y axis for it to count as a swipe
if (abs_x > swipe_dead_zone && abs_x / 3 > abs_y) {
set_offset(initial_offset+(x*2))
} else {
set_offset(initial_offset)
}
} }
const touchend = (e: TouchEvent) => { const touchend = (e: TouchEvent) => {
@@ -112,7 +136,7 @@ const menu_close = () => {
const set_offset = (off: number) => { const set_offset = (off: number) => {
render_offset = off render_offset = off
if (off > -swipe_initial_offset) { if (off > -swipe_dead_zone) {
// Clear the transformation if the offset is zero // Clear the transformation if the offset is zero
menu.style.transform = "" menu.style.transform = ""
} else { } else {
@@ -123,8 +147,11 @@ const set_offset = (off: number) => {
<svelte:window ontouchstart={touchstart} ontouchmove={touchmove} ontouchend={touchend}/> <svelte:window ontouchstart={touchstart} ontouchmove={touchmove} ontouchend={touchend}/>
<button class="button_toggle_navigation" onclick={toggle_menu}> <button class="menu_button" onclick={toggle_menu}>
<i class="icon">menu</i> <i class="icon">menu</i>
{#if $menu_is_open}
<span>Menu</span>
{/if}
</button> </button>
<div class="nav_container" bind:this={menu}> <div class="nav_container" bind:this={menu}>
@@ -225,7 +252,7 @@ const set_offset = (off: number) => {
background-repeat: var(--background_image_repeat, repeat); background-repeat: var(--background_image_repeat, repeat);
background-attachment: fixed; background-attachment: fixed;
} }
.button_toggle_navigation { .menu_button {
position: fixed; position: fixed;
backface-visibility: hidden; backface-visibility: hidden;
z-index: 10; z-index: 10;
@@ -236,10 +263,10 @@ const set_offset = (off: number) => {
margin: 0; margin: 0;
padding: 4px; padding: 4px;
border-radius: 0; border-radius: 0;
border-bottom-right-radius: 0px; border-bottom-right-radius: 4px;
border-bottom-right-radius: 2px;
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
} }
.nav_container { .nav_container {
flex: 0 0 auto; flex: 0 0 auto;
border-right: 1px solid var(--separator); border-right: 1px solid var(--separator);
@@ -259,8 +286,6 @@ const set_offset = (off: number) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 15em; width: 15em;
min-width: 10em;
max-width: 15em;
padding-top: 2em; padding-top: 2em;
} }
.nav > .button { .nav > .button {