Files
mathew/frontend/app/pages/index.vue
2026-10-01 02:29:21 +02:00

82 lines
2.7 KiB
Vue

<script setup lang="ts">
import type { ArticleMeta } from '~/components/ArticleCard.vue'
/* matches the article page's transition so opening/closing the reader
slides one surface away as the next arrives (see main.scss) */
definePageMeta({ transition: { name: 'page', mode: 'out-in' } })
const api = `${useRuntimeConfig().public.apiBase}/api`
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const { show: openSearch } = useSearch()
/* the bar opens the Ctrl/⌘+K popup rather than searching on the page itself,
but it still reads back the query the address carries — the popup's
"all results" link lands here with one */
const askedQuery = computed(() => String(route.query.q ?? ''))
/* fetch one article from the API and open it */
const randomPending = ref(false)
async function showRandomArticle() {
if (randomPending.value) return
randomPending.value = true
try {
const article = await $fetch<ArticleMeta>(`${api}/articles/random`)
/* the canonical slug is the article's address, and the middleware there
turns it onto the reader's language; an orphaned translation answers to
no such address, so that one still goes straight to its own version */
await router.push(
article.baseSlug
? versionHref(identityOf(article), articleLanguage(article))
: `/wiki/${encodeURIComponent(article.slug)}`
)
} catch {
// no articles yet or API unreachable — the banner below already covers API issues
} finally {
randomPending.value = false
}
}
useSeoMeta({
title: () => t('home.metaTitle'),
description: () => t('home.metaDescription'),
})
</script>
<template>
<div class="home-main is-home">
<section class="hero">
<h1 v-html="t('home.hero')"></h1>
<div class="search-wrap">
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="11" cy="11" r="7" />
<path d="m20 20-3.2-3.2" />
</svg>
<button
type="button"
class="search-input search-trigger"
:aria-label="t('common.searchArticles')"
@click="openSearch()"
>
{{ askedQuery || t('home.searchPlaceholder') }}
</button>
<span class="search-kbd">/</span>
</div>
<div class="hero-actions">
<NuxtLink to="/new" class="btn btn-primary">{{ t('home.writeNew') }}</NuxtLink>
<button
type="button"
class="btn btn-ghost"
:disabled="randomPending"
@click="showRandomArticle"
>
{{ t('home.random') }}
</button>
</div>
</section>
</div>
</template>