feat(pages): add gallery section to landing page templates
Add configurable gallery section that displays images from repository's .gallery folder on landing pages. Includes settings for enabled/disabled, headline, subheadline, max images (default 6), and grid columns (default 3). Reads captions from gallery.json metadata. Implements gallery rendering in all four page templates (bold-marketing, minimalist-docs, open-source-hero, saas-conversion). Integrates with existing gallery management feature.
This commit is contained in:
@@ -47,6 +47,9 @@ type LandingConfig struct {
|
|||||||
// Blog section
|
// Blog section
|
||||||
Blog BlogSectionConfig `yaml:"blog,omitempty"`
|
Blog BlogSectionConfig `yaml:"blog,omitempty"`
|
||||||
|
|
||||||
|
// Gallery section
|
||||||
|
Gallery GallerySectionConfig `yaml:"gallery,omitempty"`
|
||||||
|
|
||||||
// Navigation visibility
|
// Navigation visibility
|
||||||
Navigation NavigationConfig `yaml:"navigation,omitempty"`
|
Navigation NavigationConfig `yaml:"navigation,omitempty"`
|
||||||
|
|
||||||
@@ -196,6 +199,15 @@ type BlogSectionConfig struct {
|
|||||||
CTAButton CTAButton `yaml:"cta_button,omitempty"` // "View All Posts" link
|
CTAButton CTAButton `yaml:"cta_button,omitempty"` // "View All Posts" link
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GallerySectionConfig represents gallery section settings on the landing page
|
||||||
|
type GallerySectionConfig struct {
|
||||||
|
Enabled bool `yaml:"enabled,omitempty"`
|
||||||
|
Headline string `yaml:"headline,omitempty"`
|
||||||
|
Subheadline string `yaml:"subheadline,omitempty"`
|
||||||
|
MaxImages int `yaml:"max_images,omitempty"` // default 6
|
||||||
|
Columns int `yaml:"columns,omitempty"` // grid columns, default 3
|
||||||
|
}
|
||||||
|
|
||||||
// NavigationConfig controls which built-in navigation links appear in the header and footer
|
// NavigationConfig controls which built-in navigation links appear in the header and footer
|
||||||
type NavigationConfig struct {
|
type NavigationConfig struct {
|
||||||
ShowDocs bool `yaml:"show_docs,omitempty"`
|
ShowDocs bool `yaml:"show_docs,omitempty"`
|
||||||
|
|||||||
@@ -737,6 +737,13 @@
|
|||||||
"repo.settings.pages.stats": "Stats",
|
"repo.settings.pages.stats": "Stats",
|
||||||
"repo.settings.pages.value_props": "Value Propositions",
|
"repo.settings.pages.value_props": "Value Propositions",
|
||||||
"repo.settings.pages.features": "Features",
|
"repo.settings.pages.features": "Features",
|
||||||
|
"repo.settings.pages.gallery_section": "Gallery Section",
|
||||||
|
"repo.settings.pages.gallery_enabled_desc": "Show a gallery of images from your repository's .gallery folder on the landing page",
|
||||||
|
"repo.settings.pages.gallery_headline": "Gallery Headline",
|
||||||
|
"repo.settings.pages.gallery_subheadline": "Gallery Subheadline",
|
||||||
|
"repo.settings.pages.gallery_max_images": "Maximum Images to Show",
|
||||||
|
"repo.settings.pages.gallery_columns": "Grid Columns",
|
||||||
|
"repo.settings.pages.gallery_help_link": "Upload and manage gallery images in Settings > Gallery.",
|
||||||
"repo.settings.pages.company_logos": "Company Logos",
|
"repo.settings.pages.company_logos": "Company Logos",
|
||||||
"repo.settings.pages.testimonials": "Testimonials",
|
"repo.settings.pages.testimonials": "Testimonials",
|
||||||
"repo.settings.pages.pricing_headline": "Pricing Headline",
|
"repo.settings.pages.pricing_headline": "Pricing Headline",
|
||||||
|
|||||||
@@ -4544,6 +4544,13 @@
|
|||||||
"repo.settings.pages.blog_headline": "Blog Headline",
|
"repo.settings.pages.blog_headline": "Blog Headline",
|
||||||
"repo.settings.pages.blog_subheadline": "Blog Subheadline",
|
"repo.settings.pages.blog_subheadline": "Blog Subheadline",
|
||||||
"repo.settings.pages.blog_max_posts": "Maximum Posts to Show",
|
"repo.settings.pages.blog_max_posts": "Maximum Posts to Show",
|
||||||
|
"repo.settings.pages.gallery_section": "Gallery Section",
|
||||||
|
"repo.settings.pages.gallery_enabled_desc": "Show a gallery of images from your repository's .gallery folder on the landing page",
|
||||||
|
"repo.settings.pages.gallery_headline": "Gallery Headline",
|
||||||
|
"repo.settings.pages.gallery_subheadline": "Gallery Subheadline",
|
||||||
|
"repo.settings.pages.gallery_max_images": "Maximum Images to Show",
|
||||||
|
"repo.settings.pages.gallery_columns": "Grid Columns",
|
||||||
|
"repo.settings.pages.gallery_help_link": "Upload and manage gallery images in Settings > Gallery.",
|
||||||
"repo.settings.pages.ai_generate": "AI Content Generator",
|
"repo.settings.pages.ai_generate": "AI Content Generator",
|
||||||
"repo.settings.pages.ai_generate_desc": "Automatically generate landing page content (headline, features, stats, CTAs) from your repository's README and metadata using AI.",
|
"repo.settings.pages.ai_generate_desc": "Automatically generate landing page content (headline, features, stats, CTAs) from your repository's README and metadata using AI.",
|
||||||
"repo.settings.pages.ai_generate_button": "Generate Content with AI",
|
"repo.settings.pages.ai_generate_button": "Generate Content with AI",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"code.gitcaddy.com/server/v3/models/renderhelper"
|
"code.gitcaddy.com/server/v3/models/renderhelper"
|
||||||
repo_model "code.gitcaddy.com/server/v3/models/repo"
|
repo_model "code.gitcaddy.com/server/v3/models/repo"
|
||||||
"code.gitcaddy.com/server/v3/modules/git"
|
"code.gitcaddy.com/server/v3/modules/git"
|
||||||
|
"code.gitcaddy.com/server/v3/modules/gitrepo"
|
||||||
"code.gitcaddy.com/server/v3/modules/json"
|
"code.gitcaddy.com/server/v3/modules/json"
|
||||||
"code.gitcaddy.com/server/v3/modules/log"
|
"code.gitcaddy.com/server/v3/modules/log"
|
||||||
"code.gitcaddy.com/server/v3/modules/markup/markdown"
|
"code.gitcaddy.com/server/v3/modules/markup/markdown"
|
||||||
@@ -196,6 +197,14 @@ func renderLandingPage(ctx *context.Context, repo *repo_model.Repository, config
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load gallery images if gallery section is enabled
|
||||||
|
if config.Gallery.Enabled {
|
||||||
|
images := loadGalleryImagesForLanding(ctx, repo, config)
|
||||||
|
if len(images) > 0 {
|
||||||
|
ctx.Data["GalleryImages"] = images
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tpl := selectTemplate(config.Template)
|
tpl := selectTemplate(config.Template)
|
||||||
ctx.HTML(http.StatusOK, tpl)
|
ctx.HTML(http.StatusOK, tpl)
|
||||||
}
|
}
|
||||||
@@ -315,6 +324,94 @@ func getPageTitle(repo *repo_model.Repository, config *pages_module.LandingConfi
|
|||||||
return repo.Name
|
return repo.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GalleryImageInfo holds gallery image data for landing page templates
|
||||||
|
type GalleryImageInfo struct {
|
||||||
|
Name string
|
||||||
|
Caption string
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadGalleryImagesForLanding reads gallery images from the .gallery folder
|
||||||
|
func loadGalleryImagesForLanding(ctx *context.Context, repo *repo_model.Repository, config *pages_module.LandingConfig) []GalleryImageInfo {
|
||||||
|
if repo.IsEmpty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryEntry, err := commit.GetTreeEntryByPath(".gallery")
|
||||||
|
if err != nil || !galleryEntry.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load metadata for captions
|
||||||
|
var metadata struct {
|
||||||
|
Images []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Caption string `json:"caption"`
|
||||||
|
} `json:"images"`
|
||||||
|
}
|
||||||
|
if entry, err := commit.GetTreeEntryByPath(".gallery/gallery.json"); err == nil {
|
||||||
|
if content, err := entry.Blob().GetBlobContent(100000); err == nil {
|
||||||
|
_ = json.Unmarshal([]byte(content), &metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
captionMap := make(map[string]string)
|
||||||
|
for _, img := range metadata.Images {
|
||||||
|
captionMap[img.Name] = img.Caption
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err := commit.SubTree(".gallery")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := tree.ListEntries()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
maxImages := config.Gallery.MaxImages
|
||||||
|
if maxImages <= 0 {
|
||||||
|
maxImages = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
var images []GalleryImageInfo
|
||||||
|
for _, entry := range entries {
|
||||||
|
if entry.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := entry.Name()
|
||||||
|
if name == "gallery.json" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ext := strings.ToLower(path.Ext(name))
|
||||||
|
switch ext {
|
||||||
|
case ".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp":
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
images = append(images, GalleryImageInfo{
|
||||||
|
Name: name,
|
||||||
|
Caption: captionMap[name],
|
||||||
|
URL: repo.Link() + "/raw/" + repo.DefaultBranch + "/.gallery/" + name,
|
||||||
|
})
|
||||||
|
if len(images) >= maxImages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return images
|
||||||
|
}
|
||||||
|
|
||||||
// loadReadmeContent loads and renders the README content
|
// loadReadmeContent loads and renders the README content
|
||||||
func loadReadmeContent(ctx *context.Context, repo *repo_model.Repository) (template.HTML, error) {
|
func loadReadmeContent(ctx *context.Context, repo *repo_model.Repository) (template.HTML, error) {
|
||||||
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
|
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
|
||||||
|
|||||||
@@ -545,6 +545,15 @@ func PagesContentPost(ctx *context.Context) {
|
|||||||
if maxPosts := ctx.FormInt("blog_max_posts"); maxPosts > 0 {
|
if maxPosts := ctx.FormInt("blog_max_posts"); maxPosts > 0 {
|
||||||
config.Blog.MaxPosts = maxPosts
|
config.Blog.MaxPosts = maxPosts
|
||||||
}
|
}
|
||||||
|
config.Gallery.Enabled = ctx.FormBool("gallery_enabled")
|
||||||
|
config.Gallery.Headline = ctx.FormString("gallery_headline")
|
||||||
|
config.Gallery.Subheadline = ctx.FormString("gallery_subheadline")
|
||||||
|
if maxImages := ctx.FormInt("gallery_max_images"); maxImages > 0 {
|
||||||
|
config.Gallery.MaxImages = maxImages
|
||||||
|
}
|
||||||
|
if cols := ctx.FormInt("gallery_columns"); cols >= 2 && cols <= 4 {
|
||||||
|
config.Gallery.Columns = cols
|
||||||
|
}
|
||||||
config.Stats = nil
|
config.Stats = nil
|
||||||
for i := range 10 {
|
for i := range 10 {
|
||||||
value := ctx.FormString(fmt.Sprintf("stat_value_%d", i))
|
value := ctx.FormString(fmt.Sprintf("stat_value_%d", i))
|
||||||
|
|||||||
@@ -1136,6 +1136,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="nb-nav-link">Features</a>{{end}}
|
{{if .Config.Features}}<a href="#features" class="nb-nav-link">Features</a>{{end}}
|
||||||
{{if .Config.Pricing.Plans}}<a href="#pricing" class="nb-nav-link">Pricing</a>{{end}}
|
{{if .Config.Pricing.Plans}}<a href="#pricing" class="nb-nav-link">Pricing</a>{{end}}
|
||||||
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="nb-nav-link">Blog</a>{{end}}
|
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="nb-nav-link">Blog</a>{{end}}
|
||||||
|
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="nb-nav-link">Gallery</a>{{end}}
|
||||||
{{if .Config.Navigation.ShowRepository}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="nb-nav-repo">
|
<a href="{{.RepoURL}}" class="nb-nav-repo">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1174,6 +1175,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="nb-nav-link">Features</a>{{end}}
|
{{if .Config.Features}}<a href="#features" class="nb-nav-link">Features</a>{{end}}
|
||||||
{{if .Config.Pricing.Plans}}<a href="#pricing" class="nb-nav-link">Pricing</a>{{end}}
|
{{if .Config.Pricing.Plans}}<a href="#pricing" class="nb-nav-link">Pricing</a>{{end}}
|
||||||
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="nb-nav-link">Blog</a>{{end}}
|
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="nb-nav-link">Blog</a>{{end}}
|
||||||
|
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="nb-nav-link">Gallery</a>{{end}}
|
||||||
{{if .Config.Navigation.ShowRepository}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="nb-nav-repo">
|
<a href="{{.RepoURL}}" class="nb-nav-repo">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1481,6 +1483,29 @@
|
|||||||
</section>
|
</section>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Gallery Section -->
|
||||||
|
{{if and .Config.Gallery.Enabled .GalleryImages}}
|
||||||
|
<section class="nb-features" id="gallery" style="border-top: 1px solid var(--nb-border-hard);">
|
||||||
|
<div class="nb-section-header nb-reveal">
|
||||||
|
<div class="nb-section-label">Gallery</div>
|
||||||
|
<h2><span class="nb-glow-text">{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}Gallery{{end}}</span></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: 4px;">
|
||||||
|
{{range .GalleryImages}}
|
||||||
|
<div class="nb-reveal" style="overflow: hidden; clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));">
|
||||||
|
<a href="{{.URL}}" target="_blank" style="display: block; position: relative;">
|
||||||
|
<img src="{{.URL}}" alt="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="width: 100%; height: 220px; object-fit: cover; display: block;">
|
||||||
|
{{if .Caption}}
|
||||||
|
<div style="position: absolute; bottom: 0; left: 0; right: 0; padding: 12px 16px; background: linear-gradient(transparent, rgba(0,0,0,0.7)); font-size: 13px; color: #fff;">{{.Caption}}</div>
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
|||||||
@@ -1003,6 +1003,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="ea-nav-link">Features</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.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.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}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="ea-btn-text">
|
<a href="{{.RepoURL}}" class="ea-btn-text">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1036,6 +1037,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="ea-nav-link">Features</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.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.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}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="ea-btn-text">
|
<a href="{{.RepoURL}}" class="ea-btn-text">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1355,6 +1357,27 @@
|
|||||||
</section>
|
</section>
|
||||||
{{end}}
|
{{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 */}}
|
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
|||||||
@@ -994,6 +994,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="osh-nav-link">Features</a>{{end}}
|
{{if .Config.Features}}<a href="#features" class="osh-nav-link">Features</a>{{end}}
|
||||||
{{if .Config.Pricing.Plans}}<a href="#pricing" class="osh-nav-link">Pricing</a>{{end}}
|
{{if .Config.Pricing.Plans}}<a href="#pricing" class="osh-nav-link">Pricing</a>{{end}}
|
||||||
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="osh-nav-link">Blog</a>{{end}}
|
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="osh-nav-link">Blog</a>{{end}}
|
||||||
|
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="osh-nav-link">Gallery</a>{{end}}
|
||||||
{{if .Config.Navigation.ShowRepository}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="osh-nav-cta">
|
<a href="{{.RepoURL}}" class="osh-nav-cta">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1352,6 +1353,31 @@
|
|||||||
</section>
|
</section>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Gallery Section -->
|
||||||
|
{{if and .Config.Gallery.Enabled .GalleryImages}}
|
||||||
|
<section class="osh-features" id="gallery" style="border-top: 1px solid rgba(255,255,255,0.04);">
|
||||||
|
<div class="osh-features-inner">
|
||||||
|
<div class="osh-section-header osh-reveal">
|
||||||
|
<div class="osh-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: 16px;">
|
||||||
|
{{range .GalleryImages}}
|
||||||
|
<div class="osh-feature-card osh-reveal" style="padding: 0; overflow: hidden;">
|
||||||
|
<a href="{{.URL}}" target="_blank" style="display: block;">
|
||||||
|
<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: 16px 20px; font-size: 13px; color: var(--osh-muted);">{{.Caption}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
|||||||
@@ -1111,6 +1111,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
|
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
|
||||||
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
|
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
|
||||||
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
|
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
|
||||||
|
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="gm-nav-link">Gallery</a>{{end}}
|
||||||
{{if .Config.Navigation.ShowRepository}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="gm-nav-repo">
|
<a href="{{.RepoURL}}" class="gm-nav-repo">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1147,6 +1148,7 @@
|
|||||||
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
|
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
|
||||||
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
|
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
|
||||||
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
|
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
|
||||||
|
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="gm-nav-link">Gallery</a>{{end}}
|
||||||
{{if .Config.Navigation.ShowRepository}}
|
{{if .Config.Navigation.ShowRepository}}
|
||||||
<a href="{{.RepoURL}}" class="gm-nav-repo">
|
<a href="{{.RepoURL}}" class="gm-nav-repo">
|
||||||
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
|
||||||
@@ -1491,6 +1493,30 @@
|
|||||||
</section>
|
</section>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Gallery Section -->
|
||||||
|
{{if and .Config.Gallery.Enabled .GalleryImages}}
|
||||||
|
<section class="gm-section" id="gallery">
|
||||||
|
<div class="gm-section-inner">
|
||||||
|
<div class="gm-section-header gm-reveal">
|
||||||
|
<h2>{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}<span class="gm-serif">Gallery</span>{{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: 16px;">
|
||||||
|
{{range .GalleryImages}}
|
||||||
|
<div class="gm-value-card gm-reveal" style="padding: 0; overflow: hidden;">
|
||||||
|
<a href="{{.URL}}" target="_blank" style="display: block;">
|
||||||
|
<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: 16px 20px; font-size: 14px; color: var(--gm-light);">{{.Caption}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
|||||||
@@ -65,6 +65,37 @@
|
|||||||
<input name="blog_max_posts" type="number" min="1" max="12" value="{{if .Config.Blog.MaxPosts}}{{.Config.Blog.MaxPosts}}{{else}}3{{end}}">
|
<input name="blog_max_posts" type="number" min="1" max="12" value="{{if .Config.Blog.MaxPosts}}{{.Config.Blog.MaxPosts}}{{else}}3{{end}}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.pages.gallery_section"}}</h5>
|
||||||
|
<div class="inline field">
|
||||||
|
<div class="ui toggle checkbox">
|
||||||
|
<input type="checkbox" name="gallery_enabled" {{if .Config.Gallery.Enabled}}checked{{end}}>
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pages.gallery_enabled_desc"}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pages.gallery_headline"}}</label>
|
||||||
|
<input name="gallery_headline" value="{{.Config.Gallery.Headline}}" placeholder="Gallery">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pages.gallery_subheadline"}}</label>
|
||||||
|
<input name="gallery_subheadline" value="{{.Config.Gallery.Subheadline}}" placeholder="Screenshots and visuals from the project">
|
||||||
|
</div>
|
||||||
|
<div class="two fields">
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pages.gallery_max_images"}}</label>
|
||||||
|
<input name="gallery_max_images" type="number" min="1" max="24" value="{{if .Config.Gallery.MaxImages}}{{.Config.Gallery.MaxImages}}{{else}}6{{end}}">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pages.gallery_columns"}}</label>
|
||||||
|
<select name="gallery_columns" class="ui dropdown">
|
||||||
|
<option value="2" {{if eq .Config.Gallery.Columns 2}}selected{{end}}>2</option>
|
||||||
|
<option value="3" {{if or (eq .Config.Gallery.Columns 3) (eq .Config.Gallery.Columns 0)}}selected{{end}}>3</option>
|
||||||
|
<option value="4" {{if eq .Config.Gallery.Columns 4}}selected{{end}}>4</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.gallery_help_link"}}</p>
|
||||||
|
|
||||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.pages.stats"}}</h5>
|
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.pages.stats"}}</h5>
|
||||||
<div id="stats-container">
|
<div id="stats-container">
|
||||||
{{range $i, $stat := .Config.Stats}}
|
{{range $i, $stat := .Config.Stats}}
|
||||||
|
|||||||
Reference in New Issue
Block a user