Added a global error page to improve user experience during navigation issues, with localized messages and redirect options. Enhanced error handling for brand, product, and category slug composables by introducing explicit 404 responses. - Introduced `/error.vue` template for custom error displays using `NuxtError`. - Updated `useBrandBySlug`, `useProductBySlug`, `useCategoryBySlug` to throw 404 errors when data is not found. - Expanded i18n files (`en-gb.json` and `ru-ru.json`) with additional error-related translations. - Replaced plain text input with a `.search`-scoped class for cleaner styling. Enhances robustness and user feedback during navigation errors. No breaking changes introduced.
82 lines
No EOL
1.8 KiB
Vue
82 lines
No EOL
1.8 KiB
Vue
<script setup lang="ts">
|
|
import type { NuxtError } from '#app';
|
|
import {usePageTitle} from "@composables/utils";
|
|
|
|
const props = defineProps<{ error: NuxtError }>();
|
|
|
|
const {t} = useI18n();
|
|
const localePath = useLocalePath();
|
|
|
|
const { setPageTitle } = usePageTitle();
|
|
|
|
const handleError = () => {
|
|
clearError({ redirect: localePath('/') });
|
|
setTimeout(() => window.location.reload(), 500);
|
|
};
|
|
|
|
setPageTitle(props.error.status ?? t('errors.main'));
|
|
</script>
|
|
|
|
<template>
|
|
<div class="error">
|
|
<div class="container">
|
|
<client-only>
|
|
<div class="error__wrapper">
|
|
<h1 class="error__title">{{ error.status }}</h1>
|
|
<h6 class="error__subtitle">{{ error.status === 404 ? t('errors.pageNotFound') : error.statusText }}</h6>
|
|
<p class="error__text" v-if="error.status === 404">{{ t('errors.404') }}</p>
|
|
<ui-button
|
|
:type="'button'"
|
|
class="error__button"
|
|
@click="handleError"
|
|
>
|
|
{{ t('buttons.backToHome') }}
|
|
</ui-button>
|
|
</div>
|
|
</client-only>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.error {
|
|
height: 100vh;
|
|
background-color: $border;
|
|
padding-block: 60px;
|
|
|
|
&__wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
&__title {
|
|
font-family: "Playfair Display", sans-serif;
|
|
color: $primary;
|
|
font-size: 192px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
|
|
&__subtitle {
|
|
margin-block: 30px 20px;
|
|
font-family: "Playfair Display", sans-serif;
|
|
color: $primary;
|
|
font-size: 36px;
|
|
font-weight: 600;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
|
|
&__text {
|
|
color: $text;
|
|
font-size: 20px;
|
|
font-weight: 400;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
|
|
&__button {
|
|
margin-top: 30px;
|
|
padding-inline: 30px;
|
|
}
|
|
}
|
|
</style> |