diff --git a/components/nav/NavTitle.vue b/components/nav/NavTitle.vue index e4a7e7d9..96be0a16 100644 --- a/components/nav/NavTitle.vue +++ b/components/nav/NavTitle.vue @@ -29,7 +29,7 @@ router.afterEach(() => { @click.prevent="onClickLogo" > <NavLogo shrink-0 aspect="1/1" sm:h-8 xl:h-10 class="rtl-flip" /> - <div hidden xl:block text-secondary> + <div v-show="isHydrated" hidden xl:block text-secondary> {{ $t('app_name') }} <sup text-sm italic mt-1>{{ env === 'release' ? 'alpha' : env }}</sup> </div> </NuxtLink> diff --git a/components/status/StatusDetails.vue b/components/status/StatusDetails.vue index d117c3eb..879d89a7 100644 --- a/components/status/StatusDetails.vue +++ b/components/status/StatusDetails.vue @@ -22,7 +22,7 @@ const createdAt = useFormattedDateTime(status.createdAt) const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${getDisplayName(status.account)} ${t('common.in')} ${t('app_name')}: "${removeHTMLTags(status.content) || ''}"`, }) diff --git a/composables/setups.ts b/composables/setups.ts index f977de61..d907eae5 100644 --- a/composables/setups.ts +++ b/composables/setups.ts @@ -12,7 +12,7 @@ export function setupPageHeader() { return acc }, {} as Record<string, Directions>) - useHead({ + useHydratedHead({ htmlAttrs: { lang: () => locale.value, dir: () => localeMap[locale.value] ?? 'ltr', @@ -23,6 +23,9 @@ export function setupPageHeader() { content: () => `width=device-width,initial-scale=1${enablePinchToZoom.value ? '' : ',maximum-scale=1,user-scalable=0'},viewport-fit=cover`, }], titleTemplate: (title) => { + if (!isHydrated) + return '' + let titleTemplate = title ?? '' if (titleTemplate.match(/&[a-z0-9#]+;/gi)) { diff --git a/pages/[[server]]/@[account]/index/followers.vue b/pages/[[server]]/@[account]/index/followers.vue index dcb4ebe4..691ae2fa 100644 --- a/pages/[[server]]/@[account]/index/followers.vue +++ b/pages/[[server]]/@[account]/index/followers.vue @@ -11,7 +11,7 @@ const paginator = account ? useMastoClient().v1.accounts.listFollowers(account.i const isSelf = useSelfAccount(account) if (account) { - useHead({ + useHydratedHead({ title: () => `${t('account.followers')} | ${getDisplayName(account)} (@${account.acct})`, }) } diff --git a/pages/[[server]]/@[account]/index/following.vue b/pages/[[server]]/@[account]/index/following.vue index b65f749d..173502b9 100644 --- a/pages/[[server]]/@[account]/index/following.vue +++ b/pages/[[server]]/@[account]/index/following.vue @@ -11,7 +11,7 @@ const paginator = account ? useMastoClient().v1.accounts.listFollowing(account.i const isSelf = useSelfAccount(account) if (account) { - useHead({ + useHydratedHead({ title: () => `${t('account.following')} | ${getDisplayName(account)} (@${account.acct})`, }) } diff --git a/pages/[[server]]/@[account]/index/index.vue b/pages/[[server]]/@[account]/index/index.vue index dacf716f..28179675 100644 --- a/pages/[[server]]/@[account]/index/index.vue +++ b/pages/[[server]]/@[account]/index/index.vue @@ -15,7 +15,7 @@ const reorderAndFilter = (items: mastodon.v1.Status[]) => reorderedTimeline(item const paginator = useMastoClient().v1.accounts.listStatuses(account.id, { limit: 30, excludeReplies: true }) if (account) { - useHead({ + useHydratedHead({ title: () => `${t('account.posts')} | ${getDisplayName(account)} (@${account.acct})`, }) } diff --git a/pages/[[server]]/@[account]/index/media.vue b/pages/[[server]]/@[account]/index/media.vue index 6db9760a..1ff955ac 100644 --- a/pages/[[server]]/@[account]/index/media.vue +++ b/pages/[[server]]/@[account]/index/media.vue @@ -10,7 +10,7 @@ const account = await fetchAccountByHandle(handle) const paginator = useMastoClient().v1.accounts.listStatuses(account.id, { onlyMedia: true, excludeReplies: false }) if (account) { - useHead({ + useHydratedHead({ title: () => `${t('tab.media')} | ${getDisplayName(account)} (@${account.acct})`, }) } diff --git a/pages/[[server]]/@[account]/index/with_replies.vue b/pages/[[server]]/@[account]/index/with_replies.vue index b5501c91..189a8d5f 100644 --- a/pages/[[server]]/@[account]/index/with_replies.vue +++ b/pages/[[server]]/@[account]/index/with_replies.vue @@ -10,7 +10,7 @@ const account = await fetchAccountByHandle(handle) const paginator = useMastoClient().v1.accounts.listStatuses(account.id, { excludeReplies: false }) if (account) { - useHead({ + useHydratedHead({ title: () => `${t('tab.posts_with_replies')} | ${getDisplayName(account)} (@${account.acct})`, }) } diff --git a/pages/[[server]]/explore/index.vue b/pages/[[server]]/explore/index.vue index df53e0be..56d825d0 100644 --- a/pages/[[server]]/explore/index.vue +++ b/pages/[[server]]/explore/index.vue @@ -7,7 +7,7 @@ const paginator = useMastoClient().v1.trends.listStatuses() const hideNewsTips = useLocalStorage(STORAGE_KEY_HIDE_EXPLORE_POSTS_TIPS, false) -useHead({ +useHydratedHead({ title: () => `${t('tab.posts')} | ${t('nav.explore')}`, }) </script> diff --git a/pages/[[server]]/explore/links.vue b/pages/[[server]]/explore/links.vue index 92b10309..bafcfbc2 100644 --- a/pages/[[server]]/explore/links.vue +++ b/pages/[[server]]/explore/links.vue @@ -7,7 +7,7 @@ const paginator = useMastoClient().v1.trends.listLinks() const hideNewsTips = useLocalStorage(STORAGE_KEY_HIDE_EXPLORE_NEWS_TIPS, false) -useHead({ +useHydratedHead({ title: () => `${t('tab.news')} | ${t('nav.explore')}`, }) </script> diff --git a/pages/[[server]]/explore/tags.vue b/pages/[[server]]/explore/tags.vue index dadbc5ed..d21aeb2a 100644 --- a/pages/[[server]]/explore/tags.vue +++ b/pages/[[server]]/explore/tags.vue @@ -10,7 +10,7 @@ const paginator = client.v1.trends.listTags({ const hideTagsTips = useLocalStorage(STORAGE_KEY_HIDE_EXPLORE_TAGS_TIPS, false) -useHead({ +useHydratedHead({ title: () => `${t('tab.hashtags')} | ${t('nav.explore')}`, }) </script> diff --git a/pages/[[server]]/explore/users.vue b/pages/[[server]]/explore/users.vue index b3080094..b711423d 100644 --- a/pages/[[server]]/explore/users.vue +++ b/pages/[[server]]/explore/users.vue @@ -4,7 +4,7 @@ const { t } = useI18n() // limit: 20 is the default configuration of the official client const paginator = useMastoClient().v2.suggestions.list({ limit: 20 }) -useHead({ +useHydratedHead({ title: () => `${t('tab.for_you')} | ${t('nav.explore')}`, }) </script> diff --git a/pages/[[server]]/list/[list]/index.vue b/pages/[[server]]/list/[list]/index.vue index 1780ebcf..05407553 100644 --- a/pages/[[server]]/list/[list]/index.vue +++ b/pages/[[server]]/list/[list]/index.vue @@ -35,7 +35,7 @@ const { client } = $(useMasto()) const { data: listInfo, refresh } = $(await useAsyncData(() => client.v1.lists.fetch(list), { default: () => shallowRef() })) if (listInfo) { - useHead({ + useHydratedHead({ title: () => `${listInfo.title} | ${route.fullPath.endsWith('/accounts') ? t('tab.accounts') : t('tab.posts')} | ${t('nav.lists')}`, }) } diff --git a/pages/[[server]]/lists.vue b/pages/[[server]]/lists.vue index 00f3372c..4db33cb8 100644 --- a/pages/[[server]]/lists.vue +++ b/pages/[[server]]/lists.vue @@ -11,7 +11,7 @@ const client = useMastoClient() const paginator = client.v1.lists.list() -useHead({ +useHydratedHead({ title: () => t('nav.lists'), }) diff --git a/pages/[[server]]/public/index.vue b/pages/[[server]]/public/index.vue index 077fa6b9..b8278efd 100644 --- a/pages/[[server]]/public/index.vue +++ b/pages/[[server]]/public/index.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('title.federated_timeline'), }) </script> diff --git a/pages/[[server]]/public/local.vue b/pages/[[server]]/public/local.vue index d04171ab..3aca1e64 100644 --- a/pages/[[server]]/public/local.vue +++ b/pages/[[server]]/public/local.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('title.local_timeline'), }) </script> diff --git a/pages/[[server]]/tags/[tag].vue b/pages/[[server]]/tags/[tag].vue index 847ae7f5..dfbc0cfe 100644 --- a/pages/[[server]]/tags/[tag].vue +++ b/pages/[[server]]/tags/[tag].vue @@ -13,7 +13,7 @@ const paginator = client.v1.timelines.listHashtag(tagName) const stream = useStreaming(client => client.v1.stream.streamTagTimeline(tagName)) if (tag) { - useHead({ + useHydratedHead({ title: () => `#${tag.name}`, }) } diff --git a/pages/blocks.vue b/pages/blocks.vue index 4e3b6015..df78355d 100644 --- a/pages/blocks.vue +++ b/pages/blocks.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.blocked_users'), }) </script> diff --git a/pages/bookmarks.vue b/pages/bookmarks.vue index 1d0ed886..efebad8c 100644 --- a/pages/bookmarks.vue +++ b/pages/bookmarks.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.bookmarks'), }) </script> diff --git a/pages/compose.vue b/pages/compose.vue index 656ca1fc..a21ad452 100644 --- a/pages/compose.vue +++ b/pages/compose.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.compose'), }) </script> diff --git a/pages/conversations.vue b/pages/conversations.vue index 5c17537b..f0ab6d40 100644 --- a/pages/conversations.vue +++ b/pages/conversations.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.conversations'), }) </script> diff --git a/pages/domain_blocks.vue b/pages/domain_blocks.vue index 663292b6..5f981c3e 100644 --- a/pages/domain_blocks.vue +++ b/pages/domain_blocks.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.blocked_domains'), }) </script> diff --git a/pages/favourites.vue b/pages/favourites.vue index 7f840e4b..e4458fbd 100644 --- a/pages/favourites.vue +++ b/pages/favourites.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.favourites'), }) </script> diff --git a/pages/home.vue b/pages/home.vue index 169244db..b25c85bf 100644 --- a/pages/home.vue +++ b/pages/home.vue @@ -10,7 +10,7 @@ if (process.client && route.path === '/signin/callback') router.push('/home') const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.home'), }) </script> diff --git a/pages/mutes.vue b/pages/mutes.vue index c1e0bda9..a9b5d242 100644 --- a/pages/mutes.vue +++ b/pages/mutes.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.muted_users'), }) </script> diff --git a/pages/notifications/index.vue b/pages/notifications/index.vue index e9873b95..99d18ebd 100644 --- a/pages/notifications/index.vue +++ b/pages/notifications/index.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('tab.notifications_all')} | ${t('nav.notifications')}`, }) </script> diff --git a/pages/notifications/mention.vue b/pages/notifications/mention.vue index 8a584914..7bf4369e 100644 --- a/pages/notifications/mention.vue +++ b/pages/notifications/mention.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> -const { t } = useI18n() -useHead({ +const { t, setLocale } = useI18n() +useHydratedHead({ title: () => `${t('tab.notifications_mention')} | ${t('nav.notifications')}`, }) </script> diff --git a/pages/pinned.vue b/pages/pinned.vue index f573c10f..5ea9c7c4 100644 --- a/pages/pinned.vue +++ b/pages/pinned.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('account.pinned'), }) </script> diff --git a/pages/settings.vue b/pages/settings.vue index 38c81872..aadccd79 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => t('nav.settings'), }) @@ -22,7 +22,7 @@ const isRootPath = computedEager(() => route.name === 'settings') <template #title> <div timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:settings-3-line /> - <span>{{ $t('nav.settings') }}</span> + <span>{{ isHydrated ? $t('nav.settings') : '' }}</span> </div> </template> <div xl:w-97 lg:w-78 w-full> @@ -37,7 +37,7 @@ const isRootPath = computedEager(() => route.name === 'settings') <SettingsItem command icon="i-ri-compasses-2-line" - :text="$t('settings.interface.label')" + :text="isHydrated ? $t('settings.interface.label') : ''" to="/settings/interface" :match="$route.path.startsWith('/settings/interface/')" /> @@ -52,28 +52,28 @@ const isRootPath = computedEager(() => route.name === 'settings') <SettingsItem command icon="i-ri-globe-line" - :text="$t('settings.language.label')" + :text="isHydrated ? $t('settings.language.label') : ''" to="/settings/language" :match="$route.path.startsWith('/settings/language/')" /> <SettingsItem command icon="i-ri-equalizer-line" - :text="$t('settings.preferences.label')" + :text="isHydrated ? $t('settings.preferences.label') : ''" to="/settings/preferences" :match="$route.path.startsWith('/settings/preferences/')" /> <SettingsItem command icon="i-ri-group-line" - :text="$t('settings.users.label')" + :text="isHydrated ? $t('settings.users.label') : ''" to="/settings/users" :match="$route.path.startsWith('/settings/users/')" /> <SettingsItem command icon="i-ri:information-line" - :text="$t('settings.about.label')" + :text="isHydrated ? $t('settings.about.label') : ''" to="/settings/about" :match="$route.path.startsWith('/settings/about/')" /> diff --git a/pages/settings/about/index.vue b/pages/settings/about/index.vue index 6f7cd7c1..d0a33538 100644 --- a/pages/settings/about/index.vue +++ b/pages/settings/about/index.vue @@ -2,7 +2,7 @@ const buildInfo = useBuildInfo() const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.about.label')} | ${t('nav.settings')}`, }) diff --git a/pages/settings/index.vue b/pages/settings/index.vue index c0ee6207..e3c4d759 100644 --- a/pages/settings/index.vue +++ b/pages/settings/index.vue @@ -2,7 +2,7 @@ <div min-h-screen flex justify-center items-center> <div text-center flex="~ col gap-2" items-center> <div i-ri:settings-3-line text-5xl /> - <span text-xl>{{ $t('settings.select_a_settings') }}</span> + <span text-xl>{{ isHydrated ? $t('settings.select_a_settings') : '' }}</span> </div> </div> </template> diff --git a/pages/settings/interface/index.vue b/pages/settings/interface/index.vue index 2ac20970..94ef7e97 100644 --- a/pages/settings/interface/index.vue +++ b/pages/settings/interface/index.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.interface.label')} | ${t('nav.settings')}`, }) </script> diff --git a/pages/settings/language/index.vue b/pages/settings/language/index.vue index 5f16bb11..2ff488ca 100644 --- a/pages/settings/language/index.vue +++ b/pages/settings/language/index.vue @@ -5,7 +5,7 @@ const { t, locale } = useI18n() const translationStatus: ElkTranslationStatus = await import('~/elk-translation-status.json').then(m => m.default) -useHead({ +useHydratedHead({ title: () => `${t('settings.language.label')} | ${t('nav.settings')}`, }) const status = computed(() => { diff --git a/pages/settings/notifications/index.vue b/pages/settings/notifications/index.vue index 80704319..af14ddf3 100644 --- a/pages/settings/notifications/index.vue +++ b/pages/settings/notifications/index.vue @@ -6,7 +6,7 @@ definePageMeta({ const { t } = useI18n() const pwaEnabled = useAppConfig().pwaEnabled -useHead({ +useHydratedHead({ title: () => `${t('settings.notifications.label')} | ${t('nav.settings')}`, }) </script> @@ -15,20 +15,20 @@ useHead({ <MainContent back-on-small-screen> <template #title> <div text-lg font-bold flex items-center gap-2 @click="$scrollToTop"> - <span>{{ $t('settings.notifications.label') }}</span> + <span>{{ isHydrated ? $t('settings.notifications.label') : '' }}</span> </div> </template> <SettingsItem command - :text="$t('settings.notifications.notifications.label')" + :text="isHydrated ? $t('settings.notifications.notifications.label') : ''" to="/settings/notifications/notifications" /> <SettingsItem command :disabled="!pwaEnabled" - :text="$t('settings.notifications.push_notifications.label')" - :description="$t('settings.notifications.push_notifications.description')" + :text="isHydrated ? $t('settings.notifications.push_notifications.label') : ''" + :description="isHydrated ? $t('settings.notifications.push_notifications.description') : ''" to="/settings/notifications/push-notifications" /> </MainContent> diff --git a/pages/settings/notifications/notifications.vue b/pages/settings/notifications/notifications.vue index e58ee448..22d30220 100644 --- a/pages/settings/notifications/notifications.vue +++ b/pages/settings/notifications/notifications.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.notifications.notifications.label')} | ${t('settings.notifications.label')} | ${t('nav.settings')}`, }) </script> @@ -14,14 +14,14 @@ useHead({ <MainContent back> <template #title> <div text-lg font-bold flex items-center gap-2 @click="$scrollToTop"> - <span>{{ $t('settings.notifications.notifications.label') }}</span> + <span>{{ isHydrated ? $t('settings.notifications.notifications.label') : '' }}</span> </div> </template> <h3 px6 py4 mt2 font-bold text-xl flex="~ gap-1" items-center> - {{ $t('settings.notifications.notifications.label') }} + {{ isHydrated ? $t('settings.notifications.notifications.label') : '' }} </h3> <p text-4xl text-center> - <span sr-only>{{ $t('settings.notifications.under_construction') }}</span> 🚧 + <span sr-only>{{ isHydrated ? $t('settings.notifications.under_construction') : '' }}</span> 🚧 </p> </MainContent> </template> diff --git a/pages/settings/notifications/push-notifications.vue b/pages/settings/notifications/push-notifications.vue index 5bf238cb..cae515c1 100644 --- a/pages/settings/notifications/push-notifications.vue +++ b/pages/settings/notifications/push-notifications.vue @@ -8,7 +8,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.notifications.push_notifications.label')} | ${t('settings.notifications.label')} | ${t('nav.settings')}`, }) </script> @@ -17,7 +17,7 @@ useHead({ <MainContent back> <template #title> <div text-lg font-bold flex items-center gap-2 @click="$scrollToTop"> - <span>{{ $t('settings.notifications.push_notifications.label') }}</span> + <span>{{ isHydrated ? $t('settings.notifications.push_notifications.label') : '' }}</span> </div> </template> <NotificationPreferences show /> diff --git a/pages/settings/preferences/index.vue b/pages/settings/preferences/index.vue index c3344105..3fef0a2c 100644 --- a/pages/settings/preferences/index.vue +++ b/pages/settings/preferences/index.vue @@ -1,7 +1,7 @@ <script setup lang="ts"> const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.preferences.label')} | ${t('nav.settings')}`, }) diff --git a/pages/settings/profile/appearance.vue b/pages/settings/profile/appearance.vue index 167312df..6a9035b9 100644 --- a/pages/settings/profile/appearance.vue +++ b/pages/settings/profile/appearance.vue @@ -11,7 +11,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.profile.appearance.title')} | ${t('nav.settings')}`, }) diff --git a/pages/settings/profile/featured-tags.vue b/pages/settings/profile/featured-tags.vue index 7159d855..8cbdc6c7 100644 --- a/pages/settings/profile/featured-tags.vue +++ b/pages/settings/profile/featured-tags.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.profile.featured_tags.label')} | ${t('nav.settings')}`, }) </script> diff --git a/pages/settings/profile/index.vue b/pages/settings/profile/index.vue index c480767a..38b7894b 100644 --- a/pages/settings/profile/index.vue +++ b/pages/settings/profile/index.vue @@ -5,7 +5,7 @@ definePageMeta({ const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.profile.label')} | ${t('nav.settings')}`, }) </script> @@ -14,22 +14,22 @@ useHead({ <MainContent back-on-small-screen> <template #title> <div text-lg font-bold flex items-center gap-2 @click="$scrollToTop"> - <span>{{ $t('settings.profile.label') }}</span> + <span>{{ isHydrated ? $t('settings.profile.label') : '' }}</span> </div> </template> <SettingsItem command large icon="i-ri:user-settings-line" - :text="$t('settings.profile.appearance.label')" - :description="$t('settings.profile.appearance.description')" + :text="isHydrated ? $t('settings.profile.appearance.label') : ''" + :description="isHydrated ? $t('settings.profile.appearance.description') : ''" to="/settings/profile/appearance" /> <SettingsItem command large icon="i-ri:hashtag" - :text="$t('settings.profile.featured_tags.label')" - :description="$t('settings.profile.featured_tags.description')" + :text="isHydrated ? $t('settings.profile.featured_tags.label') : ''" + :description="isHydrated ? $t('settings.profile.featured_tags.description') : ''" to="/settings/profile/featured-tags" /> <SettingsItem diff --git a/pages/settings/users/index.vue b/pages/settings/users/index.vue index 82734a09..7c3306eb 100644 --- a/pages/settings/users/index.vue +++ b/pages/settings/users/index.vue @@ -5,7 +5,7 @@ import type { UserLogin } from '~/types' const { t } = useI18n() -useHead({ +useHydratedHead({ title: () => `${t('settings.users.label')} | ${t('nav.settings')}`, })