feat: Update home page notices and privacy information in English, Spanish, and French; add public guides and routing for guides
All checks were successful
Deploy to production / deploy (push) Successful in 2m11s
All checks were successful
Deploy to production / deploy (push) Successful in 2m11s
- Changed beta notice to service notice on home page translations for English, Spanish, and French. - Updated privacy information to reflect transparency and continuous maintenance. - Added new public guides content with detailed sections for various topics. - Implemented routing for guide list and individual guide articles. - Created new components for displaying guides and articles.
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<div class="no-login-view">
|
||||
<div class="beta-banner" role="status" aria-live="polite">
|
||||
<strong>{{ $t('home.betaNoticeLabel') }}</strong> {{ $t('home.betaNoticeText') }}
|
||||
</div>
|
||||
<div class="home-structure">
|
||||
<div class="mascot">
|
||||
<Character3D gender="male" :lightweight="true" />
|
||||
@@ -40,8 +37,8 @@
|
||||
<p>{{ $t('home.nologin.falukantShort.text') }}</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>{{ $t('home.nologin.privacyBeta.title') }}</h3>
|
||||
<p>{{ $t('home.nologin.privacyBeta.text') }}</p>
|
||||
<h3>{{ $t('home.nologin.privacyInfo.title') }}</h3>
|
||||
<p>{{ $t('home.nologin.privacyInfo.text') }}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -259,18 +256,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.beta-banner {
|
||||
width: min(100%, var(--content-max-width));
|
||||
background: linear-gradient(180deg, #fff2cf 0%, #fde7b2 100%);
|
||||
border: 1px solid rgba(201, 130, 31, 0.24);
|
||||
color: #8a5a12;
|
||||
padding: 10px 14px;
|
||||
margin: 0 0 14px 0;
|
||||
text-align: center;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.home-structure {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
219
frontend/src/views/public/GuideArticleView.vue
Normal file
219
frontend/src/views/public/GuideArticleView.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<main v-if="guide" class="guide-page">
|
||||
<nav class="breadcrumb" aria-label="Breadcrumb">
|
||||
<router-link to="/">YourPart</router-link>
|
||||
<span>/</span>
|
||||
<router-link to="/ratgeber">Ratgeber</router-link>
|
||||
<span>/</span>
|
||||
<span>{{ guide.category }}</span>
|
||||
</nav>
|
||||
|
||||
<article class="guide-article">
|
||||
<header class="guide-header">
|
||||
<p class="guide-category">{{ guide.category }}</p>
|
||||
<h1>{{ guide.title }}</h1>
|
||||
<p class="guide-description">{{ guide.description }}</p>
|
||||
<p class="guide-updated">Aktualisiert: {{ formattedDate }}</p>
|
||||
</header>
|
||||
|
||||
<section v-for="section in guide.sections" :key="section.heading" class="guide-section">
|
||||
<h2>{{ section.heading }}</h2>
|
||||
<p v-for="paragraph in section.paragraphs" :key="paragraph">{{ paragraph }}</p>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
<aside class="related-guides" aria-label="Weitere Ratgeber">
|
||||
<h2>Weitere Ratgeber</h2>
|
||||
<ul>
|
||||
<li v-for="item in relatedGuides" :key="item.slug">
|
||||
<router-link :to="`/ratgeber/${item.slug}`">{{ item.title }}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</main>
|
||||
|
||||
<main v-else class="guide-page">
|
||||
<article class="guide-article">
|
||||
<h1>Ratgeber nicht gefunden</h1>
|
||||
<p>Der gesuchte Beitrag ist nicht vorhanden.</p>
|
||||
<router-link to="/ratgeber">Zur Ratgeber-Übersicht</router-link>
|
||||
</article>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPublicGuide, publicGuides } from '@/content/publicGuides.js';
|
||||
import { applySeo, buildAbsoluteUrl } from '@/utils/seo.js';
|
||||
|
||||
export default {
|
||||
name: 'GuideArticleView',
|
||||
computed: {
|
||||
guide() {
|
||||
return getPublicGuide(this.$route.params.slug);
|
||||
},
|
||||
formattedDate() {
|
||||
if (!this.guide?.updatedAt) return '';
|
||||
return new Date(this.guide.updatedAt).toLocaleDateString('de-DE');
|
||||
},
|
||||
relatedGuides() {
|
||||
if (!this.guide) return publicGuides.slice(0, 4);
|
||||
return publicGuides
|
||||
.filter((item) => item.slug !== this.guide.slug)
|
||||
.slice(0, 4);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'$route.params.slug': {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.applyGuideSeo();
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
applyGuideSeo() {
|
||||
const guide = getPublicGuide(this.$route.params.slug);
|
||||
if (!guide) {
|
||||
applySeo({
|
||||
title: 'Ratgeber nicht gefunden | YourPart',
|
||||
description: 'Der gesuchte YourPart-Ratgeber ist nicht vorhanden.',
|
||||
canonicalPath: '/ratgeber',
|
||||
robots: 'noindex, follow',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const canonicalPath = `/ratgeber/${guide.slug}`;
|
||||
applySeo({
|
||||
title: `${guide.title} | YourPart Ratgeber`,
|
||||
description: guide.description,
|
||||
keywords: `${guide.category}, YourPart, Ratgeber, Community, Vokabeltrainer, Falukant, Browsergames`,
|
||||
canonicalPath,
|
||||
robots: 'index, follow',
|
||||
type: 'article',
|
||||
lang: 'de',
|
||||
locale: 'de_DE',
|
||||
includeHreflangAlternates: false,
|
||||
jsonLd: [
|
||||
{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Article',
|
||||
headline: guide.title,
|
||||
description: guide.description,
|
||||
dateModified: guide.updatedAt,
|
||||
datePublished: guide.updatedAt,
|
||||
inLanguage: 'de',
|
||||
url: buildAbsoluteUrl(canonicalPath),
|
||||
publisher: {
|
||||
'@type': 'Organization',
|
||||
name: 'YourPart',
|
||||
url: buildAbsoluteUrl('/'),
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.guide-page {
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 32px 20px 72px;
|
||||
color: #253043;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 22px;
|
||||
font-size: 0.9rem;
|
||||
color: #5f6b7a;
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #245da8;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.guide-article {
|
||||
max-width: 820px;
|
||||
}
|
||||
|
||||
.guide-header {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.guide-category {
|
||||
margin: 0 0 10px;
|
||||
color: #245da8;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.guide-header h1 {
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
line-height: 1.12;
|
||||
}
|
||||
|
||||
.guide-description {
|
||||
margin: 18px 0 0;
|
||||
font-size: 1.12rem;
|
||||
line-height: 1.7;
|
||||
color: #46556a;
|
||||
}
|
||||
|
||||
.guide-updated {
|
||||
margin: 14px 0 0;
|
||||
color: #667085;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.guide-section {
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.guide-section h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 1.45rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.guide-section p {
|
||||
margin: 0 0 16px;
|
||||
font-size: 1.02rem;
|
||||
line-height: 1.78;
|
||||
}
|
||||
|
||||
.related-guides {
|
||||
margin-top: 48px;
|
||||
padding-top: 26px;
|
||||
border-top: 1px solid rgba(36, 93, 168, 0.16);
|
||||
}
|
||||
|
||||
.related-guides h2 {
|
||||
margin: 0 0 14px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.related-guides ul {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 10px 18px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.related-guides a {
|
||||
color: #245da8;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
107
frontend/src/views/public/GuideListView.vue
Normal file
107
frontend/src/views/public/GuideListView.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<main class="guide-list-page">
|
||||
<header class="guide-list-header">
|
||||
<p class="guide-kicker">YourPart Ratgeber</p>
|
||||
<h1>Ratgeber zu Falukant, Vokabeltrainer, Community und Browsergames</h1>
|
||||
<p>
|
||||
Oeffentliche Artikel erklaeren die wichtigsten Bereiche von YourPart und geben neuen Besuchern genug Kontext,
|
||||
bevor sie ein Konto erstellen oder einen Kurs beziehungsweise ein Spiel starten.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section class="guide-grid" aria-label="Ratgeber">
|
||||
<article v-for="guide in guides" :key="guide.slug" class="guide-card">
|
||||
<p>{{ guide.category }}</p>
|
||||
<h2>
|
||||
<router-link :to="`/ratgeber/${guide.slug}`">{{ guide.title }}</router-link>
|
||||
</h2>
|
||||
<span>{{ guide.description }}</span>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { publicGuides } from '@/content/publicGuides.js';
|
||||
|
||||
export default {
|
||||
name: 'GuideListView',
|
||||
computed: {
|
||||
guides() {
|
||||
return publicGuides;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.guide-list-page {
|
||||
max-width: 1120px;
|
||||
margin: 0 auto;
|
||||
padding: 44px 20px 72px;
|
||||
color: #253043;
|
||||
}
|
||||
|
||||
.guide-list-header {
|
||||
max-width: 820px;
|
||||
}
|
||||
|
||||
.guide-kicker {
|
||||
margin: 0 0 10px;
|
||||
color: #245da8;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.guide-list-header h1 {
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 4vw, 3.2rem);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.guide-list-header p:last-child {
|
||||
margin: 18px 0 0;
|
||||
color: #46556a;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.guide-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 18px;
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.guide-card {
|
||||
padding: 22px;
|
||||
border: 1px solid rgba(36, 93, 168, 0.14);
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.guide-card p {
|
||||
margin: 0 0 8px;
|
||||
color: #245da8;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.guide-card h2 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 1.16rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.guide-card a {
|
||||
color: #1d2b3f;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.guide-card span {
|
||||
color: #536276;
|
||||
line-height: 1.62;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user