feat(site): redesign promotion experience
This commit is contained in:
parent
6930906583
commit
13dd160c16
39 changed files with 5764 additions and 5738 deletions
501
apps/site/src/components/Landing.astro
Normal file
501
apps/site/src/components/Landing.astro
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
---
|
||||
import CopyCommand from "./CopyCommand.astro";
|
||||
import HeroSystemGraphic from "./HeroSystemGraphic.astro";
|
||||
import OutputSpecimens from "./OutputSpecimens.astro";
|
||||
import type { LandingContent } from "../i18n/landing";
|
||||
|
||||
interface Props {
|
||||
c: LandingContent;
|
||||
lang: "ko" | "en";
|
||||
}
|
||||
|
||||
const { c, lang } = Astro.props;
|
||||
const repoUrl = "https://git.chanpaca.net/yunchan/designpaca";
|
||||
const docsUrl = `${repoUrl}#readme`;
|
||||
const showcasePath = lang === "ko" ? "/showcase/" : "/en/showcase/";
|
||||
const copyLabel = c.hero.primaryCta;
|
||||
const copiedLabel = lang === "ko" ? "복사했어요" : "Copied";
|
||||
---
|
||||
|
||||
<section class="landing-hero grain" aria-labelledby="hero-title">
|
||||
<div class="hero-grid shell">
|
||||
<div class="hero-copy">
|
||||
<h1 id="hero-title">
|
||||
{c.hero.h1.split("\n").map((line) => <span>{line}</span>)}
|
||||
</h1>
|
||||
<p class="hero-lead">{c.hero.lead}</p>
|
||||
<div class="hero-actions">
|
||||
<CopyCommand
|
||||
command={c.hero.command}
|
||||
copyLabel={copyLabel}
|
||||
copiedLabel={copiedLabel}
|
||||
/>
|
||||
<a class="btn btn-text" href="#outputs">
|
||||
{c.hero.secondaryCta}
|
||||
<svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
|
||||
<path d="M3 5.5 8 10l5-4.5" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-visual">
|
||||
<HeroSystemGraphic lang={lang} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="outputs" class="output-section">
|
||||
<div class="section-head shell">
|
||||
<h2>{c.outputs.h2}</h2>
|
||||
<div>
|
||||
<p>{c.outputs.lead}</p>
|
||||
<a class="section-link" href={showcasePath}>
|
||||
{c.outputs.archiveCta}
|
||||
<svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
|
||||
<path d="M3 8h10M9 4l4 4-4 4" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="output-surface shell">
|
||||
<OutputSpecimens lang={lang} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="process" class="process-section grain">
|
||||
<div class="process-grid shell">
|
||||
<header class="process-head">
|
||||
<h2>{c.process.h2}</h2>
|
||||
<p>{c.process.lead}</p>
|
||||
</header>
|
||||
|
||||
<ol class="stage-list">
|
||||
{c.process.stages.map((stage) => (
|
||||
<li>
|
||||
<span class="stage-index nums">{stage.step}</span>
|
||||
<h3>{stage.name}</h3>
|
||||
<p>{stage.result}</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="proof" class="proof-section">
|
||||
<div class="section-head shell">
|
||||
<h2>{c.proof.h2}</h2>
|
||||
<p>{c.proof.lead}</p>
|
||||
</div>
|
||||
|
||||
<dl class="proof-facts shell">
|
||||
{c.proof.facts.map((fact) => (
|
||||
<div>
|
||||
<dt>
|
||||
<span class="proof-value nums">{fact.value}</span>
|
||||
<span>{fact.label}</span>
|
||||
</dt>
|
||||
<dd>{fact.description}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
|
||||
<details class="audit-details shell">
|
||||
<summary>
|
||||
<span>{c.proof.details.summary}</span>
|
||||
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
|
||||
<path d="M3 5.5 8 10l5-4.5" />
|
||||
</svg>
|
||||
</summary>
|
||||
<ol>
|
||||
{c.proof.details.items.map((item) => <li>{item}</li>)}
|
||||
</ol>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section id="install" class="install-section">
|
||||
<div class="install-grid shell">
|
||||
<div>
|
||||
<h2>{c.install.h2}</h2>
|
||||
<p class="install-lead">{c.install.lead}</p>
|
||||
</div>
|
||||
<div class="install-action">
|
||||
<CopyCommand
|
||||
command={c.install.command}
|
||||
copyLabel={copyLabel}
|
||||
copiedLabel={copiedLabel}
|
||||
/>
|
||||
<ul>
|
||||
{c.install.support.map((item) => (
|
||||
<li>
|
||||
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
|
||||
<path d="m3 8 3 3 7-7" />
|
||||
</svg>
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div class="install-links">
|
||||
<a href={docsUrl}>{c.install.docsLabel}</a>
|
||||
<a href={repoUrl}>{c.install.repoLabel}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="shell">
|
||||
<p>{c.footer.tagline}</p>
|
||||
<p>{c.footer.license}</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.landing-hero {
|
||||
padding-block: var(--space-7) var(--space-9);
|
||||
border-bottom: var(--line-width) solid var(--line);
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.82fr) minmax(34rem, 1.18fr);
|
||||
gap: var(--space-8);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hero-copy h1 span { display: block; }
|
||||
|
||||
.hero-lead {
|
||||
max-width: var(--measure-narrow);
|
||||
margin-top: var(--space-6);
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step-1);
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
margin-top: var(--space-7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-actions :global(.cmd-shell) { width: min(100%, 31rem); }
|
||||
.hero-actions .btn-text svg,
|
||||
.section-link svg,
|
||||
.audit-details summary svg,
|
||||
.install-action li svg {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.hero-visual {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.output-section,
|
||||
.proof-section {
|
||||
padding-block: var(--space-9);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.82fr);
|
||||
gap: var(--space-8);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.section-head > div,
|
||||
.section-head > p {
|
||||
max-width: var(--measure-narrow);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.section-link {
|
||||
min-height: var(--control-h);
|
||||
width: fit-content;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-5);
|
||||
color: var(--ink);
|
||||
font-weight: var(--weight-medium);
|
||||
}
|
||||
|
||||
.output-surface {
|
||||
margin-top: var(--space-8);
|
||||
}
|
||||
|
||||
.process-section {
|
||||
padding-block: var(--space-9);
|
||||
background: var(--surface-inverse);
|
||||
color: var(--ink-inverse);
|
||||
}
|
||||
|
||||
.process-section.grain::after {
|
||||
mix-blend-mode: screen;
|
||||
opacity: 0.035;
|
||||
}
|
||||
|
||||
.process-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(18rem, 0.72fr) minmax(0, 1.28fr);
|
||||
gap: var(--space-8);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.process-head {
|
||||
position: sticky;
|
||||
top: calc(var(--header-h) + var(--space-6));
|
||||
}
|
||||
|
||||
.process-head p {
|
||||
max-width: var(--measure-narrow);
|
||||
margin-top: var(--space-5);
|
||||
color: var(--ink-muted-inverse);
|
||||
}
|
||||
|
||||
.stage-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-top: var(--line-width) solid var(--line-inverse);
|
||||
}
|
||||
|
||||
.stage-list li {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem minmax(10rem, 0.62fr) minmax(0, 1fr);
|
||||
gap: var(--space-4) var(--space-6);
|
||||
align-items: baseline;
|
||||
padding-block: var(--space-5);
|
||||
border-bottom: var(--line-width) solid var(--line-inverse);
|
||||
}
|
||||
|
||||
.stage-index {
|
||||
color: var(--accent);
|
||||
font-weight: var(--weight-medium);
|
||||
}
|
||||
|
||||
.stage-list h3 { font-size: var(--step-1); }
|
||||
.stage-list p {
|
||||
color: var(--ink-muted-inverse);
|
||||
font-size: var(--step-0);
|
||||
}
|
||||
|
||||
@supports (animation-timeline: view()) {
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.stage-list li::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset-inline-start: 0;
|
||||
bottom: calc(var(--line-width) * -1);
|
||||
width: 2.5rem;
|
||||
height: var(--line-width);
|
||||
background: var(--accent);
|
||||
transform-origin: left center;
|
||||
animation: stage-rail-register linear both;
|
||||
animation-timeline: view(block);
|
||||
animation-range: entry 12% cover 32%;
|
||||
}
|
||||
|
||||
@keyframes stage-rail-register {
|
||||
from { opacity: 0.25; transform: scaleX(0); }
|
||||
to { opacity: 1; transform: scaleX(1); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.proof-facts {
|
||||
margin-top: var(--space-8);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
border-block: var(--line-width) solid var(--line-strong);
|
||||
}
|
||||
|
||||
.proof-facts > div {
|
||||
min-width: 0;
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.proof-facts > div + div { border-left: var(--line-width) solid var(--line); }
|
||||
|
||||
.proof-facts dt { display: grid; gap: var(--space-2); }
|
||||
.proof-value {
|
||||
color: var(--accent);
|
||||
font-size: clamp(2.5rem, 2rem + 2vw, 4rem);
|
||||
font-weight: var(--weight-medium);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.proof-facts dd {
|
||||
margin-top: var(--space-4);
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
|
||||
.audit-details {
|
||||
margin-top: var(--space-6);
|
||||
border-bottom: var(--line-width) solid var(--line-strong);
|
||||
}
|
||||
|
||||
.audit-details summary {
|
||||
min-height: var(--control-h);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
padding-block: var(--space-4);
|
||||
font-weight: var(--weight-medium);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.audit-details summary::-webkit-details-marker { display: none; }
|
||||
.audit-details summary::marker { content: ""; }
|
||||
.audit-details summary svg { transition: transform var(--dur-quick) var(--ease-out); }
|
||||
.audit-details[open] summary svg { transform: rotate(180deg); }
|
||||
|
||||
.audit-details ol {
|
||||
margin: 0;
|
||||
padding: 0 0 var(--space-6);
|
||||
list-style: none;
|
||||
counter-reset: audit;
|
||||
}
|
||||
|
||||
.audit-details li {
|
||||
counter-increment: audit;
|
||||
display: grid;
|
||||
grid-template-columns: 2rem minmax(0, 1fr);
|
||||
gap: var(--space-3);
|
||||
padding-block: var(--space-3);
|
||||
border-top: var(--line-width) solid var(--line);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.audit-details li::before {
|
||||
content: counter(audit, decimal-leading-zero);
|
||||
color: var(--accent);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--mono-size);
|
||||
}
|
||||
|
||||
.install-section {
|
||||
padding-block: var(--space-9);
|
||||
background: var(--surface-soft);
|
||||
border-block: var(--line-width) solid var(--line);
|
||||
}
|
||||
|
||||
.install-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.95fr) minmax(28rem, 1.05fr);
|
||||
gap: var(--space-8);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.install-lead {
|
||||
max-width: var(--measure-narrow);
|
||||
margin-top: var(--space-5);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.install-action :global(.cmd-shell) { max-width: none; }
|
||||
|
||||
.install-action ul {
|
||||
list-style: none;
|
||||
margin: var(--space-6) 0 0;
|
||||
padding: 0;
|
||||
border-top: var(--line-width) solid var(--line);
|
||||
}
|
||||
|
||||
.install-action li {
|
||||
min-height: var(--control-h);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
padding-block: var(--space-3);
|
||||
border-bottom: var(--line-width) solid var(--line);
|
||||
}
|
||||
|
||||
.install-action li svg { color: var(--accent); }
|
||||
|
||||
.install-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4) var(--space-6);
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
|
||||
.install-links a {
|
||||
min-height: var(--control-h);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: var(--weight-medium);
|
||||
}
|
||||
|
||||
.site-footer { padding-block: var(--space-7); }
|
||||
.site-footer .shell {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-6);
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
.site-footer p:first-child { max-width: 32rem; color: var(--ink); }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.audit-details summary svg { transition: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 68rem) {
|
||||
.hero-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); }
|
||||
.hero-copy { max-width: 44rem; }
|
||||
.process-grid { grid-template-columns: minmax(15rem, 0.62fr) minmax(0, 1.38fr); }
|
||||
}
|
||||
|
||||
@media (max-width: 56rem) {
|
||||
.hero-grid,
|
||||
.section-head,
|
||||
.process-grid,
|
||||
.install-grid {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
.hero-grid { gap: var(--space-8); }
|
||||
.hero-copy { max-width: 44rem; }
|
||||
.process-head { position: static; }
|
||||
.section-head { gap: var(--space-5); }
|
||||
.proof-facts { grid-template-columns: 1fr; }
|
||||
.proof-facts > div + div { border-left: 0; border-top: var(--line-width) solid var(--line); }
|
||||
}
|
||||
|
||||
@media (max-width: 47.5rem) {
|
||||
.landing-hero { padding-top: var(--space-8); }
|
||||
.hero-copy h1 { font-size: clamp(2.2rem, 11.2vw, 2.8125rem); }
|
||||
:global(html[lang="en"]) .hero-copy h1 { font-size: clamp(2.25rem, 10.2vw, 2.65rem); }
|
||||
.stage-list li {
|
||||
grid-template-columns: 2rem minmax(0, 1fr);
|
||||
gap: var(--space-2) var(--space-4);
|
||||
}
|
||||
.stage-list p { grid-column: 2; }
|
||||
}
|
||||
|
||||
@media (max-width: 34rem) {
|
||||
.hero-actions { align-items: stretch; }
|
||||
.hero-actions :global(.cmd-shell),
|
||||
.hero-actions .btn-text { width: 100%; }
|
||||
.site-footer .shell { display: grid; align-items: start; }
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue