2
0
Files
gitcaddy-server/templates/pages/minimalist-docs.tmpl
logikonline 433214fb91
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 2m56s
Build and Release / Unit Tests (push) Successful in 8m52s
Build and Release / Lint (push) Successful in 9m21s
Build and Release / Build Binaries (amd64, darwin, macos) (push) Failing after 1s
Build and Release / Build Binaries (arm64, darwin, macos) (push) Failing after 1s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 4m54s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 9h5m27s
Build and Release / Build Binary (linux/arm64) (push) Failing after 13m25s
feat(pages): add app store links to downloads section
Add GooglePlayID and AppStoreID config fields to display app store download buttons on landing pages. Shows "App Stores" section with Google Play and/or App Store badges when IDs are configured. Useful for mobile apps distributed via stores instead of direct downloads. Includes branded SVG icons for both stores. Applies to all four page templates.
2026-03-16 02:04:33 -04:00

1534 lines
46 KiB
Handlebars

{{template "pages/base_head" .}}
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&family=IBM+Plex+Mono:wght@400;500&display=swap');
:root {
--ea-bg: #faf8f5;
--ea-surface: #f3efe9;
--ea-text: #1c1917;
--ea-muted: #57534e;
--ea-light: #a8a29e;
--ea-border: #e7e5e4;
--ea-accent: {{if .Config.Theme.PrimaryColor}}{{.Config.Theme.PrimaryColor}}{{else}}#b45309{{end}};
--ea-ink: #292524;
--ea-cream: #fefcf8;
}
/* Scroll reveal system */
.ea-reveal {
opacity: 0;
transform: translateY(32px);
transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
.ea-reveal.visible {
opacity: 1;
transform: translateY(0);
}
.ea-reveal-delay-1 { transition-delay: 0.1s; }
.ea-reveal-delay-2 { transition-delay: 0.2s; }
.ea-reveal-delay-3 { transition-delay: 0.3s; }
.ea-reveal-delay-4 { transition-delay: 0.4s; }
.ea-page {
min-height: 100vh;
background: var(--ea-bg);
color: var(--ea-text);
font-family: 'Cormorant Garamond', Georgia, serif;
line-height: 1.75;
-webkit-font-smoothing: antialiased;
}
/* Ink wash texture overlay */
.ea-page::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 15% 20%, color-mix(in srgb, var(--ea-accent) 3%, transparent) 0%, transparent 50%),
radial-gradient(ellipse at 85% 80%, rgba(41, 37, 36, 0.02) 0%, transparent 50%);
pointer-events: none;
z-index: 0;
}
/* --- Navigation --- */
.ea-nav {
position: relative;
z-index: 10;
padding: 28px 60px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--ea-border);
}
.ea-nav-brand {
font-family: 'Playfair Display', Georgia, serif;
font-weight: 700;
font-size: 22px;
color: var(--ea-text);
letter-spacing: -0.03em;
text-decoration: none;
}
.ea-nav-links {
display: flex;
align-items: center;
gap: 36px;
}
.ea-nav-link {
color: var(--ea-muted);
text-decoration: none;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
transition: color 0.3s ease;
}
.ea-nav-link:hover {
color: var(--ea-text);
}
/* Mobile menu */
.ea-mobile-toggle {
display: none;
background: none;
border: 1px solid var(--ea-border);
border-radius: 4px;
padding: 8px 12px;
cursor: pointer;
color: var(--ea-text);
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.ea-mobile-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--ea-cream);
border-bottom: 1px solid var(--ea-border);
padding: 24px 60px;
z-index: 100;
flex-direction: column;
gap: 16px;
}
.ea-mobile-menu.open {
display: flex;
}
/* --- Buttons --- */
.ea-btn-text {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--ea-muted);
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
text-decoration: none;
background: none;
border: none;
cursor: pointer;
transition: color 0.3s ease;
}
.ea-btn-text:hover {
color: var(--ea-text);
}
.ea-btn-primary {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 16px 36px;
background: var(--ea-ink);
color: var(--ea-cream);
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
border-radius: 0;
text-decoration: none;
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
position: relative;
overflow: hidden;
}
.ea-btn-primary::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background: var(--ea-accent);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.ea-btn-primary:hover {
background: #44403c;
}
.ea-btn-primary:hover::after {
transform: scaleX(1);
}
/* --- Section label --- */
.ea-section-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ea-light);
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 16px;
}
.ea-section-label::after {
content: '';
flex: 1;
height: 1px;
background: var(--ea-border);
}
/* --- Hero Section --- */
.ea-hero {
position: relative;
z-index: 1;
max-width: 780px;
margin: 0 auto;
padding: 100px 32px 80px;
}
.ea-hero-eyebrow {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--ea-accent);
margin-bottom: 28px;
}
.ea-hero h1 {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(40px, 6vw, 64px);
font-weight: 400;
line-height: 1.15;
margin-bottom: 28px;
letter-spacing: -0.02em;
color: var(--ea-text);
}
.ea-hero h1 em {
font-style: italic;
color: var(--ea-accent);
}
.ea-hero-sub {
font-size: clamp(18px, 2.2vw, 22px);
color: var(--ea-muted);
line-height: 1.8;
margin-bottom: 44px;
max-width: 600px;
}
.ea-hero-ctas {
display: flex;
gap: 20px;
align-items: center;
margin-bottom: 72px;
}
/* Code block */
.ea-code-block {
background: var(--ea-ink);
padding: 32px;
font-family: 'IBM Plex Mono', monospace;
font-size: 14px;
line-height: 1.8;
overflow-x: auto;
position: relative;
border-left: 3px solid var(--ea-accent);
}
.ea-code-block code {
color: #d6d3d1;
white-space: pre;
}
.ea-copy-btn {
position: absolute;
top: 16px;
right: 16px;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 0;
color: #78716c;
cursor: pointer;
transition: all 0.3s ease;
}
.ea-copy-btn:hover {
background: rgba(255, 255, 255, 0.08);
color: #d6d3d1;
}
/* --- Horizontal rule --- */
.ea-rule {
max-width: 780px;
margin: 0 auto;
padding: 0 32px;
}
.ea-rule-inner {
height: 1px;
background: var(--ea-border);
position: relative;
}
.ea-rule-inner::after {
content: '§';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: var(--ea-bg);
padding: 0 20px;
font-family: 'Playfair Display', Georgia, serif;
font-size: 18px;
color: var(--ea-light);
font-style: italic;
}
/* --- Stats --- */
.ea-stats {
max-width: 780px;
margin: 0 auto;
padding: 72px 32px;
}
.ea-stats-inner {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0;
}
.ea-stat {
text-align: center;
padding: 0 24px;
border-right: 1px solid var(--ea-border);
}
.ea-stat:last-child {
border-right: none;
}
.ea-stat-value {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(42px, 5vw, 56px);
font-weight: 400;
color: var(--ea-text);
letter-spacing: -0.03em;
line-height: 1;
margin-bottom: 8px;
font-style: italic;
}
.ea-stat-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
color: var(--ea-light);
letter-spacing: 0.12em;
text-transform: uppercase;
}
/* --- Downloads --- */
.ea-downloads {
max-width: 780px;
margin: 0 auto;
padding: 0 32px 72px;
}
.ea-downloads-list {
display: flex;
flex-direction: column;
}
.ea-download-item {
display: flex;
align-items: center;
gap: 14px;
padding: 16px 0;
border-bottom: 1px solid var(--ea-border);
color: var(--ea-text);
text-decoration: none;
font-family: 'IBM Plex Mono', monospace;
font-size: 14px;
transition: color 0.3s ease;
}
.ea-download-item:first-child {
border-top: 1px solid var(--ea-ink);
}
.ea-download-item:hover {
color: var(--ea-accent);
}
.ea-download-size {
margin-left: auto;
color: var(--ea-light);
font-size: 12px;
}
/* --- Sections --- */
.ea-section {
position: relative;
z-index: 1;
max-width: 780px;
margin: 0 auto;
padding: 0 32px 88px;
}
.ea-section-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(28px, 3.5vw, 38px);
font-weight: 400;
margin-bottom: 40px;
letter-spacing: -0.02em;
line-height: 1.3;
}
/* --- Value props --- */
.ea-value-item {
display: flex;
gap: 20px;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid var(--ea-border);
}
.ea-value-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.ea-value-number {
font-family: 'Playfair Display', Georgia, serif;
font-size: 36px;
font-weight: 400;
font-style: italic;
color: var(--ea-light);
line-height: 1;
flex-shrink: 0;
width: 44px;
}
.ea-value-body {
flex: 1;
}
.ea-value-title {
font-family: 'Playfair Display', Georgia, serif;
font-weight: 600;
font-size: 20px;
color: var(--ea-text);
margin-bottom: 4px;
}
.ea-value-desc {
color: var(--ea-muted);
font-size: 17px;
}
/* --- Features accordion --- */
.ea-accordion {
border-top: 1px solid var(--ea-ink);
}
.ea-accordion-item {
border-bottom: 1px solid var(--ea-border);
}
.ea-accordion-header {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
background: none;
border: none;
width: 100%;
text-align: left;
font-family: 'Cormorant Garamond', Georgia, serif;
padding: 28px 0;
transition: opacity 0.3s ease;
}
.ea-accordion-header:hover {
opacity: 0.7;
}
.ea-accordion-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: 22px;
font-weight: 500;
color: var(--ea-text);
letter-spacing: -0.01em;
}
.ea-accordion-icon {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Playfair Display', Georgia, serif;
font-size: 24px;
font-weight: 300;
color: var(--ea-light);
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.ea-accordion-item.open .ea-accordion-icon {
transform: rotate(45deg);
}
.ea-accordion-content {
display: none;
padding-bottom: 28px;
font-size: 18px;
line-height: 1.8;
color: var(--ea-muted);
max-width: 620px;
}
.ea-accordion-item.open .ea-accordion-content {
display: block;
}
/* --- Pricing --- */
.ea-pricing {
position: relative;
z-index: 1;
max-width: 1000px;
margin: 0 auto;
padding: 88px 32px;
border-top: 1px solid var(--ea-border);
}
.ea-pricing-title {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(28px, 3.5vw, 38px);
font-weight: 400;
text-align: center;
margin-bottom: 56px;
letter-spacing: -0.02em;
}
.ea-pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1px;
background: var(--ea-border);
border: 1px solid var(--ea-border);
}
.ea-pricing-card {
padding: 40px;
background: var(--ea-cream);
position: relative;
}
.ea-pricing-card.featured {
background: var(--ea-ink);
color: var(--ea-cream);
}
.ea-pricing-featured-badge {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 500;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--ea-accent);
margin-bottom: 16px;
display: block;
}
.ea-pricing-card.featured .ea-pricing-featured-badge {
color: #fbbf24;
}
.ea-pricing-name {
font-family: 'IBM Plex Mono', monospace;
font-size: 13px;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
margin-bottom: 12px;
color: var(--ea-muted);
}
.ea-pricing-card.featured .ea-pricing-name {
color: #a8a29e;
}
.ea-pricing-price {
font-family: 'Playfair Display', Georgia, serif;
font-size: 44px;
font-weight: 400;
font-style: italic;
margin-bottom: 4px;
letter-spacing: -0.02em;
}
.ea-pricing-period {
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
color: var(--ea-light);
margin-bottom: 28px;
letter-spacing: 0.05em;
}
.ea-pricing-card.featured .ea-pricing-period {
color: #78716c;
}
.ea-pricing-features {
list-style: none;
padding: 0;
margin: 0 0 32px;
}
.ea-pricing-features li {
display: flex;
align-items: baseline;
gap: 10px;
padding: 10px 0;
font-size: 16px;
color: var(--ea-muted);
border-bottom: 1px solid var(--ea-border);
}
.ea-pricing-card.featured .ea-pricing-features li {
color: #a8a29e;
border-color: rgba(255, 255, 255, 0.08);
}
.ea-pricing-features li:last-child {
border-bottom: none;
}
.ea-pricing-features li::before {
content: "—";
color: var(--ea-accent);
font-weight: 500;
flex-shrink: 0;
}
.ea-pricing-card.featured .ea-pricing-features li::before {
color: #fbbf24;
}
.ea-pricing-cta {
display: block;
width: 100%;
padding: 14px 28px;
text-align: center;
border: 1px solid var(--ea-border);
font-family: 'IBM Plex Mono', monospace;
font-weight: 500;
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--ea-text);
text-decoration: none;
transition: all 0.4s ease;
}
.ea-pricing-cta:hover {
background: var(--ea-ink);
color: var(--ea-cream);
border-color: var(--ea-ink);
}
.ea-pricing-card.featured .ea-pricing-cta {
background: var(--ea-cream);
color: var(--ea-ink);
border-color: var(--ea-cream);
}
.ea-pricing-card.featured .ea-pricing-cta:hover {
background: #e7e5e4;
}
/* --- Testimonial --- */
.ea-testimonial-section {
position: relative;
z-index: 1;
background: var(--ea-surface);
padding: 88px 0;
margin: 0;
}
.ea-testimonial-inner {
max-width: 720px;
margin: 0 auto;
padding: 0 32px;
}
.ea-testimonial-mark {
font-family: 'Playfair Display', Georgia, serif;
font-size: 120px;
font-weight: 400;
font-style: italic;
line-height: 0.7;
color: var(--ea-border);
margin-bottom: 12px;
}
.ea-testimonial-quote {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(22px, 3vw, 30px);
line-height: 1.5;
color: var(--ea-text);
margin-bottom: 28px;
font-style: italic;
font-weight: 400;
}
.ea-testimonial-attribution {
display: flex;
align-items: center;
gap: 12px;
}
.ea-testimonial-dash {
width: 32px;
height: 1px;
background: var(--ea-light);
}
.ea-testimonial-author {
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ea-muted);
}
.ea-testimonial-role {
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: 15px;
color: var(--ea-light);
font-style: italic;
margin-left: 44px;
margin-top: 4px;
}
/* --- Used by --- */
.ea-used-by {
position: relative;
z-index: 1;
max-width: 780px;
margin: 0 auto;
padding: 64px 32px 80px;
}
.ea-used-by-logos {
display: flex;
gap: 40px;
flex-wrap: wrap;
}
.ea-used-by-item {
font-family: 'IBM Plex Mono', monospace;
font-size: 13px;
color: var(--ea-light);
font-weight: 500;
letter-spacing: 0.04em;
transition: color 0.3s ease;
}
.ea-used-by-item:hover {
color: var(--ea-muted);
}
/* --- CTA Section --- */
.ea-cta-section {
position: relative;
z-index: 1;
max-width: 780px;
margin: 0 auto;
padding: 88px 32px;
text-align: center;
border-top: 1px solid var(--ea-border);
}
.ea-cta-section h2 {
font-family: 'Playfair Display', Georgia, serif;
font-size: clamp(28px, 4vw, 42px);
font-weight: 400;
margin-bottom: 28px;
letter-spacing: -0.02em;
font-style: italic;
}
.ea-install-cmd {
display: inline-flex;
align-items: center;
gap: 14px;
padding: 14px 24px;
background: var(--ea-ink);
font-family: 'IBM Plex Mono', monospace;
font-size: 14px;
color: #d6d3d1;
border: none;
cursor: pointer;
transition: all 0.3s ease;
border-left: 3px solid var(--ea-accent);
margin-bottom: 36px;
}
.ea-install-cmd:hover {
background: #44403c;
}
.ea-install-cmd .ea-prompt {
color: var(--ea-accent);
}
/* --- Footer --- */
.ea-footer {
position: relative;
z-index: 1;
padding: 36px 60px;
border-top: 1px solid var(--ea-border);
display: flex;
justify-content: space-between;
align-items: center;
}
.ea-footer-copyright {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
color: var(--ea-light);
letter-spacing: 0.04em;
}
.ea-footer-links {
display: flex;
gap: 28px;
}
.ea-footer-link {
color: var(--ea-light);
text-decoration: none;
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
letter-spacing: 0.04em;
transition: color 0.3s ease;
}
.ea-footer-link:hover {
color: var(--ea-text);
}
.ea-footer-social {
display: flex;
gap: 16px;
}
.ea-footer-social a {
color: var(--ea-light);
transition: color 0.3s ease;
}
.ea-footer-social a:hover {
color: var(--ea-text);
}
/* --- Responsive --- */
@media (max-width: 768px) {
.ea-nav {
padding: 20px 24px;
}
.ea-nav-links {
display: none;
}
.ea-mobile-toggle {
display: block;
}
.ea-mobile-menu {
padding: 24px;
}
.ea-hero {
padding: 72px 24px 60px;
}
.ea-hero-ctas {
flex-direction: column;
align-items: flex-start;
}
.ea-stats-inner {
grid-template-columns: 1fr;
gap: 0;
}
.ea-stat {
border-right: none;
border-bottom: 1px solid var(--ea-border);
padding: 24px 0;
}
.ea-stat:last-child {
border-bottom: none;
}
.ea-section {
padding: 0 24px 64px;
}
.ea-section-title {
font-size: 28px;
}
.ea-pricing {
padding: 64px 24px;
}
.ea-pricing-grid {
grid-template-columns: 1fr;
}
.ea-testimonial-section {
padding: 64px 0;
}
.ea-testimonial-quote {
font-size: 22px;
}
.ea-testimonial-mark {
font-size: 80px;
}
.ea-cta-section {
padding: 64px 24px;
}
.ea-footer {
flex-direction: column;
gap: 16px;
text-align: center;
padding: 28px 24px;
}
.ea-value-number {
font-size: 28px;
width: 32px;
}
.ea-stats {
padding: 48px 24px;
}
.ea-rule {
padding: 0 24px;
}
.ea-downloads {
padding: 0 24px 48px;
}
.ea-used-by {
padding: 48px 24px 64px;
}
}
@media (max-width: 480px) {
.ea-hero h1 {
font-size: 32px;
}
.ea-stat-value {
font-size: 36px;
}
.ea-accordion-title {
font-size: 18px;
}
}
/* Blog content markdown styles */
.ea-blog-content h1, .ea-blog-content h2, .ea-blog-content h3, .ea-blog-content h4 {
color: var(--ea-text); font-family: 'Playfair Display', serif; margin: 1.5em 0 0.5em;
}
.ea-blog-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--ea-border); padding-bottom: 8px; }
.ea-blog-content h3 { font-size: 1.25em; }
.ea-blog-content a { color: var(--ea-accent); text-decoration: underline; }
.ea-blog-content a:hover { opacity: 0.7; }
.ea-blog-content code { background: var(--ea-surface); padding: 2px 6px; border-radius: 3px; font-size: 0.9em; }
.ea-blog-content pre { background: var(--ea-ink); color: #e4e4e7; border-radius: 6px; padding: 16px; overflow-x: auto; margin: 16px 0; }
.ea-blog-content pre code { background: none; padding: 0; color: inherit; }
.ea-blog-content blockquote { border-left: 3px solid var(--ea-accent); padding-left: 16px; color: var(--ea-muted); margin: 16px 0; font-style: italic; }
.ea-blog-content img { max-width: 100%; border-radius: 6px; margin: 16px 0; }
.ea-blog-content ul, .ea-blog-content ol { padding-left: 24px; margin: 12px 0; }
.ea-blog-content li { margin: 4px 0; }
.ea-blog-content table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.ea-blog-content th, .ea-blog-content td { border: 1px solid var(--ea-border); padding: 8px 12px; text-align: left; }
.ea-blog-content th { background: var(--ea-surface); font-weight: 600; }
.ea-blog-content hr { border: none; border-top: 1px solid var(--ea-border); margin: 24px 0; }
</style>
<div class="ea-page">
<!-- Navigation -->
<nav class="ea-nav">
<a href="/" class="ea-nav-brand">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</a>
<div class="ea-nav-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ea-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ea-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="ea-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ea-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ea-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="#why" class="ea-nav-link">Why</a>{{end}}
{{if .Config.Features}}<a href="#features" class="ea-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="#pricing" class="ea-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="ea-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="ea-nav-link">Gallery</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="ea-btn-text">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" 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="ea-mobile-toggle" onclick="document.getElementById('ea-mobile-nav').classList.toggle('open')">Menu</button>
</nav>
<div class="ea-mobile-menu" id="ea-mobile-nav">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ea-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ea-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="ea-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ea-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ea-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="#why" class="ea-nav-link">Why</a>{{end}}
{{if .Config.Features}}<a href="#features" class="ea-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="#pricing" class="ea-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="ea-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="ea-nav-link">Gallery</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="ea-btn-text">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
Repository
</a>
{{end}}
</div>
{{if .PageIsBlogDetail}}
<!-- Blog Detail View -->
<section class="ea-hero" style="padding-top: 100px; min-height: auto;">
<div style="max-width: 720px; margin: 0 auto; padding: 0 24px;">
{{if .BlogPost.FeaturedImage}}
<div style="margin-bottom: 32px; border-radius: 6px; overflow: hidden;">
<img src="{{.BlogPost.FeaturedImage.DownloadURL}}" alt="{{.BlogPost.Title}}" style="width: 100%; max-height: 400px; object-fit: cover; display: block;">
</div>
{{end}}
<h1 style="font-family: 'Playfair Display', serif; font-size: 36px; margin-bottom: 8px; color: var(--ea-text);">{{.BlogPost.Title}}</h1>
{{if .BlogPost.Subtitle}}<p style="font-family: 'Cormorant Garamond', serif; font-size: 1.25rem; color: var(--ea-muted); margin-bottom: 24px;">{{.BlogPost.Subtitle}}</p>{{end}}
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 48px; font-size: 14px; color: var(--ea-muted);">
{{if .BlogPost.Author}}<span>{{.BlogPost.Author.DisplayName}}</span><span>&middot;</span>{{end}}
<span>{{DateUtils.AbsoluteShort .BlogPost.CreatedUnix}}</span>
{{if .BlogTags}}<span>&middot;</span>{{range .BlogTags}}<span style="background: var(--ea-surface); padding: 2px 8px; border-radius: 3px; font-size: 12px; color: var(--ea-accent);">{{.}}</span> {{end}}{{end}}
</div>
<div class="markup ea-blog-content" style="color: var(--ea-text); line-height: 1.8; font-size: 16px; font-family: 'Cormorant Garamond', serif;">
{{.BlogRenderedContent}}
</div>
<div style="margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--ea-border);">
<a href="{{.BlogBaseURL}}" class="ea-btn-text" style="text-decoration: none;">
{{svg "octicon-arrow-left" 16}} Back to Blog
</a>
</div>
</div>
</section>
{{else if .PageIsBlogList}}
<!-- Blog List View -->
<section class="ea-section" style="padding-top: 100px;">
<div class="ea-section-inner">
<div class="ea-section-header ea-reveal">
<div class="ea-section-eyebrow">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="ea-values-list">
{{range .BlogListPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ea-value-item ea-reveal" style="text-decoration: none; color: inherit;">
{{if .FeaturedImage}}
<div style="width: 140px; min-width: 140px; height: 90px; border-radius: 6px; overflow: hidden; margin-right: 24px;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 100%; object-fit: cover; display: block;">
</div>
{{end}}
<div style="flex: 1;">
<h3 style="font-family: 'Playfair Display', serif; font-size: 1.1rem; margin-bottom: 4px;">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p style="color: var(--ea-muted); font-size: 14px; margin-bottom: 4px;">{{.Subtitle}}</p>
{{end}}
<div style="font-size: 12px; color: var(--ea-light);">
{{if .Author}}{{.Author.DisplayName}} &middot; {{end}}{{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</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="ea-hero">
<div class="ea-reveal">
<div class="ea-hero-eyebrow">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}Open Source{{end}}</div>
</div>
<h1 class="ea-reveal ea-reveal-delay-1">{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}</h1>
<p class="ea-hero-sub ea-reveal ea-reveal-delay-2">{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}</p>
<div class="ea-hero-ctas ea-reveal ea-reveal-delay-3">
{{if .Config.Hero.PrimaryCTA.Label}}
<a href="{{.Config.Hero.PrimaryCTA.URL}}" class="ea-btn-primary" data-cta="primary">
{{.Config.Hero.PrimaryCTA.Label}}
{{svg "octicon-arrow-right" 14}}
</a>
{{else}}
<a href="{{.RepoURL}}" class="ea-btn-primary" data-cta="primary">
Get Started
{{svg "octicon-arrow-right" 14}}
</a>
{{end}}
</div>
{{if .Config.Hero.CodeExample}}
<div class="ea-code-block ea-reveal ea-reveal-delay-4">
<button class="ea-copy-btn" onclick="navigator.clipboard.writeText(document.getElementById('code-example').textContent)">
{{svg "octicon-copy" 14}}
</button>
<code id="code-example">{{.Config.Hero.CodeExample}}</code>
</div>
{{end}}
</section>
{{if or .Config.Stats (gt .NumStars 0)}}
<div class="ea-rule"><div class="ea-rule-inner"></div></div>
<!-- Stats -->
<section class="ea-stats">
<div class="ea-stats-inner">
{{if .Config.Stats}}
{{range .Config.Stats}}
<div class="ea-stat ea-reveal">
<div class="ea-stat-value">{{.Value}}</div>
<div class="ea-stat-label">{{.Label}}</div>
</div>
{{end}}
{{else}}
<div class="ea-stat ea-reveal">
<div class="ea-stat-value">{{.NumStars}}</div>
<div class="ea-stat-label">Stars</div>
</div>
<div class="ea-stat ea-reveal ea-reveal-delay-1">
<div class="ea-stat-value">{{.NumForks}}</div>
<div class="ea-stat-label">Forks</div>
</div>
{{if .LatestRelease}}
<div class="ea-stat ea-reveal ea-reveal-delay-2">
<div class="ea-stat-value">v{{.LatestReleaseTag}}</div>
<div class="ea-stat-label">Latest</div>
</div>
{{end}}
{{end}}
</div>
</section>
<div class="ea-rule"><div class="ea-rule-inner"></div></div>
{{end}}
{{if and .PublicReleases .LatestRelease .LatestRelease.Attachments}}
<section class="ea-downloads">
<div class="ea-section-label ea-reveal">Downloads</div>
<h2 class="ea-section-title ea-reveal">v{{.LatestReleaseTag}}</h2>
<p style="color: var(--ea-muted); font-size: 17px; margin-bottom: 28px;" class="ea-reveal">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: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 14}} Windows</h4>
<div class="ea-downloads-list">
{{range $windowsFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $macosFiles}}
<div style="margin-bottom: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 14}} macOS</h4>
<div class="ea-downloads-list">
{{range $macosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $linuxFiles}}
<div style="margin-bottom: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-terminal" 14}} Linux</h4>
<div class="ea-downloads-list">
{{range $linuxFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if not $.HideMobileReleases}}
{{if $androidFiles}}
<div style="margin-bottom: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 14}} Android</h4>
<div class="ea-downloads-list">
{{range $androidFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $iosFiles}}
<div style="margin-bottom: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 14}} iOS</h4>
<div class="ea-downloads-list">
{{range $iosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{end}}
{{if or $.GooglePlayID $.AppStoreID}}
<div style="margin-bottom: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 14}} App Stores</h4>
<div style="display: flex; gap: 12px; flex-wrap: wrap;">
{{if $.GooglePlayID}}
<a href="https://play.google.com/store/apps/details?id={{$.GooglePlayID}}" target="_blank" rel="noopener" class="ea-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="18" height="18" 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="ea-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="18" height="18" 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: 20px;" class="ea-reveal">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-file" 14}} Other</h4>
<div class="ea-downloads-list">
{{range $otherFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ea-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ea-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
</section>
<div class="ea-rule"><div class="ea-rule-inner"></div></div>
{{end}}
<!-- Value Props -->
{{if .Config.ValueProps}}
<section class="ea-section" id="why">
<div class="ea-section-label ea-reveal">Why choose this</div>
<h2 class="ea-section-title ea-reveal">{{if .Config.Brand.Name}}Why {{.Config.Brand.Name}}{{else}}Why Choose Us{{end}}</h2>
{{range $i, $v := .Config.ValueProps}}
<div class="ea-value-item ea-reveal">
<div class="ea-value-number">{{$i | printf "%d"}}</div>
<div class="ea-value-body">
<div class="ea-value-title">{{$v.Title}}</div>
<div class="ea-value-desc">{{$v.Description}}</div>
</div>
</div>
{{end}}
</section>
{{end}}
<!-- Features Accordion -->
{{if .Config.Features}}
<section class="ea-section" id="features">
<div class="ea-section-label ea-reveal">Capabilities</div>
<h2 class="ea-section-title ea-reveal">Features</h2>
<div class="ea-accordion ea-reveal">
{{range $i, $f := .Config.Features}}
<div class="ea-accordion-item" data-index="{{$i}}">
<button class="ea-accordion-header" onclick="toggleAccordion(this)">
<span class="ea-accordion-title">{{$f.Title}}</span>
<span class="ea-accordion-icon">+</span>
</button>
<div class="ea-accordion-content">
{{$f.Description}}
</div>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Pricing Section -->
{{if .Config.Pricing.Plans}}
<section class="ea-pricing" id="pricing">
<div class="ea-section-label ea-reveal" style="max-width: 780px; margin: 0 auto 20px;">Investment</div>
<h2 class="ea-pricing-title ea-reveal">{{if .Config.Pricing.Headline}}{{.Config.Pricing.Headline}}{{else}}Pricing{{end}}</h2>
<div class="ea-pricing-grid ea-reveal">
{{range .Config.Pricing.Plans}}
<div class="ea-pricing-card{{if .Featured}} featured{{end}}">
{{if .Featured}}<span class="ea-pricing-featured-badge">Recommended</span>{{end}}
<div class="ea-pricing-name">{{.Name}}</div>
<div class="ea-pricing-price">{{.Price}}</div>
<div class="ea-pricing-period">{{.Period}}</div>
{{if .Features}}
<ul class="ea-pricing-features">
{{range .Features}}
<li>{{.}}</li>
{{end}}
</ul>
{{end}}
<a href="#" class="ea-pricing-cta">{{if .CTA}}{{.CTA}}{{else}}Get Started{{end}}</a>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Testimonial -->
{{if .Config.SocialProof.Testimonials}}
<section class="ea-testimonial-section">
<div class="ea-testimonial-inner">
<div class="ea-testimonials-container">
{{range .Config.SocialProof.Testimonials}}
<div class="ea-testimonial-item" style="display: none;">
<div class="ea-testimonial-mark ea-reveal">&ldquo;</div>
<blockquote class="ea-testimonial-quote ea-reveal ea-reveal-delay-1">{{.Quote}}</blockquote>
<div class="ea-reveal ea-reveal-delay-2">
<div class="ea-testimonial-attribution">
<div class="ea-testimonial-dash"></div>
<span class="ea-testimonial-author">{{.Author}}</span>
</div>
<div class="ea-testimonial-role">{{.Role}}</div>
</div>
</div>
{{end}}
</div>
</div>
</section>
<script>
(function() {
var items = document.querySelectorAll(".ea-testimonial-item");
if (items.length > 0) {
var idx = Math.floor(Math.random() * items.length);
items[idx].style.display = "block";
}
})();
</script>
{{end}}
<!-- Used By -->
{{if .Config.SocialProof.Logos}}
<section class="ea-used-by">
<div class="ea-section-label ea-reveal">Trusted by</div>
<div class="ea-used-by-logos ea-reveal ea-reveal-delay-1">
{{range .Config.SocialProof.Logos}}
<span class="ea-used-by-item">{{.}}</span>
{{end}}
</div>
</section>
{{end}}
<!-- CTA Section -->
{{if .Config.CTASection.Headline}}
<section class="ea-cta-section">
<h2 class="ea-reveal">{{.Config.CTASection.Headline}}</h2>
{{if .Config.CTASection.Subheadline}}
<button class="ea-install-cmd ea-reveal ea-reveal-delay-1" onclick="navigator.clipboard.writeText('{{.Config.CTASection.Subheadline}}')">
<span class="ea-prompt">$</span>
{{.Config.CTASection.Subheadline}}
{{svg "octicon-copy" 14}}
</button>
{{end}}
{{if .Config.CTASection.Button.Label}}
<div class="ea-reveal ea-reveal-delay-2">
<a href="{{.Config.CTASection.Button.URL}}" class="ea-btn-primary" data-cta="primary">
{{.Config.CTASection.Button.Label}}
{{svg "octicon-arrow-right" 14}}
</a>
</div>
{{end}}
</section>
{{end}}
<!-- Blog Section -->
{{if and .Config.Blog.Enabled .BlogPosts}}
<section class="ea-section" id="blog">
<div class="ea-section-label ea-reveal">Blog</div>
<h2 class="ea-section-title ea-reveal">{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}Latest Posts{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p style="color: var(--ea-muted); font-size: 17px; margin-bottom: 32px;" class="ea-reveal">{{.Config.Blog.Subheadline}}</p>{{end}}
{{range .BlogPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ea-value-item ea-reveal" style="text-decoration: none; color: inherit;">
{{if .FeaturedImage}}
<div style="flex-shrink: 0; width: 120px; height: 80px; overflow: hidden; border-radius: 4px;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 100%; object-fit: cover;">
</div>
{{end}}
<div class="ea-value-body">
<div class="ea-value-title">{{.Title}}</div>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<div class="ea-value-desc">{{.Subtitle}}</div>
{{end}}
<div style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ea-light); letter-spacing: 0.04em; margin-top: 4px;">
{{if .Author}}{{.Author.DisplayName}}{{end}} · {{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</div>
</a>
{{end}}
{{if .Config.Blog.CTAButton.Label}}
<div style="margin-top: 32px;" class="ea-reveal">
<a href="{{if .Config.Blog.CTAButton.URL}}{{.Config.Blog.CTAButton.URL}}{{else}}{{.BlogBaseURL}}{{end}}" class="ea-btn-text">
{{.Config.Blog.CTAButton.Label}}
{{svg "octicon-arrow-right" 14}}
</a>
</div>
{{end}}
</section>
{{end}}
<!-- Gallery Section -->
{{if and .Config.Gallery.Enabled .GalleryImages}}
<section class="ea-section" id="gallery">
<div class="ea-section-label ea-reveal">Gallery</div>
<h2 class="ea-section-title ea-reveal">{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}Gallery{{end}}</h2>
{{if .Config.Gallery.Subheadline}}<p style="color: var(--ea-muted); font-size: 17px; margin-bottom: 32px;" class="ea-reveal">{{.Config.Gallery.Subheadline}}</p>{{end}}
<div style="display: grid; grid-template-columns: repeat({{if .Config.Gallery.Columns}}{{.Config.Gallery.Columns}}{{else}}3{{end}}, 1fr); gap: 16px;">
{{range .GalleryImages}}
<div class="ea-reveal" style="overflow: hidden; border-radius: 4px; border: 1px solid var(--ea-border);">
<a href="{{.URL}}" target="_blank" style="display: block;">
<img src="{{.URL}}" alt="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="width: 100%; height: 200px; object-fit: cover; display: block;">
</a>
{{if .Caption}}
<div style="padding: 12px 16px; font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: var(--ea-light); letter-spacing: 0.04em;">{{.Caption}}</div>
{{end}}
</div>
{{end}}
</div>
</section>
{{end}}
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
<!-- Footer -->
<footer class="ea-footer">
<span class="ea-footer-copyright">{{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>
{{if .Config.Footer.Social}}
<div class="ea-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="ea-footer-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ea-footer-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowRepository}}<a href="{{.RepoURL}}" class="ea-footer-link">Repository</a>{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ea-footer-link">Documentation</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ea-footer-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ea-footer-link">Issues</a>{{end}}
</div>
</footer>
</div>
<script>
function toggleAccordion(header) {
var item = header.parentElement;
var wasOpen = item.classList.contains('open');
document.querySelectorAll('.ea-accordion-item').forEach(function(el) {
el.classList.remove('open');
el.querySelector('.ea-accordion-icon').textContent = '+';
});
if (!wasOpen) {
item.classList.add('open');
item.querySelector('.ea-accordion-icon').textContent = '+';
}
}
/* Scroll reveal */
(function() {
var reveals = document.querySelectorAll('.ea-reveal');
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" .}}