307 lines
9.7 KiB
Text
307 lines
9.7 KiB
Text
---
|
|
import { landingKo, landingEn } from "../i18n/landing";
|
|
import socialPreviewKo from "../assets/og-designpaca-ko.png";
|
|
import socialPreviewEn from "../assets/og-designpaca-en.png";
|
|
import "../styles/fonts.css";
|
|
import "../styles/tokens.css";
|
|
import "../styles/base.css";
|
|
|
|
interface Props {
|
|
lang: "ko" | "en";
|
|
title: string;
|
|
description: string;
|
|
translationPath?: string | null;
|
|
noindex?: boolean;
|
|
}
|
|
|
|
const { lang, title, description, noindex = false } = Astro.props;
|
|
const copy = lang === "ko" ? landingKo : landingEn;
|
|
const socialPreview = lang === "ko" ? socialPreviewKo : socialPreviewEn;
|
|
const socialPreviewAlt = lang === "ko"
|
|
? "designpaca의 일곱 단계 디자인 파이프라인 그래픽"
|
|
: "The seven-stage designpaca pipeline graphic";
|
|
const path = Astro.url.pathname;
|
|
const normalizedPath = path.replace(/\/+$/, "") || "/";
|
|
const isKoHome = normalizedPath === "/";
|
|
const isEnHome = normalizedPath === "/en";
|
|
const inferredTranslationPath = isKoHome ? "/en/" : isEnHome ? "/" : null;
|
|
const translationPath = Object.prototype.hasOwnProperty.call(Astro.props, "translationPath")
|
|
? Astro.props.translationPath
|
|
: inferredTranslationPath;
|
|
const homePath = lang === "ko" ? "/" : "/en/";
|
|
const showcasePath = lang === "ko" ? "/showcase/" : "/en/showcase/";
|
|
const isHome = isKoHome || isEnHome;
|
|
const navItems = copy.nav.items.map((item) => ({
|
|
...item,
|
|
href: isHome ? item.href : `${homePath}${item.href}`,
|
|
}));
|
|
const repositoryUrl = "https://git.chanpaca.net/yunchan/designpaca";
|
|
const canonical = new URL(path, Astro.site);
|
|
const translated = translationPath ? new URL(translationPath, Astro.site) : null;
|
|
const socialPreviewUrl = new URL(socialPreview.src, Astro.site);
|
|
const markBg = "%23c43f20";
|
|
const markFg = "%23faf9f4";
|
|
const favicon = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='3' fill='${markBg}'/%3E%3Cpath d='M8 6v20M8 7h12M8 11h8M8 15h13M8 19h9M8 23h12' stroke='${markFg}' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E`;
|
|
const schema = isHome
|
|
? {
|
|
"@context": "https://schema.org",
|
|
"@type": "WebSite",
|
|
name: "designpaca",
|
|
url: new URL("/", Astro.site).href,
|
|
description,
|
|
inLanguage: ["ko-KR", "en-US"],
|
|
}
|
|
: {
|
|
"@context": "https://schema.org",
|
|
"@type": "WebPage",
|
|
name: title,
|
|
url: canonical.href,
|
|
description,
|
|
inLanguage: lang === "ko" ? "ko-KR" : "en-US",
|
|
};
|
|
---
|
|
|
|
<!doctype html>
|
|
<html lang={lang}>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>{title}</title>
|
|
<meta name="description" content={description} />
|
|
{noindex && <meta name="robots" content="noindex, follow" />}
|
|
<meta name="theme-color" content="#f2f1eb" />
|
|
<meta name="color-scheme" content="light" />
|
|
<link rel="icon" href={favicon} />
|
|
|
|
<link rel="canonical" href={canonical} />
|
|
{translated && !isHome && <link rel="alternate" hreflang={lang} href={canonical} />}
|
|
{translated && !isHome && <link rel="alternate" hreflang={lang === "ko" ? "en" : "ko"} href={translated} />}
|
|
{translated && !isHome && <link rel="alternate" hreflang="x-default" href={lang === "ko" ? canonical : translated} />}
|
|
{isHome && <link rel="alternate" hreflang="ko" href={new URL("/", Astro.site)} />}
|
|
{isHome && <link rel="alternate" hreflang="en" href={new URL("/en/", Astro.site)} />}
|
|
{isHome && <link rel="alternate" hreflang="x-default" href={new URL("/", Astro.site)} />}
|
|
|
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdn.jsdelivr.net/gh/wanteddev/wanted-sans@v1.0.3/packages/wanted-sans/fonts/webfonts/variable/split/WantedSansVariable.min.css"
|
|
/>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
|
media="print"
|
|
onload="this.media='all'"
|
|
/>
|
|
|
|
<meta property="og:title" content={title} />
|
|
<meta property="og:description" content={description} />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:url" content={canonical} />
|
|
<meta property="og:locale" content={lang === "ko" ? "ko_KR" : "en_US"} />
|
|
<meta property="og:image" content={socialPreviewUrl} />
|
|
<meta property="og:image:width" content={socialPreview.width} />
|
|
<meta property="og:image:height" content={socialPreview.height} />
|
|
<meta property="og:image:alt" content={socialPreviewAlt} />
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:image" content={socialPreviewUrl} />
|
|
<meta name="twitter:image:alt" content={socialPreviewAlt} />
|
|
<script type="application/ld+json" set:html={JSON.stringify(schema)} />
|
|
</head>
|
|
|
|
<body>
|
|
<a class="skip" href="#main">{lang === "ko" ? "본문으로 건너뛰기" : "Skip to content"}</a>
|
|
|
|
<header class="site-header">
|
|
<div class="header-inner shell">
|
|
<a class="wordmark" href={homePath} translate="no" aria-label={lang === "ko" ? "designpaca 홈" : "designpaca home"}>
|
|
<svg class="wordmark-mark" viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
|
|
<path d="M4 2.5v19M4 3h13M4 6h9M4 9h15M4 12h10M4 15h14M4 18h8M4 21h12" />
|
|
</svg>
|
|
<span>designpaca</span>
|
|
</a>
|
|
|
|
<nav class="nav-primary" aria-label={copy.nav.menuLabel}>
|
|
{navItems.map((item) => <a href={item.href}>{item.label}</a>)}
|
|
</nav>
|
|
|
|
<div class="header-actions">
|
|
<a class="header-archive" href={showcasePath}>{copy.nav.showcaseLabel}</a>
|
|
{translationPath && (
|
|
<a
|
|
class="header-lang"
|
|
href={translationPath}
|
|
hreflang={lang === "ko" ? "en" : "ko"}
|
|
lang={lang === "ko" ? "en" : "ko"}
|
|
aria-label={copy.nav.langLabel}
|
|
>
|
|
{lang === "ko" ? "EN" : "KO"}
|
|
</a>
|
|
)}
|
|
<a class="header-repo" href={repositoryUrl} rel="noopener" aria-label={copy.nav.repoLabel}>
|
|
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
|
|
<path d="M4 12 12 4M6 4h6v6" />
|
|
</svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main id="main" tabindex="-1">
|
|
<slot />
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|
|
<style>
|
|
.site-header {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
min-height: var(--header-h);
|
|
background: var(--surface);
|
|
border-bottom: var(--line-width) solid var(--line);
|
|
}
|
|
|
|
.header-inner {
|
|
min-height: var(--header-h);
|
|
display: grid;
|
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
align-items: center;
|
|
gap: var(--space-6);
|
|
}
|
|
|
|
.wordmark {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
min-height: var(--control-h-sm);
|
|
font-size: 1rem;
|
|
font-weight: var(--weight-medium);
|
|
letter-spacing: -0.01em;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.wordmark-mark {
|
|
flex: none;
|
|
color: var(--accent);
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.5;
|
|
stroke-linecap: round;
|
|
}
|
|
|
|
.nav-primary {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: clamp(var(--space-3), 1.6vw, var(--space-6));
|
|
min-width: 0;
|
|
}
|
|
|
|
.nav-primary a,
|
|
.header-actions a {
|
|
min-height: var(--control-h-sm);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--ink-muted);
|
|
font-size: var(--step--1);
|
|
font-weight: var(--weight-medium);
|
|
line-height: 1.2;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.nav-primary a {
|
|
position: relative;
|
|
padding-inline: var(--space-2);
|
|
}
|
|
|
|
.nav-primary a::after {
|
|
content: "";
|
|
position: absolute;
|
|
right: var(--space-2);
|
|
bottom: 0;
|
|
left: var(--space-2);
|
|
height: 1px;
|
|
background: var(--ink);
|
|
transform: scaleX(0);
|
|
transform-origin: left;
|
|
transition: transform var(--dur-quick) var(--ease-out);
|
|
}
|
|
|
|
.nav-primary a:hover,
|
|
.nav-primary a:focus-visible,
|
|
.header-actions a:hover,
|
|
.header-actions a:focus-visible {
|
|
color: var(--ink);
|
|
}
|
|
|
|
.nav-primary a:hover::after,
|
|
.nav-primary a:focus-visible::after {
|
|
transform: scaleX(1);
|
|
}
|
|
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.header-archive {
|
|
padding-inline: var(--space-3);
|
|
border-left: var(--line-width) solid var(--line);
|
|
}
|
|
|
|
.header-lang,
|
|
.header-repo {
|
|
min-width: var(--control-h-sm);
|
|
padding-inline: var(--space-2);
|
|
border: var(--line-width) solid var(--line-strong);
|
|
}
|
|
|
|
.header-repo svg {
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.5;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
@media (max-width: 64rem) {
|
|
.header-inner { gap: var(--space-3); }
|
|
.header-archive { display: none !important; }
|
|
}
|
|
|
|
@media (max-width: 48rem) {
|
|
.header-inner {
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
grid-template-rows: 3.5rem 3.25rem;
|
|
gap: 0 var(--space-3);
|
|
}
|
|
|
|
.wordmark { grid-column: 1; grid-row: 1; }
|
|
.header-actions { grid-column: 2; grid-row: 1; }
|
|
.nav-primary {
|
|
grid-column: 1 / -1;
|
|
grid-row: 2;
|
|
justify-content: space-between;
|
|
gap: var(--space-1);
|
|
border-top: var(--line-width) solid var(--line);
|
|
}
|
|
.nav-primary a {
|
|
flex: 1 1 0;
|
|
min-width: 0;
|
|
padding-inline: var(--space-1);
|
|
text-align: center;
|
|
}
|
|
.header-repo { display: none !important; }
|
|
}
|
|
|
|
@media (max-width: 23rem) {
|
|
.wordmark { gap: var(--space-2); }
|
|
.nav-primary a { font-size: 0.7rem; }
|
|
}
|
|
</style>
|