Files
mathew/frontend/app/components/AuthGate.vue
2026-09-30 01:49:35 +02:00

45 lines
1.7 KiB
Vue

<script setup lang="ts">
/* Reading Mathew is open to everyone; writing it takes an account. The editor
pages wrap their form in this, so a visitor who follows “New article” without
one lands somewhere that says what is missing and offers the way in, instead
of a form that quietly refuses to save. Nothing is fetched or mounted behind
the gate until there is a session. */
const { loggedIn } = useAuth()
const { show } = useSignInPopup()
const { t } = useI18n()
const props = defineProps<{
heading?: string
text?: string
}>()
/* the defaults live here rather than in withDefaults so they follow the
interface language as it changes */
const headingText = computed(() => props.heading ?? t('gate.heading'))
const textText = computed(() => props.text ?? t('gate.text'))
</script>
<template>
<slot v-if="loggedIn" />
<section v-else class="auth-gate" aria-labelledby="auth-gate-heading">
<span class="auth-gate-mark" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
<circle cx="8" cy="15" r="4" />
<path d="m10.8 12.2 8.2-8.2 2 2-2 2 1.5 1.5-2 2-1.5-1.5-1.7 1.7" />
</svg>
</span>
<h1 id="auth-gate-heading" class="auth-gate-title">{{ headingText }}</h1>
<p class="auth-gate-text">{{ textText }}</p>
<div class="auth-gate-actions">
<button type="button" class="btn btn-primary" @click="show({ mode: 'signin' })">
{{ t('auth.signin') }}
</button>
<button type="button" class="btn btn-ghost" @click="show({ mode: 'signup' })">
{{ t('auth.signup') }}
</button>
</div>
<p class="auth-gate-fine">{{ t('gate.fine') }}</p>
</section>
</template>