feat: custom error page (#178)

Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
Joaquín Sánchez 2022-11-28 10:01:14 +01:00 committed by GitHub
parent b8cadca717
commit 3b92b27cc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 42 deletions

31
app.vue
View file

@ -1,21 +1,8 @@
<script setup>
import { APP_NAME } from './constants'
const isDev = process.dev
const isPreview = window.location.hostname.includes('deploy-preview')
useHead({
titleTemplate: title => `${title ? `${title} | ` : ''}${APP_NAME}${isDev ? ' (dev)' : isPreview ? ' (preview)' : ''}`,
link: [
{ rel: 'icon', type: 'image/svg+png', href: isDev || isPreview ? '/favicon-dev.png' : '/favicon.png' },
],
})
usePageHeader()
// We want to trigger rerendering the page when account changes
const key = computed(() => useMasto().instances.config.url || 'default')
// eslint-disable-next-line no-unused-expressions
isDark.value
</script>
<template>
@ -27,19 +14,3 @@ isDark.value
id="teleport-end"
/>
</template>
<style>
html, body , #__nuxt{
height: 100vh;
margin: 0;
padding: 0;
}
html.dark {
color-scheme: dark;
}
html {
--at-apply: bg-base text-base;
}
</style>

View file

@ -0,0 +1,16 @@
import { APP_NAME } from '~/constants'
const isDev = process.dev
const isPreview = window.location.hostname.includes('deploy-preview')
export function usePageHeader() {
useHead({
titleTemplate: title => `${title ? `${title} | ` : ''}${APP_NAME}${isDev ? ' (dev)' : isPreview ? ' (preview)' : ''}`,
link: [
{ rel: 'icon', type: 'image/svg+png', href: isDev || isPreview ? '/favicon-dev.png' : '/favicon.png' },
],
})
// eslint-disable-next-line no-unused-expressions
isDark.value
}

57
error.vue Normal file
View file

@ -0,0 +1,57 @@
<script setup lang="ts">
import type { NuxtError } from '#app'
// prevent reactive update when clearing error
const { error } = defineProps<{
error: Partial<NuxtError>
}>()
usePageHeader()
// add more custom status codes messages here
const errorCodes: Record<number, string> = {
404: 'Page not found',
}
const defaultMessage = 'Something went wrong'
const message = error.message ?? errorCodes[error.statusCode!] ?? defaultMessage
const state = ref<'error' | 'reloading'>('error')
const reload = async () => {
state.value = 'reloading'
try {
if (!useMasto())
await loginTo(currentUser.value)
clearError({ redirect: currentUser.value ? '/home' : '/public' })
}
catch {
state.value = 'error'
}
}
</script>
<template>
<NuxtLoadingIndicator color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" />
<NuxtLayout>
<MainContent>
<template #title>
<span text-lg font-bold>Error</span>
</template>
<slot>
<form p5 grid gap-y-4 @submit="reload">
<div text-lg>
Something went wrong
</div>
<div text-secondary>
{{ message }}
</div>
<button flex items-center gap-2 justify-center btn-solid text-center :disabled="state === 'reloading'">
<span v-if="state === 'reloading'" i-ri:loader-2-fill animate-spin inline-block />
{{ state === 'reloading' ? 'Reloading' : 'Reload' }}
</button>
</form>
</slot>
</MainContent>
</NuxtLayout>
</template>

View file

@ -55,6 +55,12 @@ export default defineNuxtConfig({
translateApi: '',
},
},
nitro: {
prerender: {
crawlLinks: false,
routes: ['/200.html'],
},
},
app: {
keepalive: true,
},

View file

@ -2,6 +2,7 @@ import type { MastoClient } from 'masto'
import { currentUser } from '../composables/users'
export default defineNuxtPlugin(async () => {
let masto!: MastoClient
try {
const { query } = useRoute()
const user = typeof query.server === 'string' && typeof query.token === 'string'
@ -9,23 +10,22 @@ export default defineNuxtPlugin(async () => {
: currentUser.value
// TODO: improve upstream to make this synchronous (delayed auth)
const masto = await loginTo(user) as MastoClient
return {
provide: {
masto: shallowReactive({
replace(api: MastoClient) { this.api = api },
api: masto,
}),
},
}
masto = await loginTo(user)
}
catch {
// TODO: handle error
// Show error page when Mastodon server is down
throw createError({
showError({
fatal: true,
statusMessage: 'Could not log into account.',
})
}
return {
provide: {
masto: shallowReactive({
replace(api: MastoClient) { this.api = api },
api: masto,
}),
},
}
})

View file

@ -103,3 +103,17 @@ html {
background-position: 0 50%
}
}
html, body , #__nuxt{
height: 100vh;
margin: 0;
padding: 0;
}
html.dark {
color-scheme: dark;
}
html {
--at-apply: bg-base text-base;
}