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
|
package build
import (
"fmt"
"html/template"
"log"
"time"
"github.com/HimanshuSardana/kite/pkg/config"
"github.com/HimanshuSardana/kite/pkg/content"
"github.com/HimanshuSardana/kite/pkg/themes"
)
const (
DefaultContentDir = "./content"
DefaultOutputDir = "./output"
DefaultThemesDir = "./themes"
DefaultConfigPath = "./config.yaml"
DefaultThemeName = "modern-light"
)
type BuildOptions struct {
ThemeName string
ContentDir string
OutputDir string
ThemesDir string
ConfigPath string
}
func Build(opts BuildOptions) error {
if opts.ThemeName == "" {
opts.ThemeName = DefaultThemeName
}
if opts.ContentDir == "" {
opts.ContentDir = DefaultContentDir
}
if opts.OutputDir == "" {
opts.OutputDir = DefaultOutputDir
}
if opts.ThemesDir == "" {
opts.ThemesDir = DefaultThemesDir
}
if opts.ConfigPath == "" {
opts.ConfigPath = DefaultConfigPath
}
cfg, err := config.Load(opts.ConfigPath)
if err != nil {
log.Printf("Warning: Could not load config: %v", err)
}
themePath := themes.GetThemePath(opts.ThemesDir, opts.ThemeName)
files, err := content.ListContentFiles(opts.ContentDir)
if err != nil {
return fmt.Errorf("listing content files: %w", err)
}
summaries := make([]content.PostSummary, 0, len(files))
for _, file := range files {
start := time.Now()
parsed, err := ParseMarkdown(file.Path)
if err != nil {
log.Printf("Error parsing %s: %v", file.Path, err)
continue
}
summaries = append(summaries, content.PostSummary{
Title: parsed.Frontmatter.Title,
Slug: file.Slug,
Date: parsed.Frontmatter.Date,
Tags: parsed.Frontmatter.Tags,
})
outputPath, err := content.GetOutputPath(opts.ContentDir, file.Path, opts.OutputDir)
if err != nil {
log.Printf("Error computing output path: %v", err)
continue
}
tmpl, err := LoadTemplate(themePath, "layout.html")
if err != nil {
log.Fatalf("Error loading template: %v", err)
}
page := Page{
Title: parsed.Frontmatter.Title,
Content: template.HTML(parsed.Content),
TOC: parsed.TOC,
Year: time.Now().Year(),
}
if err := RenderPage(tmpl, outputPath, page); err != nil {
log.Printf("Error rendering page: %v", err)
}
elapsed := time.Since(start).Milliseconds()
fmt.Printf("Compiling %s (%dms)\n", parsed.Frontmatter.Title, elapsed)
}
fmt.Println("All files processed!")
if err := RenderHomePage(themePath, opts.OutputDir, opts.ConfigPath, summaries); err != nil {
log.Printf("Error rendering home page: %v", err)
}
siteURL := "https://your-site.com"
if cfg != nil && cfg.SiteURL != "" {
siteURL = cfg.SiteURL
}
if err := GenerateRSS(opts.OutputDir, opts.ConfigPath, siteURL, summaries); err != nil {
log.Printf("Error generating RSS feed: %v", err)
}
return nil
}
func ListThemes(themesDir string) []string {
if themesDir == "" {
themesDir = DefaultThemesDir
}
themeList, err := themes.List(themesDir)
if err != nil {
log.Fatal("Error:", err)
}
result := make([]string, len(themeList))
for i, t := range themeList {
result[i] = t.Name
}
return result
}
func ShowHelpMessage() {
fmt.Println(`
Kite — A lightweight static site generator
USAGE:
kite <command> [options]
COMMANDS:
build Build the static site into the output directory
serve Start a local development server with live reload
list-themes List all available themes
OPTIONS:
-h, --help Show this help message
EXAMPLES:
kite build
kite serve
kite serve --port 8080
kite list-themes
DESCRIPTION:
Kite converts your content into a static website using themes and templates.
Use 'build' for production output and 'serve' for local development.
`)
}
|