Merge pull request #489 from SamR1/calendar-keyboard-navigation

handle keyboard navigation on calendar
This commit is contained in:
Sam 2024-02-04 14:24:43 +01:00 committed by GitHub
commit 37faf06205
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 113 additions and 47 deletions

View File

@ -7,11 +7,11 @@
<link rel="stylesheet" href="/static/css/fork-awesome.min.css"/>
<link rel="stylesheet" href="/static/css/leaflet.css"/>
<title>FitTrackee</title>
<script type="module" crossorigin src="/static/index-QmYZ8SSf.js"></script>
<script type="module" crossorigin src="/static/index-SWko0ePt.js"></script>
<link rel="modulepreload" crossorigin href="/static/charts-_RwsDDkL.js">
<link rel="modulepreload" crossorigin href="/static/maps-ZyuCPqes.js">
<link rel="stylesheet" crossorigin href="/static/css/maps-B7qTrBCW.css">
<link rel="stylesheet" crossorigin href="/static/css/index-ZuVoSwX6.css">
<link rel="stylesheet" crossorigin href="/static/css/index-tZL8_Oa6.css">
</head>
<body>
<div id="app"></div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@
:workouts="filterWorkouts(day, workouts)"
:sports="sports"
:displayHARecord="displayHARecord"
:index="i"
/>
<div class="calendar-cell-day">
{{ format(day, 'd') }}

View File

@ -1,9 +1,7 @@
<template>
<div
<router-link
class="calendar-workout"
@click="
$router.push({ name: 'Workout', params: { workoutId: workout.id } })
"
:to="{ name: 'Workout', params: { workoutId: workout.id } }"
>
<SportImage
:sport-label="sportLabel"
@ -26,7 +24,7 @@
"
/>
</sup>
</div>
</router-link>
</template>
<script setup lang="ts">

View File

@ -21,6 +21,7 @@
:datasets="chartDatasets"
:colors="colors"
:displayHARecord="displayHARecord"
:index="index"
/>
</div>
</div>
@ -32,6 +33,7 @@
:datasets="chartDatasets"
:colors="colors"
:displayHARecord="displayHARecord"
:index="index"
/>
</div>
</div>
@ -52,10 +54,11 @@
displayHARecord: boolean
workouts: IWorkout[]
sports: ISport[]
index: number
}
const props = defineProps<Props>()
const { displayHARecord, workouts, sports } = toRefs(props)
const { displayHARecord, index, sports, workouts } = toRefs(props)
const chartDatasets = computed(() => getDonutDatasets(props.workouts))
const colors = computed(() => sportIdColors(props.sports))
const displayedWorkoutCount = 6

View File

@ -1,16 +1,22 @@
<template>
<div class="calendar-workouts-chart">
<div class="workouts-chart" @click="togglePane">
<button
class="workouts-chart transparent"
:id="`workouts-donut-${index}`"
@click="togglePane"
>
<div class="workouts-count">{{ workouts.length }}</div>
<DonutChart :datasets="datasets" :colors="colors" />
</div>
</button>
<div class="workouts-pane" v-if="!isHidden">
<div class="more-workouts" v-click-outside="togglePane">
<i
class="fa fa-times calendar-more"
aria-hidden="true"
@click="togglePane"
/>
<div
class="more-workouts"
:id="`workouts-pane-${index}`"
v-click-outside="togglePane"
>
<button class="calendar-more-close transparent" @click="togglePane">
<i class="fa fa-times" aria-hidden="true" />
</button>
<CalendarWorkout
v-for="(workout, index) in workouts"
:key="index"
@ -25,7 +31,7 @@
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { nextTick, onMounted, onUnmounted, ref, toRefs } from 'vue'
import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
import DonutChart from '@/components/Dashboard/UserCalendar/DonutChart.vue'
@ -39,16 +45,71 @@
sports: ISport[]
workouts: IWorkout[]
displayHARecord: boolean
index: number
}
const props = defineProps<Props>()
let tabbableElementIndex = 0
const { colors, datasets, sports, workouts } = toRefs(props)
const { colors, datasets, index, sports, workouts } = toRefs(props)
const isHidden = ref(true)
function togglePane(event: Event) {
function isWorkoutsMorePaneDisplayed() {
const pane = document.getElementById(`workouts-pane-${index.value}`)
return pane?.children && pane?.children.length > 0 ? pane : null
}
async function togglePane(event: Event) {
event.preventDefault()
event.stopPropagation()
isHidden.value = !isHidden.value
await nextTick()
const pane = isWorkoutsMorePaneDisplayed()
if (!isHidden.value) {
;(pane?.children[0] as HTMLButtonElement).focus()
} else {
document.getElementById(`workouts-donut-${index.value}`)?.focus()
}
}
function handleKey(e: KeyboardEvent) {
if (!isHidden.value) {
// focusTrap
if (!isHidden.value && (e.key === 'Tab' || e.keyCode === 9)) {
e.preventDefault()
e.stopPropagation()
const pane = isWorkoutsMorePaneDisplayed()
if (pane) {
if (e.shiftKey) {
tabbableElementIndex -= 1
if (tabbableElementIndex < 0) {
tabbableElementIndex = pane.children.length - 1
}
} else {
tabbableElementIndex += 1
if (tabbableElementIndex >= pane.children.length) {
tabbableElementIndex = 0
}
}
// children are only links or buttons
;(
pane.children[tabbableElementIndex] as
| HTMLButtonElement
| HTMLLinkElement
).focus()
}
}
// close pane on Escape
if (e.key === 'Escape') {
togglePane(e)
}
}
}
onMounted(() => {
document.addEventListener('keydown', handleKey)
})
onUnmounted(() => {
document.removeEventListener('keydown', handleKey)
})
</script>
<style lang="scss" scoped>
@ -58,6 +119,7 @@
.workouts-chart {
position: relative;
padding: 0;
.workouts-count {
display: flex;
justify-content: center;
@ -108,11 +170,12 @@
flex-wrap: wrap;
z-index: 1000;
.calendar-more {
.calendar-more-close {
position: absolute;
font-size: 0.9em;
top: 5px;
right: 5px;
padding: 0;
}
}
}

View File

@ -95,6 +95,7 @@ button {
&.transparent {
font-family: 'PT Sans', Helvetica, Arial, sans-serif;
font-size: 1em;
background: transparent;
border-color: transparent;
box-shadow: none;