mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-02-24 08:48:47 +01:00
Experimental j,k,o,esc,backspace shortcuts
This commit is contained in:
parent
36a33e488b
commit
b12b0c588d
3 changed files with 92 additions and 0 deletions
|
@ -41,6 +41,7 @@ a.mention span {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
transition: opacity 0.1s ease-in-out;
|
transition: opacity 0.1s ease-in-out;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
.deck-container[hidden] {
|
.deck-container[hidden] {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Link } from 'preact-router/match';
|
import { Link } from 'preact-router/match';
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { InView } from 'react-intersection-observer';
|
import { InView } from 'react-intersection-observer';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
|
@ -71,6 +72,88 @@ function Home({ hidden }) {
|
||||||
|
|
||||||
const scrollableRef = useRef();
|
const scrollableRef = useRef();
|
||||||
|
|
||||||
|
useHotkeys('j', () => {
|
||||||
|
// focus on next status after active status
|
||||||
|
// Traverses .timeline li .status-link, focus on .status-link
|
||||||
|
const activeStatus = document.activeElement.closest('.status-link');
|
||||||
|
const activeStatusRect = activeStatus?.getBoundingClientRect();
|
||||||
|
if (
|
||||||
|
activeStatus &&
|
||||||
|
activeStatusRect.top < scrollableRef.current.clientHeight &&
|
||||||
|
activeStatusRect.bottom > 0
|
||||||
|
) {
|
||||||
|
const nextStatus = activeStatus.parentElement.nextElementSibling;
|
||||||
|
if (nextStatus) {
|
||||||
|
const statusLink = nextStatus.querySelector('.status-link');
|
||||||
|
if (statusLink) {
|
||||||
|
statusLink.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If active status is not in viewport, get the topmost status-link in viewport
|
||||||
|
const statusLinks = document.querySelectorAll(
|
||||||
|
'.timeline li .status-link',
|
||||||
|
);
|
||||||
|
let topmostStatusLink;
|
||||||
|
for (const statusLink of statusLinks) {
|
||||||
|
const statusLinkRect = statusLink.getBoundingClientRect();
|
||||||
|
if (statusLinkRect.top >= 44) {
|
||||||
|
// 44 is the magic number for header height, not real
|
||||||
|
topmostStatusLink = statusLink;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (topmostStatusLink) {
|
||||||
|
topmostStatusLink.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeys('k', () => {
|
||||||
|
// focus on previous status after active status
|
||||||
|
// Traverses .timeline li .status-link, focus on .status-link
|
||||||
|
const activeStatus = document.activeElement.closest('.status-link');
|
||||||
|
const activeStatusRect = activeStatus?.getBoundingClientRect();
|
||||||
|
if (
|
||||||
|
activeStatus &&
|
||||||
|
activeStatusRect.top < scrollableRef.current.clientHeight &&
|
||||||
|
activeStatusRect.bottom > 0
|
||||||
|
) {
|
||||||
|
const prevStatus = activeStatus.parentElement.previousElementSibling;
|
||||||
|
if (prevStatus) {
|
||||||
|
const statusLink = prevStatus.querySelector('.status-link');
|
||||||
|
if (statusLink) {
|
||||||
|
statusLink.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If active status is not in viewport, get the topmost status-link in viewport
|
||||||
|
const statusLinks = document.querySelectorAll(
|
||||||
|
'.timeline li .status-link',
|
||||||
|
);
|
||||||
|
let topmostStatusLink;
|
||||||
|
for (const statusLink of statusLinks) {
|
||||||
|
const statusLinkRect = statusLink.getBoundingClientRect();
|
||||||
|
if (statusLinkRect.top >= 44) {
|
||||||
|
// 44 is the magic number for header height, not real
|
||||||
|
topmostStatusLink = statusLink;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (topmostStatusLink) {
|
||||||
|
topmostStatusLink.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeys(['enter', 'o'], () => {
|
||||||
|
// open active status
|
||||||
|
const activeStatus = document.activeElement.closest('.status-link');
|
||||||
|
if (activeStatus) {
|
||||||
|
activeStatus.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="home-page"
|
id="home-page"
|
||||||
|
@ -165,6 +248,8 @@ function Home({ hidden }) {
|
||||||
onChange={(inView) => {
|
onChange={(inView) => {
|
||||||
if (inView) loadStatuses();
|
if (inView) loadStatuses();
|
||||||
}}
|
}}
|
||||||
|
root={scrollableRef.current}
|
||||||
|
rootMargin="100px 0px"
|
||||||
>
|
>
|
||||||
<Status skeleton />
|
<Status skeleton />
|
||||||
</InView>
|
</InView>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import './status.css';
|
import './status.css';
|
||||||
|
|
||||||
import debounce from 'just-debounce-it';
|
import debounce from 'just-debounce-it';
|
||||||
|
import { route } from 'preact-router';
|
||||||
import { Link } from 'preact-router/match';
|
import { Link } from 'preact-router/match';
|
||||||
import {
|
import {
|
||||||
useEffect,
|
useEffect,
|
||||||
|
@ -9,6 +10,7 @@ import {
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'preact/hooks';
|
} from 'preact/hooks';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { InView } from 'react-intersection-observer';
|
import { InView } from 'react-intersection-observer';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
|
@ -278,6 +280,10 @@ function StatusPage({ id }) {
|
||||||
return top > 0 ? 'down' : 'up';
|
return top > 0 ? 'down' : 'up';
|
||||||
}, [heroInView]);
|
}, [heroInView]);
|
||||||
|
|
||||||
|
useHotkeys(['esc', 'backspace'], () => {
|
||||||
|
route(closeLink);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="deck-backdrop">
|
<div class="deck-backdrop">
|
||||||
<Link href={closeLink}></Link>
|
<Link href={closeLink}></Link>
|
||||||
|
|
Loading…
Reference in a new issue