2
0
Files
gitcaddy-server/templates/pages/cli-terminal.tmpl
logikonline f3eba7dd34 feat(pages): add 5 new landing page templates
Add Documentation First, Developer Tool, Visual Showcase, CLI Terminal, and Architecture Deep Dive templates. Brings total templates to 9. Each template has unique design language and target audience: Documentation First for docs-heavy projects, Developer Tool for technical products, Visual Showcase for design/media projects, CLI Terminal for command-line tools, Architecture Deep Dive for technical deep-dives. Updates template display names for clarity.
2026-03-16 22:18:53 -04:00

1555 lines
46 KiB
Handlebars

{{template "pages/base_head" .}}
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
:root {
--ct-bg: #0a0e14;
--ct-surface: #0f1923;
--ct-elevated: #162030;
--ct-text: #c5cdd8;
--ct-muted: #5c6a78;
--ct-dim: #1e2d3d;
--ct-primary: {{if .Config.Theme.PrimaryColor}}{{.Config.Theme.PrimaryColor}}{{else}}#39ff14{{end}};
--ct-secondary: {{if .Config.Theme.AccentColor}}{{.Config.Theme.AccentColor}}{{else}}#ffb627{{end}};
--ct-glow: rgba(57, 255, 20, 0.15);
--ct-glow-strong: rgba(57, 255, 20, 0.4);
}
html {
scroll-behavior: smooth;
}
html, body.pages-body {
overflow-x: hidden;
background: var(--ct-bg) !important;
}
/* Scanline overlay */
.ct-page::before {
content: "";
position: fixed;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.04) 2px,
rgba(0, 0, 0, 0.04) 4px
);
pointer-events: none;
z-index: 9999;
}
.ct-page {
position: relative;
min-height: 100vh;
background: var(--ct-bg);
color: var(--ct-text);
font-family: 'Space Mono', monospace;
-webkit-font-smoothing: antialiased;
}
/* Reveal animation system */
.ct-reveal {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.ct-reveal.visible {
opacity: 1;
transform: translateY(0);
}
.ct-reveal-delay-1 { transition-delay: 0.08s; }
.ct-reveal-delay-2 { transition-delay: 0.16s; }
.ct-reveal-delay-3 { transition-delay: 0.24s; }
.ct-reveal-delay-4 { transition-delay: 0.32s; }
/* Blink cursor animation */
@keyframes ct-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
/* CRT vignette on hero */
.ct-hero-vignette {
position: absolute;
inset: 0;
background: radial-gradient(ellipse at center, transparent 50%, rgba(10, 14, 20, 0.8) 100%);
pointer-events: none;
z-index: 1;
}
/* Hero phosphor glow */
.ct-hero-glow {
position: absolute;
top: -30%;
left: 50%;
transform: translateX(-50%);
width: 120%;
height: 80%;
background: radial-gradient(ellipse at center, var(--ct-glow) 0%, transparent 60%);
pointer-events: none;
}
/* Navigation */
.ct-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 0 40px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(10, 14, 20, 0.92);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid var(--ct-dim);
z-index: 100;
}
.ct-nav-brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: var(--ct-primary);
}
.ct-nav-logo {
width: 28px;
height: 28px;
background: var(--ct-bg);
border: 1px solid var(--ct-primary);
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ct-primary);
box-shadow: 0 0 8px var(--ct-glow);
}
.ct-nav-name {
font-weight: 700;
font-size: 14px;
letter-spacing: 0.05em;
}
.ct-nav-name::before {
content: ">_ ";
color: var(--ct-muted);
font-weight: 400;
}
.ct-nav-links {
display: flex;
align-items: center;
gap: 4px;
}
.ct-nav-link {
color: var(--ct-muted);
text-decoration: none;
font-size: 12px;
font-weight: 400;
padding: 6px 12px;
border-radius: 2px;
transition: color 0.15s ease, background 0.15s ease;
letter-spacing: 0.02em;
}
.ct-nav-link:hover {
color: var(--ct-primary);
background: rgba(57, 255, 20, 0.05);
}
.ct-nav-cta {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
background: transparent;
border: 1px solid var(--ct-dim);
color: var(--ct-text);
font-size: 12px;
font-weight: 400;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
transition: border-color 0.15s ease, color 0.15s ease;
}
.ct-nav-cta:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
}
/* Mobile menu toggle */
.ct-menu-toggle {
display: none;
background: none;
border: none;
color: var(--ct-muted);
cursor: pointer;
padding: 8px;
}
/* Buttons */
.ct-btn-primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: transparent;
color: var(--ct-primary);
font-weight: 700;
font-size: 13px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
transition: all 0.15s ease;
border: 1px solid var(--ct-primary);
cursor: pointer;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-btn-primary:hover {
background: rgba(57, 255, 20, 0.08);
box-shadow: 0 0 20px var(--ct-glow), 0 0 40px rgba(57, 255, 20, 0.1);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.5);
}
.ct-btn-secondary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: transparent;
color: var(--ct-text);
font-weight: 400;
font-size: 13px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
border: 1px solid var(--ct-dim);
transition: all 0.15s ease;
letter-spacing: 0.02em;
}
.ct-btn-secondary:hover {
border-color: var(--ct-muted);
color: var(--ct-text);
}
/* Hero Section */
.ct-hero {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 140px 40px 100px;
text-align: center;
}
.ct-hero-content {
position: relative;
z-index: 2;
max-width: 800px;
}
.ct-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 5px 14px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
font-size: 11px;
font-weight: 400;
color: var(--ct-secondary);
margin-bottom: 32px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.ct-badge-dot {
width: 6px;
height: 6px;
background: var(--ct-secondary);
border-radius: 50%;
animation: ct-blink 1.4s step-end infinite;
box-shadow: 0 0 6px rgba(255, 182, 39, 0.5);
}
.ct-hero h1 {
font-size: clamp(36px, 5.5vw, 60px);
font-weight: 700;
line-height: 1.15;
margin-bottom: 24px;
letter-spacing: -0.02em;
color: var(--ct-primary);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-hero h1::before {
content: ">_ ";
color: var(--ct-muted);
font-size: 0.7em;
}
.ct-hero h1::after {
content: "\2588";
animation: ct-blink 0.7s step-end infinite;
color: var(--ct-primary);
font-size: 0.8em;
margin-left: 4px;
}
.ct-hero-sub {
font-size: clamp(14px, 1.6vw, 16px);
color: var(--ct-muted);
line-height: 1.8;
margin-bottom: 40px;
max-width: 560px;
margin-left: auto;
margin-right: auto;
font-weight: 400;
}
.ct-hero-ctas {
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 48px;
}
/* Terminal code block */
.ct-code-block {
display: inline-block;
max-width: 520px;
width: 100%;
margin: 0 auto;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
overflow: hidden;
text-align: left;
}
.ct-code-titlebar {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
background: var(--ct-elevated);
border-bottom: 1px solid var(--ct-dim);
}
.ct-code-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.ct-code-dot:nth-child(1) { background: #ff5f57; }
.ct-code-dot:nth-child(2) { background: #febc2e; }
.ct-code-dot:nth-child(3) { background: #28c840; }
.ct-code-title {
flex: 1;
text-align: center;
font-size: 11px;
color: var(--ct-muted);
letter-spacing: 0.04em;
}
.ct-code-body {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
}
.ct-code-prompt {
color: var(--ct-primary);
font-weight: 700;
user-select: none;
font-size: 13px;
}
.ct-code-body code {
color: var(--ct-text);
flex: 1;
font-size: 13px;
font-family: 'Space Mono', monospace;
}
.ct-copy-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-muted);
cursor: pointer;
transition: all 0.15s ease;
flex-shrink: 0;
}
.ct-copy-btn:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
}
/* Stats section */
.ct-stats {
padding: 56px 40px;
border-top: 1px solid var(--ct-dim);
border-bottom: 1px solid var(--ct-dim);
background: var(--ct-surface);
}
.ct-stats-inner {
display: flex;
justify-content: center;
align-items: center;
max-width: 800px;
margin: 0 auto;
flex-wrap: wrap;
gap: 0;
}
.ct-stat-item {
text-align: center;
padding: 0 40px;
position: relative;
}
.ct-stat-item:not(:last-child)::after {
content: "|";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
color: var(--ct-dim);
font-size: 24px;
}
.ct-stat-value {
font-size: 26px;
font-weight: 700;
color: var(--ct-primary);
letter-spacing: 0.02em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-stat-label {
font-size: 11px;
color: var(--ct-muted);
margin-top: 6px;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 400;
}
/* Downloads section */
.ct-downloads {
padding: 80px 40px;
position: relative;
}
.ct-downloads-inner {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.ct-downloads h2 {
font-size: clamp(22px, 3vw, 28px);
font-weight: 700;
margin-bottom: 8px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-downloads p {
color: var(--ct-muted);
margin-bottom: 24px;
font-size: 13px;
}
.ct-downloads-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
}
.ct-download-item {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-text);
text-decoration: none;
font-size: 12px;
transition: all 0.15s ease;
}
.ct-download-item:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
box-shadow: 0 0 10px var(--ct-glow);
}
.ct-download-size {
font-size: 11px;
color: var(--ct-muted);
}
/* Features / Value Props */
.ct-features {
padding: 100px 40px;
position: relative;
}
.ct-features-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-section-label {
font-size: 11px;
font-weight: 700;
color: var(--ct-secondary);
text-transform: uppercase;
letter-spacing: 0.14em;
margin-bottom: 12px;
text-align: center;
}
.ct-section-label::before {
content: "// ";
color: var(--ct-muted);
}
.ct-section-header {
text-align: center;
margin-bottom: 56px;
}
.ct-section-header h2 {
font-size: clamp(24px, 3.5vw, 36px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-section-header p {
font-size: 14px;
color: var(--ct-muted);
max-width: 480px;
margin: 0 auto;
font-weight: 400;
}
.ct-features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 12px;
}
.ct-feature-card {
padding: 28px;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
transition: all 0.15s ease;
position: relative;
}
.ct-feature-card:hover {
border-color: rgba(57, 255, 20, 0.3);
background: var(--ct-elevated);
box-shadow: 0 0 15px rgba(57, 255, 20, 0.05);
}
.ct-feature-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-primary);
margin-bottom: 16px;
}
.ct-feature-title {
font-size: 14px;
font-weight: 700;
color: var(--ct-text);
margin-bottom: 8px;
letter-spacing: 0.02em;
}
.ct-feature-desc {
font-size: 12px;
color: var(--ct-muted);
line-height: 1.7;
font-weight: 400;
}
/* Social proof */
.ct-social-proof {
padding: 80px 40px;
background: var(--ct-surface);
border-top: 1px solid var(--ct-dim);
border-bottom: 1px solid var(--ct-dim);
}
.ct-social-proof-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-logos {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 56px;
flex-wrap: wrap;
}
.ct-logo-item {
padding: 8px 16px;
font-size: 12px;
font-weight: 400;
color: var(--ct-dim);
letter-spacing: 0.04em;
text-transform: uppercase;
transition: color 0.15s ease;
}
.ct-logo-item:hover {
color: var(--ct-muted);
}
.ct-testimonial {
background: var(--ct-bg);
border: 1px solid var(--ct-dim);
border-radius: 2px;
padding: 40px;
max-width: 640px;
margin: 0 auto;
position: relative;
}
.ct-testimonial::before {
content: "/**";
position: absolute;
top: 16px;
left: 16px;
font-size: 12px;
color: var(--ct-muted);
}
.ct-testimonial::after {
content: "*/";
position: absolute;
bottom: 16px;
right: 16px;
font-size: 12px;
color: var(--ct-muted);
}
.ct-testimonial-quote {
font-size: 16px;
line-height: 1.8;
color: var(--ct-text);
margin-bottom: 24px;
font-weight: 400;
font-style: italic;
padding: 0 16px;
}
.ct-testimonial-author {
font-weight: 700;
color: var(--ct-primary);
font-size: 13px;
padding: 0 16px;
}
.ct-testimonial-role {
font-size: 12px;
color: var(--ct-muted);
padding: 0 16px;
}
/* Pricing */
.ct-pricing {
padding: 100px 40px;
}
.ct-pricing-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 12px;
margin-top: 56px;
}
.ct-pricing-card {
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
padding: 32px;
position: relative;
transition: all 0.15s ease;
}
.ct-pricing-card:hover {
border-color: var(--ct-muted);
}
.ct-pricing-card.featured {
border-color: var(--ct-primary);
box-shadow: 0 0 20px var(--ct-glow);
}
.ct-pricing-badge {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
padding: 4px 12px;
background: var(--ct-primary);
color: var(--ct-bg);
font-size: 10px;
font-weight: 700;
border-radius: 2px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.ct-pricing-name {
font-size: 14px;
font-weight: 700;
color: var(--ct-text);
margin-bottom: 8px;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-pricing-price {
font-size: 40px;
font-weight: 700;
color: var(--ct-primary);
line-height: 1;
margin-bottom: 4px;
letter-spacing: -0.02em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-pricing-period {
font-size: 12px;
color: var(--ct-muted);
margin-bottom: 24px;
}
.ct-pricing-features {
list-style: none;
padding: 0;
margin: 0 0 28px 0;
}
.ct-pricing-features li {
padding: 8px 0;
border-bottom: 1px solid var(--ct-dim);
font-size: 12px;
color: var(--ct-muted);
display: flex;
align-items: center;
gap: 8px;
}
.ct-pricing-features li::before {
content: "$";
color: var(--ct-primary);
font-size: 11px;
flex-shrink: 0;
}
.ct-pricing-features li:last-child {
border-bottom: none;
}
.ct-pricing-cta {
display: block;
width: 100%;
padding: 11px 20px;
text-align: center;
background: transparent;
color: var(--ct-text);
font-weight: 700;
font-size: 12px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
border: 1px solid var(--ct-dim);
transition: all 0.15s ease;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-pricing-cta:hover {
border-color: var(--ct-muted);
}
.ct-pricing-card.featured .ct-pricing-cta {
background: transparent;
color: var(--ct-primary);
border-color: var(--ct-primary);
}
.ct-pricing-card.featured .ct-pricing-cta:hover {
background: rgba(57, 255, 20, 0.08);
box-shadow: 0 0 20px var(--ct-glow);
}
/* CTA section */
.ct-cta-section {
padding: 100px 40px;
text-align: center;
position: relative;
}
.ct-cta-section::before {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
height: 50%;
background: radial-gradient(ellipse at center bottom, var(--ct-glow) 0%, transparent 60%);
pointer-events: none;
}
.ct-cta-inner {
max-width: 600px;
margin: 0 auto;
position: relative;
z-index: 1;
}
.ct-cta-section h2 {
font-size: clamp(24px, 3.5vw, 38px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-cta-section p {
font-size: 14px;
color: var(--ct-muted);
margin-bottom: 32px;
font-weight: 400;
}
/* Blog content markdown styles */
.ct-blog-content h1, .ct-blog-content h2, .ct-blog-content h3, .ct-blog-content h4 {
color: var(--ct-text); font-family: 'Space Mono', monospace; margin: 1.5em 0 0.5em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-blog-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--ct-dim); padding-bottom: 8px; }
.ct-blog-content h3 { font-size: 1.25em; }
.ct-blog-content a { color: var(--ct-primary); text-decoration: underline; }
.ct-blog-content a:hover { opacity: 0.8; }
.ct-blog-content code { background: var(--ct-elevated); padding: 2px 6px; border-radius: 2px; font-family: 'Space Mono', monospace; font-size: 0.9em; color: var(--ct-secondary); }
.ct-blog-content pre { background: var(--ct-surface); border: 1px solid var(--ct-dim); border-radius: 2px; padding: 16px; overflow-x: auto; margin: 16px 0; }
.ct-blog-content pre code { background: none; padding: 0; color: var(--ct-text); }
.ct-blog-content blockquote { border-left: 2px solid var(--ct-primary); padding-left: 16px; color: var(--ct-muted); margin: 16px 0; font-style: italic; }
.ct-blog-content img { max-width: 100%; border-radius: 2px; margin: 16px 0; }
.ct-blog-content ul, .ct-blog-content ol { padding-left: 24px; margin: 12px 0; }
.ct-blog-content li { margin: 4px 0; }
.ct-blog-content table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.ct-blog-content th, .ct-blog-content td { border: 1px solid var(--ct-dim); padding: 8px 12px; text-align: left; }
.ct-blog-content th { background: var(--ct-surface); font-weight: 700; color: var(--ct-primary); }
.ct-blog-content hr { border: none; border-top: 1px solid var(--ct-dim); margin: 24px 0; }
/* Footer */
.ct-footer {
padding: 28px 40px;
border-top: 1px solid var(--ct-dim);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.ct-footer-brand {
display: flex;
align-items: center;
gap: 8px;
}
.ct-footer-logo {
width: 20px;
height: 20px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ct-primary);
}
.ct-footer-text {
font-size: 11px;
color: var(--ct-muted);
}
.ct-footer-links {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.ct-footer-link {
color: var(--ct-muted);
text-decoration: none;
font-size: 11px;
transition: color 0.15s ease;
letter-spacing: 0.02em;
}
.ct-footer-link:hover {
color: var(--ct-primary);
}
.ct-footer-social {
display: flex;
gap: 10px;
}
.ct-footer-social a {
color: var(--ct-dim);
transition: color 0.15s ease;
padding: 4px;
}
.ct-footer-social a:hover {
color: var(--ct-primary);
}
/* Responsive */
@media (max-width: 768px) {
.ct-nav { padding: 0 20px; }
.ct-nav-links { display: none; }
.ct-menu-toggle { display: flex; }
.ct-hero { padding: 120px 20px 80px; }
.ct-hero-ctas { flex-direction: column; align-items: center; }
.ct-btn-primary, .ct-btn-secondary { width: 100%; justify-content: center; }
.ct-features, .ct-social-proof, .ct-cta-section, .ct-pricing { padding: 60px 20px; }
.ct-stats { padding: 40px 20px; }
.ct-stat-item { padding: 12px 20px; }
.ct-stat-item:not(:last-child)::after { display: none; }
.ct-stats-inner { flex-direction: column; }
.ct-features-grid { grid-template-columns: 1fr; }
.ct-footer { flex-direction: column; text-align: center; padding: 20px; }
.ct-testimonial { padding: 32px 20px; }
.ct-code-block { max-width: 100%; }
.ct-downloads { padding: 60px 20px; }
}
@media (max-width: 480px) {
.ct-hero h1 { font-size: 28px; }
.ct-section-header h2 { font-size: 22px; }
.ct-pricing-price { font-size: 32px; }
.ct-code-body { font-size: 11px; }
}
</style>
<div class="ct-page">
<!-- Navigation -->
<nav class="ct-nav">
<a href="/" class="ct-nav-brand">
{{if .LogoURL}}
<img src="{{.LogoURL}}" alt="{{.Config.Brand.Name}}" style="height: 28px; border-radius: 2px;">
{{else}}
<div class="ct-nav-logo">
{{svg "octicon-terminal" 14}}
</div>
{{end}}
<span class="ct-nav-name">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</span>
</a>
<div class="ct-nav-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ct-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ct-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="ct-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ct-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ct-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="#value-props" class="ct-nav-link">Value Props</a>{{end}}
{{if .Config.Features}}<a href="#features" class="ct-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="#pricing" class="ct-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="ct-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="ct-nav-link">Gallery</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="ct-nav-cta">
<img src="/assets/img/gitcaddy-icon.svg" width="14" height="14" alt="GitCaddy">
Repository
</a>
{{end}}
{{if .LangSwitcherEnabled}}
<div class="pages-lang-switcher">
<button class="pages-lang-btn" onclick="this.nextElementSibling.classList.toggle('open')">
{{svg "octicon-globe" 14}} {{index $.LanguageNames .ActiveLang}}
</button>
<div class="pages-lang-dropdown">
{{range .AvailableLanguages}}
<a href="?lang={{.}}" class="pages-lang-option{{if eq . $.ActiveLang}} active{{end}}">{{index $.LanguageNames .}}</a>
{{end}}
</div>
</div>
{{end}}
</div>
<button class="ct-menu-toggle" onclick="this.parentElement.querySelector('.ct-nav-links').style.display=this.parentElement.querySelector('.ct-nav-links').style.display==='flex'?'none':'flex'">
{{svg "octicon-three-bars" 20}}
</button>
</nav>
{{if .PageIsBlogDetail}}
<!-- Blog Detail View -->
<section class="ct-hero" style="padding-top: 120px; min-height: auto;">
<div class="ct-hero-content" style="max-width: 800px;">
{{if .BlogPost.FeaturedImage}}
<div style="margin: 0 auto 32px; border-radius: 2px; overflow: hidden; border: 1px solid var(--ct-dim);">
<img src="{{.BlogPost.FeaturedImage.DownloadURL}}" alt="{{.BlogPost.Title}}" style="width: 100%; max-height: 400px; object-fit: cover; display: block;">
</div>
{{end}}
<h1 style="font-size: 32px; margin-bottom: 8px; text-shadow: 0 0 10px rgba(57,255,20,0.3);">{{.BlogPost.Title}}</h1>
{{if .BlogPost.Subtitle}}<p style="font-size: 1.1rem; color: var(--ct-muted); margin-bottom: 24px;">{{.BlogPost.Subtitle}}</p>{{end}}
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 48px; font-size: 12px; color: var(--ct-muted);">
{{if .BlogPost.Author}}<span>{{.BlogPost.Author.DisplayName}}</span><span style="color: var(--ct-dim);">|</span>{{end}}
<span>{{DateUtils.AbsoluteShort .BlogPost.CreatedUnix}}</span>
{{if .BlogTags}}<span style="color: var(--ct-dim);">|</span>{{range .BlogTags}}<span style="background: rgba(57,255,20,0.08); border: 1px solid rgba(57,255,20,0.15); padding: 2px 8px; border-radius: 2px; font-size: 11px; color: var(--ct-primary);">{{.}}</span> {{end}}{{end}}
</div>
<div class="markup ct-blog-content" style="color: var(--ct-text); line-height: 1.8; font-size: 18px; text-align: left;">
{{.BlogRenderedContent}}
</div>
<div style="margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--ct-dim);">
<a href="{{.BlogBaseURL}}" class="ct-btn-secondary" data-cta="secondary" style="text-decoration: none;">
{{svg "octicon-arrow-left" 16}} Back to Blog
</a>
</div>
</div>
</section>
{{else if .PageIsBlogList}}
<!-- Blog List View -->
<section class="ct-features" style="padding-top: 120px;">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Blog</div>
<h2>{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}All Posts{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p>{{.Config.Blog.Subheadline}}</p>{{end}}
</div>
<div class="ct-features-grid">
{{range .BlogListPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ct-feature-card ct-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -28px -28px 16px -28px; overflow: hidden; border-radius: 2px 2px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="ct-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="ct-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--ct-muted);">
{{if .Author}}{{.Author.DisplayName}} &middot; {{end}}{{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if gt .BlogListTotal 9}}
<div style="text-align: center; margin-top: 48px;">
{{template "base/paginate" .}}
</div>
{{end}}
</div>
</section>
{{else}}
<!-- Hero Section -->
<section class="ct-hero">
<div class="ct-hero-glow"></div>
<div class="ct-hero-vignette"></div>
<div class="ct-hero-content">
<div class="ct-badge ct-reveal visible">
<span class="ct-badge-dot"></span>
{{if .LatestRelease}}v{{.LatestReleaseTag}} released{{else}}Open Source{{end}}
</div>
<h1 class="ct-reveal visible ct-reveal-delay-1">{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}</h1>
<p class="ct-hero-sub ct-reveal visible ct-reveal-delay-2">
{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}
</p>
<div class="ct-hero-ctas ct-reveal visible ct-reveal-delay-3">
{{if .Config.Hero.PrimaryCTA.Label}}
<a href="{{.Config.Hero.PrimaryCTA.URL}}" class="ct-btn-primary" data-cta="primary">
{{.Config.Hero.PrimaryCTA.Label}}
{{svg "octicon-arrow-right" 16}}
</a>
{{else}}
<a href="{{.RepoURL}}" class="ct-btn-primary" data-cta="primary">
Get Started
{{svg "octicon-arrow-right" 16}}
</a>
{{end}}
{{if .Config.Hero.SecondaryCTA.Label}}
<a href="{{.Config.Hero.SecondaryCTA.URL}}" class="ct-btn-secondary" data-cta="secondary">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
{{.Config.Hero.SecondaryCTA.Label}}
</a>
{{else}}
<a href="{{.RepoURL}}" class="ct-btn-secondary" data-cta="secondary">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
View Source
</a>
{{end}}
</div>
{{if .Config.Hero.CodeExample}}
<div class="ct-code-block ct-reveal visible ct-reveal-delay-4">
<div class="ct-code-titlebar">
<span class="ct-code-dot"></span>
<span class="ct-code-dot"></span>
<span class="ct-code-dot"></span>
<span class="ct-code-title">terminal</span>
</div>
<div class="ct-code-body">
<span class="ct-code-prompt">$</span>
<code id="install-cmd">{{.Config.Hero.CodeExample}}</code>
<button class="ct-copy-btn" onclick="navigator.clipboard.writeText(document.getElementById('install-cmd').textContent)">
{{svg "octicon-copy" 14}}
</button>
</div>
</div>
{{end}}
</div>
</section>
<!-- Stats Section -->
{{if or .Config.Stats (gt .NumStars 0)}}
<section class="ct-stats">
<div class="ct-stats-inner ct-reveal">
{{if .Config.Stats}}
{{range .Config.Stats}}
<div class="ct-stat-item">
<div class="ct-stat-value">{{.Value}}</div>
<div class="ct-stat-label">{{.Label}}</div>
</div>
{{end}}
{{else}}
<div class="ct-stat-item">
<div class="ct-stat-value">{{.NumStars}}</div>
<div class="ct-stat-label">Stars</div>
</div>
<div class="ct-stat-item">
<div class="ct-stat-value">{{.NumForks}}</div>
<div class="ct-stat-label">Forks</div>
</div>
{{if .LatestRelease}}
<div class="ct-stat-item">
<div class="ct-stat-value">v{{.LatestReleaseTag}}</div>
<div class="ct-stat-label">Latest</div>
</div>
{{end}}
{{end}}
</div>
</section>
{{end}}
<!-- Downloads Section -->
{{if and .PublicReleases .LatestRelease .LatestRelease.Attachments}}
<section class="ct-downloads">
<div class="ct-downloads-inner ct-reveal">
<h2>Download v{{.LatestReleaseTag}}</h2>
<p>Get the latest release</p>
{{$windowsFiles := newSlice}}{{$macosFiles := newSlice}}{{$linuxFiles := newSlice}}{{$androidFiles := newSlice}}{{$iosFiles := newSlice}}{{$otherFiles := newSlice}}
{{range $att := .LatestRelease.Attachments}}
{{$name := StringUtils.ToLower $att.Name}}
{{if or (StringUtils.Contains $name "android") (StringUtils.HasSuffix $name ".apk") (StringUtils.HasSuffix $name ".aab") (StringUtils.HasSuffix $name ".xapk")}}
{{$androidFiles = Append $androidFiles $att}}
{{else if or (StringUtils.Contains $name "ios") (StringUtils.Contains $name "iphone") (StringUtils.Contains $name "ipad") (StringUtils.HasSuffix $name ".ipa")}}
{{$iosFiles = Append $iosFiles $att}}
{{else if or (StringUtils.Contains $name "windows") (StringUtils.Contains $name "win64") (StringUtils.Contains $name "win32") (StringUtils.Contains $name "-win.") (StringUtils.Contains $name "_win.") (StringUtils.Contains $name "-win-") (StringUtils.Contains $name "_win_") (StringUtils.HasSuffix $name ".exe") (StringUtils.HasSuffix $name ".msi") (StringUtils.HasSuffix $name ".msix") (StringUtils.HasSuffix $name ".msixbundle") (StringUtils.HasSuffix $name ".appx") (StringUtils.HasSuffix $name ".appxbundle")}}
{{$windowsFiles = Append $windowsFiles $att}}
{{else if or (StringUtils.Contains $name "darwin") (StringUtils.Contains $name "macos") (StringUtils.Contains $name "-mac.") (StringUtils.Contains $name "_mac.") (StringUtils.Contains $name "-mac-") (StringUtils.Contains $name "_mac_") (StringUtils.Contains $name "osx") (StringUtils.HasSuffix $name ".dmg") (StringUtils.HasSuffix $name ".pkg")}}
{{$macosFiles = Append $macosFiles $att}}
{{else if or (StringUtils.Contains $name "linux") (StringUtils.Contains $name "-lin.") (StringUtils.Contains $name "_lin.") (StringUtils.Contains $name "-lin-") (StringUtils.Contains $name "_lin_") (StringUtils.HasSuffix $name ".deb") (StringUtils.HasSuffix $name ".rpm") (StringUtils.HasSuffix $name ".appimage") (StringUtils.HasSuffix $name ".flatpak") (StringUtils.HasSuffix $name ".snap")}}
{{$linuxFiles = Append $linuxFiles $att}}
{{else}}
{{$otherFiles = Append $otherFiles $att}}
{{end}}
{{end}}
{{if $windowsFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} Windows</h4>
<div class="ct-downloads-grid">
{{range $windowsFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $macosFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} macOS</h4>
<div class="ct-downloads-grid">
{{range $macosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $linuxFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-terminal" 16}} Linux</h4>
<div class="ct-downloads-grid">
{{range $linuxFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if not $.HideMobileReleases}}
{{if $androidFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} Android</h4>
<div class="ct-downloads-grid">
{{range $androidFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $iosFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} iOS</h4>
<div class="ct-downloads-grid">
{{range $iosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{end}}
{{if or $.GooglePlayID $.AppStoreID}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} App Stores</h4>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
{{if $.GooglePlayID}}
<a href="https://play.google.com/store/apps/details?id={{$.GooglePlayID}}" target="_blank" rel="noopener" class="ct-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M3.609 1.814L13.792 12 3.61 22.186a.996.996 0 0 1-.61-.92V2.734a1 1 0 0 1 .609-.92zm10.89 10.893l2.302 2.302-10.937 6.333 8.635-8.635zm3.199-1.4l2.834 1.64a1 1 0 0 1 0 1.726l-2.834 1.64-2.635-2.636 2.635-2.37zM5.864 2.658L16.8 9.99l-2.302 2.302-8.635-8.635z"/></svg>
Google Play
</a>
{{end}}
{{if $.AppStoreID}}
<a href="https://apps.apple.com/app/{{$.AppStoreID}}" target="_blank" rel="noopener" class="ct-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>
App Store
</a>
{{end}}
</div>
</div>
{{end}}
{{if $otherFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-file" 16}} Other</h4>
<div class="ct-downloads-grid">
{{range $otherFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Value Props Section -->
{{if .Config.ValueProps}}
<section class="ct-features" id="value-props">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Why choose us</div>
<h2>{{if .Config.Brand.Name}}Why {{.Config.Brand.Name}}?{{else}}Why Choose Us{{end}}</h2>
<p>Everything you need to get started quickly.</p>
</div>
<div class="ct-features-grid">
{{range .Config.ValueProps}}
<div class="ct-feature-card ct-reveal">
<div class="ct-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "check")) 20}}
</div>
<h3 class="ct-feature-title">{{.Title}}</h3>
<p class="ct-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Features Section -->
{{if .Config.Features}}
<section class="ct-features" id="features" style="padding-top: 40px;">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Capabilities</div>
<h2>Features</h2>
<p>Powerful capabilities at your fingertips.</p>
</div>
<div class="ct-features-grid">
{{range .Config.Features}}
<div class="ct-feature-card ct-reveal">
<div class="ct-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "zap")) 20}}
</div>
<h3 class="ct-feature-title">{{.Title}}</h3>
<p class="ct-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Social Proof -->
{{if or .Config.SocialProof.Logos .Config.SocialProof.Testimonials}}
<section class="ct-social-proof">
<div class="ct-social-proof-inner">
{{if .Config.SocialProof.Logos}}
<div class="ct-logos ct-reveal">
{{range .Config.SocialProof.Logos}}
<div class="ct-logo-item">{{.}}</div>
{{end}}
</div>
{{end}}
{{if .Config.SocialProof.Testimonials}}
<div class="ct-testimonials-container">
{{range .Config.SocialProof.Testimonials}}
<div class="ct-testimonial ct-reveal" style="display: none;">
<p class="ct-testimonial-quote">"{{.Quote}}"</p>
<div>
<div class="ct-testimonial-author">{{.Author}}</div>
<div class="ct-testimonial-role">{{.Role}}</div>
</div>
</div>
{{end}}
</div>
<script>
(function() {
var testimonials = document.querySelectorAll(".ct-testimonial");
if (testimonials.length > 0) {
var idx = Math.floor(Math.random() * testimonials.length);
testimonials[idx].style.display = "block";
}
})();
</script>
{{end}}
</div>
</section>
{{end}}
<!-- Pricing Section -->
{{if .Config.Pricing.Plans}}
<section class="ct-pricing" id="pricing">
<div class="ct-pricing-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Pricing</div>
<h2>{{if .Config.Pricing.Headline}}{{.Config.Pricing.Headline}}{{else}}Pricing{{end}}</h2>
<p>{{if .Config.Pricing.Subheadline}}{{.Config.Pricing.Subheadline}}{{else}}Choose the plan that works for you{{end}}</p>
</div>
<div class="ct-pricing-grid">
{{range .Config.Pricing.Plans}}
<div class="ct-pricing-card{{if .Featured}} featured{{end}} ct-reveal">
{{if .Featured}}<span class="ct-pricing-badge">Popular</span>{{end}}
<div class="ct-pricing-name">{{.Name}}</div>
<div class="ct-pricing-price">{{.Price}}</div>
<div class="ct-pricing-period">{{.Period}}</div>
{{if .Features}}
<ul class="ct-pricing-features">
{{range .Features}}<li>{{.}}</li>{{end}}
</ul>
{{end}}
<a href="#" class="ct-pricing-cta">{{if .CTA}}{{.CTA}}{{else}}Get Started{{end}}</a>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- CTA Section -->
{{if .Config.CTASection.Headline}}
<section class="ct-cta-section">
<div class="ct-cta-inner ct-reveal">
<h2>{{.Config.CTASection.Headline}}</h2>
{{if .Config.CTASection.Subheadline}}
<p>{{.Config.CTASection.Subheadline}}</p>
{{end}}
<a href="{{if .Config.CTASection.Button.URL}}{{.Config.CTASection.Button.URL}}{{else}}{{.RepoURL}}{{end}}" class="ct-btn-primary" data-cta="primary" style="padding: 14px 28px; font-size: 13px;">
{{if .Config.CTASection.Button.Label}}{{.Config.CTASection.Button.Label}}{{else}}Get Started{{end}}
{{svg "octicon-arrow-right" 16}}
</a>
</div>
</section>
{{end}}
<!-- Blog Section -->
{{if and .Config.Blog.Enabled .BlogPosts}}
<section class="ct-features" id="blog" style="border-top: 1px solid var(--ct-dim);">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Blog</div>
<h2>{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}Latest Posts{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p>{{.Config.Blog.Subheadline}}</p>{{end}}
</div>
<div class="ct-features-grid">
{{range .BlogPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ct-feature-card ct-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -28px -28px 16px -28px; overflow: hidden; border-radius: 2px 2px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="ct-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="ct-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--ct-muted);">
{{if .Author}}{{.Author.DisplayName}}{{end}} · {{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if .Config.Blog.CTAButton.Label}}
<div style="text-align: center; margin-top: 48px;" class="ct-reveal">
<a href="{{if .Config.Blog.CTAButton.URL}}{{.Config.Blog.CTAButton.URL}}{{else}}{{.BlogBaseURL}}{{end}}" class="ct-btn-secondary" data-cta="secondary">
{{.Config.Blog.CTAButton.Label}}
{{svg "octicon-arrow-right" 16}}
</a>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Gallery Section -->
{{if and .Config.Gallery.Enabled .GalleryImages}}
<section class="ct-features" id="gallery" style="border-top: 1px solid var(--ct-dim);">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Gallery</div>
<h2>{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}Gallery{{end}}</h2>
{{if .Config.Gallery.Subheadline}}<p>{{.Config.Gallery.Subheadline}}</p>{{end}}
</div>
<div style="display: grid; grid-template-columns: repeat({{if .Config.Gallery.Columns}}{{.Config.Gallery.Columns}}{{else}}3{{end}}, 1fr); gap: 12px;">
{{range .GalleryImages}}
<div class="ct-feature-card ct-reveal" style="padding: 0; overflow: hidden;">
<a href="{{.URL}}" class="pages-gallery-trigger" data-src="{{.URL}}" data-caption="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="display: block; cursor: pointer;">
<img src="{{.URL}}" alt="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="width: 100%; height: 220px; object-fit: cover; display: block;">
</a>
{{if .Caption}}
<div style="padding: 12px 16px; font-size: 11px; color: var(--ct-muted); border-top: 1px solid var(--ct-dim);">{{.Caption}}</div>
{{end}}
</div>
{{end}}
</div>
</div>
</section>
{{end}}
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
<!-- Footer -->
<footer class="ct-footer">
<div class="ct-footer-brand">
<div class="ct-footer-logo">{{svg "octicon-terminal" 10}}</div>
<span class="ct-footer-text">{{if .Config.Footer.Copyright}}{{.Config.Footer.Copyright}}{{else}}&copy; <script>document.write(new Date().getFullYear())</script> {{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}{{end}}</span>
</div>
{{if .Config.Footer.Social}}
<div class="ct-footer-social">
{{range .Config.Footer.Social}}
<a href="{{.URL}}" title="{{.Platform}}">
{{if eq .Platform "twitter"}}{{svg "octicon-mention" 16}}
{{else if eq .Platform "bluesky"}}{{svg "octicon-cloud" 16}}
{{else if eq .Platform "github"}}{{svg "octicon-mark-github" 16}}
{{else if eq .Platform "discord"}}{{svg "octicon-comment-discussion" 16}}
{{else if eq .Platform "linkedin"}}{{svg "octicon-briefcase" 16}}
{{else if eq .Platform "youtube"}}{{svg "octicon-video" 16}}
{{else if eq .Platform "instagram"}}{{svg "octicon-device-camera" 16}}
{{else if eq .Platform "facebook"}}{{svg "octicon-people" 16}}
{{else if eq .Platform "substack"}}{{svg "octicon-note" 16}}
{{else if eq .Platform "threads"}}{{svg "octicon-share" 16}}
{{else if eq .Platform "tiktok"}}{{svg "octicon-play" 16}}
{{else if eq .Platform "reddit"}}{{svg "octicon-hash" 16}}
{{else if eq .Platform "mastodon"}}{{svg "octicon-megaphone" 16}}
{{else if eq .Platform "twitch"}}{{svg "octicon-broadcast" 16}}
{{else if eq .Platform "rss"}}{{svg "octicon-rss" 16}}
{{else}}{{svg "octicon-link-external" 16}}{{end}}
</a>
{{end}}
</div>
{{end}}
<div class="ct-footer-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ct-footer-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowRepository}}<a href="{{.RepoURL}}" class="ct-footer-link">Repository</a>{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ct-footer-link">Documentation</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ct-footer-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ct-footer-link">Issues</a>{{end}}
</div>
</footer>
</div>
<!-- Scroll reveal observer -->
<script>
(function() {
var reveals = document.querySelectorAll('.ct-reveal:not(.visible)');
if (!reveals.length) return;
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
reveals.forEach(function(el) { observer.observe(el); });
})();
</script>
{{template "pages/base_footer" .}}