fix: new tactic to display properly translated title and breadcrumb at page load

This commit is contained in:
axolotle 2024-08-21 20:41:45 +02:00
parent 6cf9fa3804
commit 55cdc2a3d7
3 changed files with 79 additions and 56 deletions

View file

@ -1,7 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { useInfos } from '@/composables/useInfos' import { useInfos } from '@/composables/useInfos'
const { breadcrumb } = useInfos() const { breadcrumb, updateHtmlTitle } = useInfos()
// Call this here to trigger title update at page load (with translation)
updateHtmlTitle()
</script> </script>
<template> <template>

View file

@ -1,19 +1,40 @@
import { createGlobalState, useLocalStorage } from '@vueuse/core' import { createGlobalState, useLocalStorage } from '@vueuse/core'
import { computed, ref } from 'vue' import { computed, ref, watch } from 'vue'
import type { import type {
RouteLocationNormalized, RouteLocationNormalized,
RouteLocationNormalizedLoaded, RouteLocationNormalizedLoaded,
RouteRecordNormalized, RouteMeta,
RouteParamsGeneric,
RouteRecordNameGeneric,
} from 'vue-router' } from 'vue-router'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import api from '@/api' import api from '@/api'
import { timeout } from '@/helpers/commons' import { timeout } from '@/helpers/commons'
import i18n from '@/i18n' import i18n from '@/i18n'
import type { CustomRoute } from '@/types/commons'
import { useDomains } from './data' import { useDomains } from './data'
import { useRequests, type ReconnectingArgs } from './useRequests' import { useRequests, type ReconnectingArgs } from './useRequests'
type BreadcrumbRoutes = {
name: RouteRecordNameGeneric
params: RouteParamsGeneric
args: RouteMeta['args']
}
function formatRoute({ name, params, args }: BreadcrumbRoutes) {
const { trad, param } = args
// if a traduction key string has been given and we also need to pass
// the route param as a variable.
if (trad && param) {
return i18n.global.t(trad, { [param]: params[param] })
} else if (trad) {
return i18n.global.t(trad)
} else if (param) {
return params[param] as string
}
return ''
}
export const useInfos = createGlobalState(() => { export const useInfos = createGlobalState(() => {
const router = useRouter() const router = useRouter()
@ -22,13 +43,60 @@ export const useInfos = createGlobalState(() => {
const connected = useLocalStorage('connected', false) const connected = useLocalStorage('connected', false)
const yunohost = ref<{ version: string; repo: string } | undefined>() const yunohost = ref<{ version: string; repo: string } | undefined>()
const routerKey = ref<string | undefined>() const routerKey = ref<string | undefined>()
const breadcrumb = ref<CustomRoute[]>([]) const breadcrumbRoutes = ref<BreadcrumbRoutes[]>([])
const breadcrumb = computed(() => {
return breadcrumbRoutes.value.map((to) => {
console.log(to)
return { to: { name: to.name }, text: formatRoute(to) }
})
})
const htmlTitle = computed(() => {
const bc = breadcrumb.value
if (bc.length === 0) {
const { name, params, meta } = router.currentRoute.value
return formatRoute({ name, params, args: meta.args || {} })
}
return (bc.length > 2 ? bc.slice(-2) : bc)
.map((route) => route.text)
.reverse()
.join(' / ')
})
const { maybeMainDomain } = useDomains() const { maybeMainDomain } = useDomains()
const ssoLink = computed(() => { const ssoLink = computed(() => {
return `//${maybeMainDomain.value ?? host.value}/yunohost/sso` return `//${maybeMainDomain.value ?? host.value}/yunohost/sso`
}) })
watch(router.currentRoute, (to) => {
updateRouterKey()
const routeNames =
to.meta.breadcrumb ||
to.matched
.slice()
.reverse()
.find((route) => route.meta.breadcrumb)?.meta.breadcrumb
if (!routeNames) {
breadcrumbRoutes.value = []
return
}
const allRoutes = router.getRoutes()
breadcrumbRoutes.value = routeNames.map((name) => {
const route = allRoutes.find((route) => route.name === name)
if (!route) {
throw Error(
`Route ${name}, declared in breadcrumd, cannot be found in routes.`,
)
}
return { name: to.name, params: to.params, args: route.meta.args || {} }
})
updateHtmlTitle()
})
// INIT // INIT
async function _checkInstall(retry = 2) { async function _checkInstall(retry = 2) {
@ -123,50 +191,9 @@ export const useInfos = createGlobalState(() => {
routerKey.value = `${to.name?.toString()}-${params.join('-')}` routerKey.value = `${to.name?.toString()}-${params.join('-')}`
} }
function updateBreadcrumb(to: RouteLocationNormalized) { function updateHtmlTitle() {
function getRouteNames(route: RouteLocationNormalized): string[] {
if (route.meta.breadcrumb) return route.meta.breadcrumb
const parentRoute = route.matched
.slice()
.reverse()
.find((route) => route.meta.breadcrumb)
return parentRoute?.meta.breadcrumb || []
}
function formatRoute(
route: RouteRecordNormalized | RouteLocationNormalized,
) {
const { trad, param } = route.meta.args || {}
let text = ''
// if a traduction key string has been given and we also need to pass
// the route param as a variable.
if (trad && param) {
text = i18n.global.t(trad, { [param]: to.params[param] })
} else if (trad) {
text = i18n.global.t(trad)
} else if (param) {
text = to.params[param] as string
}
return { to: { name: route.name! }, text }
}
const routeNames = getRouteNames(to)
const allRoutes = router.getRoutes()
breadcrumb.value = routeNames.map((name) => {
const route = allRoutes.find((route) => route.name === name)!
return formatRoute(route)
})
function getTitle(breadcrumb: CustomRoute[]) {
if (breadcrumb.length === 0) return formatRoute(to).text
return (breadcrumb.length > 2 ? breadcrumb.slice(-2) : breadcrumb)
.map((route) => route.text)
.reverse()
.join(' / ')
}
// Display a simplified breadcrumb as the document title. // Display a simplified breadcrumb as the document title.
document.title = `${getTitle(breadcrumb.value)} | ${i18n.global.t('yunohost_admin')}` document.title = `${htmlTitle.value} | ${i18n.global.t('yunohost_admin')}`
} }
return { return {
@ -183,7 +210,6 @@ export const useInfos = createGlobalState(() => {
login, login,
logout, logout,
tryToReconnect, tryToReconnect,
updateRouterKey, updateHtmlTitle,
updateBreadcrumb,
} }
}) })

View file

@ -51,10 +51,4 @@ router.beforeEach((to, from, next) => {
} }
}) })
router.afterEach((to) => {
const { updateRouterKey, updateBreadcrumb } = useInfos()
updateRouterKey(to)
updateBreadcrumb(to)
})
export default router export default router