mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
97 lines
2.2 KiB
Vue
97 lines
2.2 KiB
Vue
<script setup lang="ts">
|
|
import { BCardGroup } from 'bootstrap-vue-next'
|
|
import {
|
|
getCurrentInstance,
|
|
h,
|
|
nextTick,
|
|
onBeforeUnmount,
|
|
onBeforeUpdate,
|
|
onMounted,
|
|
ref,
|
|
} from 'vue'
|
|
|
|
// Implementation of the feed pattern
|
|
// https://www.w3.org/WAI/ARIA/apg/patterns/feed/
|
|
|
|
const props = withDefaults(defineProps<{ stacks?: number }>(), { stacks: 21 })
|
|
const slots = defineSlots<{
|
|
default: any
|
|
}>()
|
|
|
|
const busy = ref(false)
|
|
const range = ref(props.stacks)
|
|
const childrenCount = ref(slots.default()[0].children.length)
|
|
const feedElem = ref<InstanceType<typeof BCardGroup> | null>(null)
|
|
|
|
function getTopParent(prev: HTMLElement): HTMLElement {
|
|
return prev.parentElement === feedElem.value?.$el
|
|
? prev
|
|
: getTopParent(prev.parentElement!)
|
|
}
|
|
|
|
const i = getCurrentInstance()
|
|
function onScroll() {
|
|
const elem = feedElem.value?.$el
|
|
if (
|
|
window.innerHeight >
|
|
elem.clientHeight + elem.getBoundingClientRect().top - 200
|
|
) {
|
|
busy.value = true
|
|
range.value = Math.min(range.value + props.stacks, childrenCount.value)
|
|
nextTick().then(() => {
|
|
busy.value = false
|
|
})
|
|
}
|
|
}
|
|
|
|
function onKeydown(e: KeyboardEvent) {
|
|
if (['PageUp', 'PageDown'].includes(e.code)) {
|
|
e.preventDefault()
|
|
const key = e.code === 'PageUp' ? 'previous' : 'next'
|
|
const sibling = getTopParent(e.target as HTMLElement)[
|
|
`${key}ElementSibling`
|
|
] as HTMLElement | null
|
|
sibling?.focus()
|
|
sibling?.scrollIntoView({ block: 'center' })
|
|
}
|
|
// FIXME Add `Home` and `End` shorcuts
|
|
}
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('scroll', onScroll)
|
|
feedElem.value?.$el.addEventListener('keydown', onKeydown)
|
|
onScroll()
|
|
})
|
|
|
|
onBeforeUpdate(() => {
|
|
const children = slots.default()[0].children
|
|
if (childrenCount.value !== children.length) {
|
|
range.value = props.stacks
|
|
childrenCount.value = children.length
|
|
}
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
window.removeEventListener('scroll', onScroll)
|
|
feedElem.value?.$el.removeEventListener('keydown', onKeydown)
|
|
})
|
|
|
|
const root = () =>
|
|
h(
|
|
BCardGroup,
|
|
{
|
|
deck: true,
|
|
role: 'feed',
|
|
'aria-busy': busy.value,
|
|
ref: feedElem,
|
|
},
|
|
{
|
|
default: () => slots.default()[0].children.slice(0, range.value),
|
|
},
|
|
)
|
|
</script>
|
|
|
|
<template>
|
|
{{ busy }}
|
|
<root />
|
|
</template>
|