update documentation

This commit is contained in:
MacRimi
2026-07-06 18:48:25 +02:00
parent 6f0fc68c3d
commit 4789371f4d
16 changed files with 696 additions and 32 deletions
@@ -1,7 +1,8 @@
import type { Metadata } from "next"
import { getTranslations, getMessages, setRequestLocale } from "next-intl/server"
import { Star, ExternalLink } from "lucide-react"
import { Star, ExternalLink, BookOpen } from "lucide-react"
import Image from "next/image"
import { Link } from "@/i18n/navigation"
import { DocHeader } from "@/components/ui/doc-header"
import { Callout } from "@/components/ui/callout"
import CopyableCode from "@/components/CopyableCode"
@@ -98,7 +99,7 @@ export default async function PbsDestinationPage({
</h2>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("repoSelection.intro", { code })}
{t.rich("repoSelection.intro", { code, em })}
</p>
<div className="overflow-x-auto mb-6">
@@ -160,6 +161,23 @@ export default async function PbsDestinationPage({
{t("encryption.heading")}
</h2>
<div className="mb-6 flex items-start gap-3 rounded-md border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-800">
<BookOpen className="h-4 w-4 text-slate-500 shrink-0 mt-0.5" aria-hidden="true" />
<p className="leading-relaxed">
{t.rich("encryption.glossaryHint", {
em,
glosarioLink: (chunks) => (
<Link
href="/docs/backup-restore/glossary#group-0"
className="text-blue-600 hover:underline font-medium"
>
{chunks}
</Link>
),
})}
</p>
</div>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("encryption.intro", { code, strong })}
</p>
@@ -207,7 +225,7 @@ export default async function PbsDestinationPage({
</h3>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("encryption.blobUploadBody1", { code })}
{t.rich("encryption.blobUploadBody1", { code, strong })}
</p>
<figure className="my-6">
@@ -231,6 +249,12 @@ export default async function PbsDestinationPage({
</figcaption>
</figure>
<Callout variant="success" title={t("encryption.envelopeSecurityTitle")}>
<p className="leading-relaxed">
{t.rich("encryption.envelopeSecurityBody", { code, strong, em })}
</p>
</Callout>
<h4 className="text-base font-semibold mt-6 mb-2 text-gray-900">
{t("encryption.blobUploadConstraintTitle")}
</h4>
@@ -0,0 +1,141 @@
import type { Metadata } from "next"
import { getTranslations, getMessages, setRequestLocale } from "next-intl/server"
import { Link } from "@/i18n/navigation"
import { DocHeader } from "@/components/ui/doc-header"
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>
}): Promise<Metadata> {
const { locale } = await params
const t = await getTranslations({ locale, namespace: "docs.backupRestore.glossary.meta" })
return {
title: t("title"),
description: t("description"),
keywords: [
"proxmenux backup glossary",
"proxmox backup terminology",
"pbs recovery envelope",
"pbs keyfile passphrase",
"backup vocabulary",
],
alternates: { canonical: "https://proxmenux.com/docs/backup-restore/glossary" },
openGraph: {
title: t("ogTitle"),
description: t("ogDescription"),
type: "article",
url: "https://proxmenux.com/docs/backup-restore/glossary",
},
twitter: {
card: "summary_large_image",
title: t("twitterTitle"),
description: t("twitterDescription"),
},
}
}
type Entry = { id: string; term: string; also?: string; def: string }
type Group = { title: string; intro: string; entries: Entry[] }
type WhereNextItem = { label: string; href: string; tail: string }
export default async function GlossaryPage({
params,
}: {
params: Promise<{ locale: string }>
}) {
const { locale } = await params
setRequestLocale(locale)
const t = await getTranslations({ locale, namespace: "docs.backupRestore.glossary" })
const messages = (await getMessages({ locale })) as unknown as {
docs: { backupRestore: { glossary: {
groups: Group[]
whereNext: { items: WhereNextItem[] }
} } }
}
const gl = messages.docs.backupRestore.glossary
const groups = gl.groups
const whereNextItems = gl.whereNext.items
return (
<div>
<DocHeader
title={t("header.title")}
description={t("header.description")}
section={t("header.section")}
estimatedMinutes={8}
/>
<p className="mt-8 mb-8 text-gray-800 leading-relaxed">
{t("intro.body")}
</p>
<nav
className="mb-10 rounded-lg border border-gray-200 bg-gray-50 p-4"
aria-label={t("header.title")}
>
<ul className="flex flex-wrap gap-x-4 gap-y-2 text-sm">
{groups.map((group, idx) => (
<li key={idx}>
<a
href={`#group-${idx}`}
className="text-blue-600 hover:underline font-medium"
>
{group.title}
</a>
</li>
))}
</ul>
</nav>
{groups.map((group, idx) => (
<section key={idx} id={`group-${idx}`} className="mb-12 scroll-mt-24">
<h2 className="text-2xl font-semibold mt-10 mb-3 text-gray-900">
{group.title}
</h2>
<p className="mb-6 text-gray-800 leading-relaxed">
{group.intro}
</p>
<dl className="space-y-6">
{group.entries.map((entry) => (
<div
key={entry.id}
id={entry.id}
className="scroll-mt-24 border-l-4 border-blue-100 pl-4"
>
<dt className="mb-1">
<span className="font-semibold text-gray-900">{entry.term}</span>
{entry.also ? (
<span className="ml-2 text-sm text-gray-500 italic">
({entry.also})
</span>
) : null}
</dt>
<dd
className="text-gray-800 leading-relaxed [&_a]:text-blue-600 [&_a]:hover:underline [&_code]:bg-gray-100 [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-sm"
dangerouslySetInnerHTML={{ __html: entry.def }}
/>
</div>
))}
</dl>
</section>
))}
<h2 className="text-2xl font-semibold mt-12 mb-4 text-gray-900">
{t("whereNext.heading")}
</h2>
<ul className="mb-6 space-y-2">
{whereNextItems.map((item) => (
<li key={item.href} className="text-gray-800 leading-relaxed">
<Link href={item.href} className="text-blue-600 hover:underline font-medium">
{item.label}
</Link>
<span>{item.tail}</span>
</li>
))}
</ul>
</div>
)
}
@@ -1,6 +1,6 @@
import type { Metadata } from "next"
import { getTranslations, getMessages, setRequestLocale } from "next-intl/server"
import { Info } from "lucide-react"
import { Info, CalendarClock } from "lucide-react"
import { Link } from "@/i18n/navigation"
import { DocHeader } from "@/components/ui/doc-header"
import { Callout } from "@/components/ui/callout"
@@ -117,6 +117,20 @@ export default async function ScheduledJobsPage({
</div>
</div>
<div className="my-8 rounded-lg border border-emerald-200 bg-emerald-50 p-5">
<div className="flex items-start gap-3">
<CalendarClock className="h-5 w-5 text-emerald-700 shrink-0 mt-0.5" aria-hidden="true" />
<div>
<h3 className="text-base font-semibold text-emerald-900 mb-1">
{t("frequencyBadge.title")}
</h3>
<p className="text-sm text-emerald-900/90 leading-relaxed">
{t.rich("frequencyBadge.body", { code, strong })}
</p>
</div>
</div>
</div>
<h2 className="text-2xl font-semibold mt-10 mb-4 text-gray-900">
{t("modes.heading")}
</h2>