mirror of
https://git.shipoclu.com/moon/plspace.git
synced 2026-08-13 02:42:30 +00:00
refresh
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
import SiteHeader from '$components/chrome/SiteHeader.svelte'
|
import SiteHeader from '$components/chrome/SiteHeader.svelte'
|
||||||
import SiteNav from '$components/chrome/SiteNav.svelte'
|
import SiteNav from '$components/chrome/SiteNav.svelte'
|
||||||
import SiteFooter from '$components/chrome/SiteFooter.svelte'
|
import SiteFooter from '$components/chrome/SiteFooter.svelte'
|
||||||
|
import RefreshHotkey from '$components/common/RefreshHotkey.svelte'
|
||||||
import Home from '$routes/Home.svelte'
|
import Home from '$routes/Home.svelte'
|
||||||
import Profile from '$routes/Profile.svelte'
|
import Profile from '$routes/Profile.svelte'
|
||||||
import Timeline from '$routes/Timeline.svelte'
|
import Timeline from '$routes/Timeline.svelte'
|
||||||
@@ -56,6 +57,8 @@
|
|||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<RefreshHotkey />
|
||||||
|
|
||||||
<div class="site">
|
<div class="site">
|
||||||
<SiteHeader />
|
<SiteHeader />
|
||||||
<SiteNav />
|
<SiteNav />
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
/**
|
||||||
|
* App-wide, deliberately invisible refresh shortcut.
|
||||||
|
*
|
||||||
|
* The action is injectable so this component can be tested without actually
|
||||||
|
* navigating, and editable controls are ignored so composing text is safe.
|
||||||
|
*/
|
||||||
|
interface Props {
|
||||||
|
onrefresh?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
let { onrefresh = () => window.location.reload() }: Props = $props()
|
||||||
|
|
||||||
|
function isEditable(target: EventTarget | null): boolean {
|
||||||
|
if (!(target instanceof Element)) return false
|
||||||
|
return Boolean(
|
||||||
|
target.closest(
|
||||||
|
'input, textarea, select, [contenteditable]:not([contenteditable="false"])',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(event: KeyboardEvent): void {
|
||||||
|
if (
|
||||||
|
event.defaultPrevented ||
|
||||||
|
event.repeat ||
|
||||||
|
event.isComposing ||
|
||||||
|
event.key.toLowerCase() !== 'r' ||
|
||||||
|
!event.shiftKey ||
|
||||||
|
event.altKey ||
|
||||||
|
event.ctrlKey ||
|
||||||
|
event.metaKey ||
|
||||||
|
isEditable(event.target)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
onrefresh()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window onkeydown={handleKeydown} />
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { fireEvent, render } from '@testing-library/svelte'
|
||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
import RefreshHotkey from './RefreshHotkey.svelte'
|
||||||
|
|
||||||
|
describe('RefreshHotkey', () => {
|
||||||
|
it('refreshes for Shift+R from anywhere on the page', async () => {
|
||||||
|
const onrefresh = vi.fn()
|
||||||
|
render(RefreshHotkey, { props: { onrefresh } })
|
||||||
|
|
||||||
|
const event = new KeyboardEvent('keydown', {
|
||||||
|
key: 'R',
|
||||||
|
shiftKey: true,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
})
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
|
||||||
|
expect(onrefresh).toHaveBeenCalledOnce()
|
||||||
|
expect(event.defaultPrevented).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ignores typing, repeats, and other modifier combinations', async () => {
|
||||||
|
const onrefresh = vi.fn()
|
||||||
|
render(RefreshHotkey, { props: { onrefresh } })
|
||||||
|
const input = document.createElement('input')
|
||||||
|
document.body.append(input)
|
||||||
|
|
||||||
|
await fireEvent.keyDown(input, { key: 'R', shiftKey: true })
|
||||||
|
await fireEvent.keyDown(window, { key: 'r' })
|
||||||
|
await fireEvent.keyDown(window, { key: 'R', shiftKey: true, repeat: true })
|
||||||
|
await fireEvent.keyDown(window, { key: 'R', shiftKey: true, ctrlKey: true })
|
||||||
|
await fireEvent.keyDown(window, { key: 'R', shiftKey: true, metaKey: true })
|
||||||
|
|
||||||
|
expect(onrefresh).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user