Files
kb-anhonesthost/src/pages/index.astro
T

256 lines
7.8 KiB
Plaintext
Raw Normal View History

---
import { getCollection } from 'astro:content';
import '~/styles/anhh-tokens.css';
import '@fontsource-variable/inter';
interface Product {
slug: string;
title: string;
blurb: string;
href: string;
count: number;
}
// Hardcoded product metadata. Adding a new product = adding to this map.
const PRODUCT_META: Record<string, { title: string; blurb: string; firstSection: string }> = {
whp: {
title: 'WHP',
blurb: 'Our hosting control panel. Add domains, create sites, manage email, set up backups.',
firstSection: 'getting-started/welcome',
},
wordpress: {
title: 'WordPress',
blurb: 'Tips and tricks for getting the most out of WordPress on WHP.',
firstSection: 'index',
},
'email-clients': {
title: 'Email clients',
blurb: 'Configure Outlook, Apple Mail, Thunderbird, and mobile clients.',
firstSection: 'index',
},
domains: {
title: 'Domains',
blurb: 'Transfer a domain to us, point it at your hosting, and sort out DNS problems.',
firstSection: 'transferring-a-domain-to-us',
},
email: {
title: 'Email',
blurb: 'How our mail filtering works and what to do when a message does not arrive.',
firstSection: 'outbound-spam-filtering',
},
support: {
title: 'Support',
blurb: 'Working with our support team, including remote-assistance sessions.',
firstSection: 'remote-support',
},
};
const docs = await getCollection('docs');
// Group articles by top-level product folder
const byProduct = new Map<string, number>();
for (const entry of docs) {
const product = entry.id.split('/')[0];
byProduct.set(product, (byProduct.get(product) ?? 0) + 1);
}
const visibleProducts: Product[] = Array.from(byProduct.entries())
.filter(([slug]) => PRODUCT_META[slug] !== undefined)
.filter(([, count]) => count > 0)
.map(([slug, count]) => ({
slug,
title: PRODUCT_META[slug].title,
blurb: PRODUCT_META[slug].blurb,
href: `/${slug}/${PRODUCT_META[slug].firstSection}/`,
count,
}))
.sort((a, b) => a.title.localeCompare(b.title));
---
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AnHonestHost Knowledge Base</title>
<meta
name="description"
content="Customer documentation for WHP and other AnHonestHost services."
/>
<link rel="canonical" href="https://kb.anhonesthost.com/" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<style>
body {
background: var(--anhh-bg, #0a1628);
color: var(--anhh-text-primary, #f0f4ff);
font-family: 'Inter Variable', 'Inter', system-ui, sans-serif;
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
}
header,
footer {
padding: 1.25rem 2rem;
}
header {
border-bottom: 1px solid var(--anhh-border-color, #334155);
display: flex;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
flex-wrap: wrap;
}
a.brand {
display: inline-flex;
align-items: center;
gap: 0.75rem;
color: inherit;
text-decoration: none;
}
.ext-nav {
display: flex;
align-items: center;
gap: 1.25rem;
}
.ext-link {
font-size: 0.875rem;
font-weight: 500;
color: var(--anhh-text-secondary, #94a3b8);
text-decoration: none;
white-space: nowrap;
}
.ext-link:hover,
.ext-link:focus {
color: var(--anhh-accent, #00d4aa);
outline: none;
}
@media (max-width: 40em) {
.ext-nav {
display: none;
}
}
.kb-label {
font-size: 0.875rem;
font-weight: 500;
color: var(--anhh-text-secondary, #94a3b8);
padding-left: 0.75rem;
border-left: 1px solid var(--anhh-border-color, #334155);
line-height: 1;
}
footer {
border-top: 1px solid var(--anhh-border-color, #334155);
font-size: 0.875rem;
color: var(--anhh-text-secondary, #94a3b8);
}
main {
flex: 1;
max-width: 64rem;
margin: 0 auto;
padding: 4rem 2rem;
width: 100%;
box-sizing: border-box;
}
h1 {
font-size: 2.5rem;
margin: 0 0 0.5rem;
}
.lede {
color: var(--anhh-text-secondary, #94a3b8);
font-size: 1.125rem;
margin: 0 0 3rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
a.card {
display: block;
background: var(--anhh-bg-surface, #1e293b);
border: 1px solid var(--anhh-border-color, #334155);
border-radius: 0.75rem;
padding: 1.5rem;
text-decoration: none;
color: inherit;
transition:
border-color 120ms ease,
transform 120ms ease;
}
a.card:hover,
a.card:focus {
border-color: var(--anhh-accent, #00d4aa);
transform: translateY(-2px);
outline: none;
}
a.card h2 {
margin: 0 0 0.5rem;
font-size: 1.25rem;
color: var(--anhh-accent, #00d4aa);
}
a.card p {
margin: 0 0 0.75rem;
color: var(--anhh-text-secondary, #94a3b8);
}
a.card .count {
font-size: 0.875rem;
color: var(--anhh-text-muted, #64748b);
}
.empty {
background: var(--anhh-bg-surface, #1e293b);
border: 1px dashed var(--anhh-border-color, #334155);
border-radius: 0.75rem;
padding: 2rem;
color: var(--anhh-text-muted, #64748b);
text-align: center;
}
footer a {
color: var(--anhh-accent, #00d4aa);
}
</style>
</head>
<body>
<header>
<a href="/" class="brand" aria-label="AnHonestHost Knowledge Base">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 32" fill="none" height="28" role="img">
<path d="M12 4L3 16L12 28" stroke="#00d4aa" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M24 4L33 16L24 28" stroke="#00d4aa" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="12" y1="16" x2="24" y2="16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.35"/>
<text x="44" y="21" font-family="Inter, system-ui, -apple-system, sans-serif" font-size="18" font-weight="800" fill="currentColor" letter-spacing="-0.5">AnHonest<tspan fill="#00d4aa">Host</tspan></text>
</svg>
<span class="kb-label">Knowledge Base</span>
</a>
<nav class="ext-nav" aria-label="AnHonestHost links">
<a href="https://anhonesthost.com/" class="ext-link">Get a Plan</a>
<a href="https://secure.anhonesthost.com/clientarea.php" class="ext-link">Client Portal</a>
</nav>
</header>
<main>
<h1>Knowledge Base</h1>
<p class="lede">Pick a product to get started.</p>
{
visibleProducts.length === 0 ? (
<div class="empty">No documentation has been published yet.</div>
) : (
<div class="grid">
{visibleProducts.map((p) => (
<a class="card" href={p.href}>
<h2>{p.title}</h2>
<p>{p.blurb}</p>
<span class="count">
{p.count} {p.count === 1 ? 'article' : 'articles'}
</span>
</a>
))}
</div>
)
}
</main>
<footer>
Need help?{' '}
<a href="https://secure.anhonesthost.com/submitticket.php">Open a support ticket</a>. ·{' '}
<a href="https://repo.anhonesthost.net/cloud-hosting-platform/kb-anhonesthost">Repo on Gitea</a>
</footer>
</body>
</html>