2
0
Files
gitcaddy-server/templates/pages/minimalist-docs.tmpl
logikonline 5e165b97be feat(pages): add option to hide mobile releases from landing page
Add HideMobileReleases config option to hide Android and iOS releases from the downloads section on landing pages. Useful when mobile apps are distributed via app stores rather than direct downloads. Adds checkbox in Content settings and conditional rendering in all four page templates.
2026-03-16 01:22:52 -04:00

1515 lines
44 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 $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" .}}