enh(NcContent): Add skip content buttons
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Родитель
1ad3480fac
Коммит
f482cf2ece
|
@ -313,6 +313,12 @@ msgstr ""
|
|||
msgid "Show password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Skip to app navigation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Skip to main content"
|
||||
msgstr ""
|
||||
|
||||
msgid "Smart Picker"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.1.0",
|
||||
"@linusborg/vue-simple-portal": "^0.1.5",
|
||||
"@nextcloud/auth": "^2.0.0",
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/browser-storage": "^0.3.0",
|
||||
|
@ -3472,6 +3473,17 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@linusborg/vue-simple-portal": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@linusborg/vue-simple-portal/-/vue-simple-portal-0.1.5.tgz",
|
||||
"integrity": "sha512-dq+oubEVW4UabBoQxmH97GiDa+F6sTomw4KcXFHnXEpw69rdkXFCxo1WzwuvWjoLiUVYJTyN1dtlUvTa50VcXg==",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/hast-util-table-cell-style": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.2.0.tgz",
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.1.0",
|
||||
"@linusborg/vue-simple-portal": "^0.1.5",
|
||||
"@nextcloud/auth": "^2.0.0",
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/browser-storage": "^0.3.0",
|
||||
|
|
|
@ -78,14 +78,14 @@ emit('toggle-navigation', {
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import NcAppNavigationToggle from '../NcAppNavigationToggle/index.js'
|
||||
import { useIsMobile } from '../../composables/useIsMobile/index.js'
|
||||
import { getTrapStack } from '../../utils/focusTrap.js'
|
||||
|
||||
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
|
||||
|
||||
import { createFocusTrap } from 'focus-trap'
|
||||
|
||||
import NcAppNavigationToggle from '../NcAppNavigationToggle/index.js'
|
||||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'NcAppNavigation',
|
||||
|
||||
|
@ -93,6 +93,14 @@ export default {
|
|||
NcAppNavigationToggle,
|
||||
},
|
||||
|
||||
// Injected from NcContent
|
||||
inject: {
|
||||
setHasAppNavigation: {
|
||||
default: () => () => Vue.util.warn('NcAppNavigation is not mounted inside NcContent, this is probably an error.'),
|
||||
from: 'NcContent:setHasAppNavigation',
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
/**
|
||||
* The aria label to describe the navigation
|
||||
|
@ -135,6 +143,7 @@ export default {
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.setHasAppNavigation(true)
|
||||
subscribe('toggle-navigation', this.toggleNavigationByEventBus)
|
||||
// Emit an event with the initial state of the navigation
|
||||
emit('navigation-toggled', {
|
||||
|
@ -150,6 +159,7 @@ export default {
|
|||
this.toggleFocusTrap()
|
||||
},
|
||||
unmounted() {
|
||||
this.setHasAppNavigation(false)
|
||||
unsubscribe('toggle-navigation', this.toggleNavigationByEventBus)
|
||||
this.focusTrap.deactivate()
|
||||
},
|
||||
|
@ -161,6 +171,14 @@ export default {
|
|||
* @param {boolean} [state] set the state instead of inverting the current one
|
||||
*/
|
||||
toggleNavigation(state) {
|
||||
// Early return if alreay in that state
|
||||
if (this.open === state) {
|
||||
emit('navigation-toggled', {
|
||||
open: this.open,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.open = (typeof state === 'undefined') ? !this.open : state
|
||||
const bodyStyles = getComputedStyle(document.body)
|
||||
const animationLength = parseInt(bodyStyles.getPropertyValue('--animation-quick')) || 100
|
||||
|
|
|
@ -28,6 +28,8 @@ This component provides the default container of all apps.
|
|||
It _MUST_ be used as the main wrapper of your app.
|
||||
It includes the Navigation, the App content and the Sidebar.
|
||||
|
||||
It also will set the skip content buttons needed for accessibility.
|
||||
|
||||
### Standard usage
|
||||
|
||||
```vue
|
||||
|
@ -72,22 +74,84 @@ It includes the Navigation, the App content and the Sidebar.
|
|||
<div id="content-vue"
|
||||
:class="`app-${appName.toLowerCase()}`"
|
||||
class="content">
|
||||
<!-- TODO: with vue3 the `selector` attribute needs to be changed to `to="#skip-actions"` -->
|
||||
<Teleport selector="#skip-actions">
|
||||
<div class="skip-actions">
|
||||
<NcButton type="primary" href="#app-content-vue">
|
||||
{{ t('Skip to main content') }}
|
||||
</NcButton>
|
||||
<NcButton v-show="hasAppNavigation"
|
||||
type="primary"
|
||||
href="#app-navigation-vue"
|
||||
@click.prevent="openAppNavigation">
|
||||
{{ t('Skip to app navigation') }}
|
||||
</NcButton>
|
||||
</div>
|
||||
</Teleport>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { t } from '../../l10n.js'
|
||||
|
||||
import NcButton from '../NcButton/NcButton.vue'
|
||||
// TODO: This is built-in for vue3 just drop the import
|
||||
import { Portal as Teleport } from '@linusborg/vue-simple-portal'
|
||||
|
||||
export default {
|
||||
name: 'NcContent',
|
||||
components: {
|
||||
NcButton,
|
||||
Teleport,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
'NcContent:setHasAppNavigation': this.setAppNavigation,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
appName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasAppNavigation: false,
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
const container = document.getElementById('skip-actions')
|
||||
if (container) {
|
||||
// clear default buttons
|
||||
container.innerHTML = ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
t,
|
||||
openAppNavigation() {
|
||||
emit('toggle-navigation', { open: true })
|
||||
this.$nextTick(() => {
|
||||
window.location.hash = 'app-navigation-vue'
|
||||
// we need to manually focus if the window location is already set to the app-navigation then it will not focus again
|
||||
document.getElementById('app-navigation-vue').focus()
|
||||
})
|
||||
},
|
||||
setAppNavigation(value) {
|
||||
this.hasAppNavigation = value
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skip-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
margin: var(--body-container-margin);
|
||||
|
|
Загрузка…
Ссылка в новой задаче