-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
173 lines (157 loc) · 4.94 KB
/
Copy pathmain.go
File metadata and controls
173 lines (157 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Command gen renders all site content for vasic.digital and milosvasic.ru
// dynamically from _content/** and design-system/**. No page is hardcoded:
// Go holds only layout/templates; every product name, status, tech, repo, and
// copy string comes from _content/products/*.md, _content/portfolio/portfolio.json,
// _content/sites/*.home.json, and design-system/diagrams|icons.
//
// Usage:
//
// gen -site <vasic.digital|milosvasic.ru> [-lang en] [-what all|products|portfolio|home]
// [-root <repo>] [-out <dir>]
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"
)
type Site struct {
Key string
Brand string
CSSName string // basename of the deployed brand CSS at <site>/assets/od/<CSSName>.css
HomeJSON string // path (relative to root) of the homepage content data
Dir string // default output dir (relative to root)
Domain string // production host (from CNAME), no scheme
OGImage string // root-relative Open Graph / letterhead image that exists on disk
LDKind string // JSON-LD identity: "Organization" | "Person"
SameAs []string // JSON-LD sameAs profile URLs
}
// URL builds an absolute production URL from a root-relative path (no leading /).
func (s *Site) URL(path string) string {
return "https://" + s.Domain + "/" + strings.TrimPrefix(path, "/")
}
var sites = map[string]*Site{
"vasic.digital": {
Key: "vasic.digital",
Brand: "Vasic Digital",
CSSName: "vasic-digital",
HomeJSON: "_content/sites/vasic-digital.home.json",
Dir: "vasic.digital",
Domain: "vasic.digital",
OGImage: "Assets/Logo.jpeg",
LDKind: "Organization",
SameAs: []string{"https://github.com/Helix-Track", "https://github.com/nexu-io"},
},
"milosvasic.ru": {
Key: "milosvasic.ru",
Brand: "Miloš Vasić",
CSSName: "milosvasic",
HomeJSON: "_content/sites/milosvasic-ru.home.json",
Dir: "milosvasic.ru",
Domain: "milosvasic.ru",
OGImage: "assets/images/profile-800.jpg",
LDKind: "Person",
SameAs: []string{
"https://github.com/milos85vasic",
"https://gitlab.com/milos85vasic",
"https://t.me/milos85vasic",
},
},
}
func writeFile(path, content string) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}
return os.WriteFile(path, []byte(content), 0o644)
}
func main() {
var siteKey, lang, what, root, out string
flag.StringVar(&siteKey, "site", "", "target site: vasic.digital | milosvasic.ru")
flag.StringVar(&lang, "lang", "en", "language code")
flag.StringVar(&what, "what", "all", "what to render: all | products | portfolio | home")
flag.StringVar(&root, "root", ".", "repository root")
flag.StringVar(&out, "out", "", "output base dir (default: <root>/<site>)")
flag.Parse()
site, ok := sites[siteKey]
if !ok {
fmt.Fprintln(os.Stderr, "error: -site must be vasic.digital or milosvasic.ru")
os.Exit(2)
}
absRoot, err := filepath.Abs(root)
if err != nil {
fatal(err)
}
if out == "" {
out = filepath.Join(absRoot, site.Dir)
} else {
out, _ = filepath.Abs(out)
}
langSeg := ""
if lang != "" && lang != "en" {
langSeg = lang
}
p, err := loadPortfolio(filepath.Join(absRoot, "_content", "portfolio", "portfolio.json"))
if err != nil {
fatal(fmt.Errorf("portfolio: %w", err))
}
langs := availableLangs(absRoot)
nProducts := 0
if what == "all" || what == "products" {
for i := range p.Entries {
e := &p.Entries[i]
html, err := renderProduct(absRoot, site, e, langs)
if err != nil {
fatal(err)
}
var dest string
if langSeg != "" {
dest = filepath.Join(out, "products", langSeg, e.Slug+".html")
} else {
dest = filepath.Join(out, "products", e.Slug+".html")
}
if err := writeFile(dest, html); err != nil {
fatal(err)
}
nProducts++
}
}
if what == "all" || what == "portfolio" {
html := renderPortfolio(p, site, langs)
var dest string
if langSeg != "" {
dest = filepath.Join(out, "portfolio", langSeg, "index.html")
} else {
dest = filepath.Join(out, "portfolio", "index.html")
}
if err := writeFile(dest, html); err != nil {
fatal(err)
}
}
if what == "all" || what == "home" {
if langSeg != "" {
fmt.Printf("[gen] %s: skipping homepage for lang=%s (EN-only content data)\n", site.Key, lang)
} else {
doc, err := loadHome(filepath.Join(absRoot, site.HomeJSON))
if err != nil {
fatal(fmt.Errorf("home: %w", err))
}
html := renderHome(doc, p, site, langs)
if err := writeFile(filepath.Join(out, "index.html"), html); err != nil {
fatal(err)
}
}
}
// sitemap.xml + robots.txt reflect the files actually generated (EN only for
// now), so every sitemap URL resolves. Generated for a full "all" build.
if what == "all" && langSeg == "" {
if err := writeSitemapRobots(site, out); err != nil {
fatal(fmt.Errorf("sitemap/robots: %w", err))
}
}
fmt.Printf("[gen] site=%s lang=%s what=%s out=%s products=%d\n", site.Key, lang, what, out, nProducts)
}
func fatal(err error) {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}