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 SiteNav from '$components/chrome/SiteNav.svelte'
|
||||
import SiteFooter from '$components/chrome/SiteFooter.svelte'
|
||||
import RefreshHotkey from '$components/common/RefreshHotkey.svelte'
|
||||
import Home from '$routes/Home.svelte'
|
||||
import Profile from '$routes/Profile.svelte'
|
||||
import Timeline from '$routes/Timeline.svelte'
|
||||
@@ -56,6 +57,8 @@
|
||||
)
|
||||
</script>
|
||||
|
||||
<RefreshHotkey />
|
||||
|
||||
<div class="site">
|
||||
<SiteHeader />
|
||||
<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