Added catch layout for error pages
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
type HeadingLevel = "h1" | "h2" | "h3"
|
type HeadingLevel = "h0" | "h1" | "h2" | "h3"
|
||||||
|
|
||||||
interface HeadingProps {
|
interface HeadingProps {
|
||||||
level?: HeadingLevel
|
level?: HeadingLevel
|
||||||
@@ -11,13 +11,16 @@ withDefaults(defineProps<HeadingProps>(), {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1 v-if="level === 'h1'" class="text-4xl font-bold flex">
|
<h1 v-if="level === 'h0'" class="text-4xl md:text-6xl font-bold flex">
|
||||||
<slot />
|
<slot />
|
||||||
</h1>
|
</h1>
|
||||||
<h2 v-else-if="level === 'h2'" class="text-2xl font-bold flex">
|
<h1 v-else-if="level === 'h1'" class="text-2xl md:text-4xl font-bold flex">
|
||||||
|
<slot />
|
||||||
|
</h1>
|
||||||
|
<h2 v-else-if="level === 'h2'" class="text-xl md:text-2xl font-bold flex">
|
||||||
<slot />
|
<slot />
|
||||||
</h2>
|
</h2>
|
||||||
<h3 v-if="level === 'h3'" class="text-xl font-bold flex">
|
<h3 v-if="level === 'h3'" class="text-lg md:text-xl font-bold flex">
|
||||||
<slot />
|
<slot />
|
||||||
</h3>
|
</h3>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
104
error.vue
Normal file
104
error.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { NuxtError } from "#app";
|
||||||
|
import { PhArrowBendDoubleUpLeft, PhBugBeetle, PhImageBroken, PhLinkBreak } from "@phosphor-icons/vue";
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
titleTemplate: (titleChunk) => {
|
||||||
|
return titleChunk ? `${titleChunk} — TTTools` : "TTTools";
|
||||||
|
},
|
||||||
|
meta: [
|
||||||
|
{ name: "charset", content: "UTF-8" },
|
||||||
|
{ name: "viewport", content: "width=device-width, initial-scale=1.0" },
|
||||||
|
{ name: "author", content: "Alexis Pelé" },
|
||||||
|
{ name: "generator", content: "Nuxt" },
|
||||||
|
{ name: "msapplication-TileColor", content: "00aba9" },
|
||||||
|
{ name: "theme-color", content: "00aba9" },
|
||||||
|
{ name: "og:type", content: "tabletop-tools" },
|
||||||
|
{ name: "og:url", content: "ttt.alexcreates.fr" },
|
||||||
|
{ name: "robots", content: "noindex, nofollow"}
|
||||||
|
],
|
||||||
|
link: [
|
||||||
|
{ rel: "apple-touch-icon", sizes: "76x76", href: "/apple-touch-icon.png" },
|
||||||
|
{ rel: "icon", sizes: "32x32", type: "image/png", href: "/favicon-32x32.png" },
|
||||||
|
{ rel: "icon", sizes: "16x16", type: "image/png", href: "/favicon-16x16.png" },
|
||||||
|
{ rel: "manifest", href: "/site.webmanifest" },
|
||||||
|
{ rel: "mask-icon", href: "/safari-pinned-tab.svg", color: "#6595b4" },
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
// eslint-disable-next-line vue/require-default-prop
|
||||||
|
error: Object as () => NuxtError
|
||||||
|
})
|
||||||
|
|
||||||
|
const { statusCode } = props.error!
|
||||||
|
|
||||||
|
let titleKey: string
|
||||||
|
let descriptionKey: string
|
||||||
|
let subDescriptionKey: string
|
||||||
|
|
||||||
|
switch (statusCode) {
|
||||||
|
case 404:
|
||||||
|
titleKey = "error.notFound.title"
|
||||||
|
descriptionKey = "error.notFound.descriptionMain"
|
||||||
|
subDescriptionKey = "error.notFound.descriptionSub"
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 500:
|
||||||
|
titleKey = "error.unknownServer.title"
|
||||||
|
descriptionKey = "error.unknownServer.descriptionMain"
|
||||||
|
subDescriptionKey = "error.unknownServer.descriptionSub"
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
titleKey = "error.default.title"
|
||||||
|
descriptionKey = "error.default.descriptionMain"
|
||||||
|
subDescriptionKey = "error.default.descriptionSub"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="h-screen">
|
||||||
|
<div class="h-full grid grid-cols-[auto_1fr] dark:bg-black transition-colors">
|
||||||
|
<Sidebar />
|
||||||
|
|
||||||
|
<div class="wrapper shadow-body-light dark:shadow-body-dark transition-all">
|
||||||
|
<div class="h-full w-full grid place-items-center">
|
||||||
|
<Head>
|
||||||
|
<Title>{{ $t(titleKey) }}</Title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<div class="grid justify-items-center opacity-80">
|
||||||
|
<PhImageBroken v-if="statusCode === 404" size="100" class="opacity-60" />
|
||||||
|
<PhLinkBreak v-else-if="statusCode === 500" size="100" class="opacity-60" />
|
||||||
|
<PhBugBeetle v-else size="100" class="opacity-60" />
|
||||||
|
|
||||||
|
<Heading level="h0">
|
||||||
|
{{ $t(titleKey) }}
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<div class="mt-6 md:text-lg text-center">
|
||||||
|
<p>{{ $t(descriptionKey) }}</p>
|
||||||
|
<p>{{ $t(subDescriptionKey) }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UiButton variant="default" class="mt-6 gap-2" as-child>
|
||||||
|
<RouterLink to="/">
|
||||||
|
<PhArrowBendDoubleUpLeft size="24" />
|
||||||
|
|
||||||
|
{{ $t('ui.backToHome') }}
|
||||||
|
</RouterLink>
|
||||||
|
</UiButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.wrapper > * {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,23 @@ export default defineI18nConfig(() => ({
|
|||||||
title: "Fantasy calendars for TTRPGs",
|
title: "Fantasy calendars for TTRPGs",
|
||||||
description: "Tools for players and game masters to help them visualize fantasy worlds better.",
|
description: "Tools for players and game masters to help them visualize fantasy worlds better.",
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
default: {
|
||||||
|
title: "An error occured",
|
||||||
|
description: "An error occured while loading the page.",
|
||||||
|
descriptionSub: "Please try again later or contact the administrator !"
|
||||||
|
},
|
||||||
|
notFound: {
|
||||||
|
title: "Page not found",
|
||||||
|
description: "The page you're looking for doesn't exist.",
|
||||||
|
descriptionSub: "Maybe it has been deleted or moved ?"
|
||||||
|
},
|
||||||
|
unknownServer: {
|
||||||
|
title: "Internal server error",
|
||||||
|
description: "An error occured while loading the page.",
|
||||||
|
descriptionSub: "Please try again later or contact the administrator !"
|
||||||
|
},
|
||||||
|
},
|
||||||
ui: {
|
ui: {
|
||||||
action: {
|
action: {
|
||||||
back: "Back",
|
back: "Back",
|
||||||
@@ -49,6 +66,7 @@ export default defineI18nConfig(() => ({
|
|||||||
greeting: "Connected as {user}",
|
greeting: "Connected as {user}",
|
||||||
anonymousGreeting: "Preferences",
|
anonymousGreeting: "Preferences",
|
||||||
backToProfile: "Back to profile",
|
backToProfile: "Back to profile",
|
||||||
|
backToHome: "Back to home",
|
||||||
sidebarMenu: {
|
sidebarMenu: {
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
appearance: "Appearance",
|
appearance: "Appearance",
|
||||||
@@ -273,6 +291,23 @@ export default defineI18nConfig(() => ({
|
|||||||
title: "Calendriers fantasies pour JDR",
|
title: "Calendriers fantasies pour JDR",
|
||||||
description: "Outils destinés aux joueurs et maîtres de jeux pour visualiser plus facilement leurs univers.",
|
description: "Outils destinés aux joueurs et maîtres de jeux pour visualiser plus facilement leurs univers.",
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
default: {
|
||||||
|
title: "Une erreur est survenue",
|
||||||
|
descriptionMain: "Une erreur est survenue lors du chargement de la page.",
|
||||||
|
descriptionSub: "Merci de rééssayer plus tard ou de contacter l'administrateur !"
|
||||||
|
},
|
||||||
|
notFound: {
|
||||||
|
title: "Page introuvable",
|
||||||
|
descriptionMain: "La page que vous cherchez n'existe pas.",
|
||||||
|
descriptionSub: "Peut-être a t-elle été supprimée ou déplacée ?"
|
||||||
|
},
|
||||||
|
unknownServer: {
|
||||||
|
title: "Une erreur du serveur est survenue",
|
||||||
|
descriptionMain: "Une erreur est survenue lors du chargement de la page.",
|
||||||
|
descriptionSub: "Merci de rééssayer plus tard ou de contacter l'administrateur !"
|
||||||
|
},
|
||||||
|
},
|
||||||
ui: {
|
ui: {
|
||||||
action: {
|
action: {
|
||||||
back: "Retour",
|
back: "Retour",
|
||||||
@@ -314,6 +349,7 @@ export default defineI18nConfig(() => ({
|
|||||||
greeting: "Connecté en tant que {user}",
|
greeting: "Connecté en tant que {user}",
|
||||||
anonymousGreeting: "Préférences",
|
anonymousGreeting: "Préférences",
|
||||||
backToProfile: "Retour au profil",
|
backToProfile: "Retour au profil",
|
||||||
|
backToHome: "Retourner à l'accueil",
|
||||||
sidebarMenu: {
|
sidebarMenu: {
|
||||||
profile: "Profil",
|
profile: "Profil",
|
||||||
appearance: "Apparence",
|
appearance: "Apparence",
|
||||||
|
|||||||
Reference in New Issue
Block a user