Skip to content

Commit d4c6028

Browse files
committed
commands/new: Improve theme creation
- Reorganize layouts directory to match the new template system. - Add --format flag to control format of the site configuration and default archetype. - Remove theme.toml. This file's presence can be confusing for new users, and the README in the themes repository already has an example. Closes #13489 Closes #13544
1 parent c15ebce commit d4c6028

File tree

20 files changed

+124
-107
lines changed

20 files changed

+124
-107
lines changed

commands/new.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,22 @@ according to your needs.`,
144144
createpath := paths.AbsPathify(conf.configs.Base.WorkingDir, filepath.Join(conf.configs.Base.ThemesDir, args[0]))
145145
r.Println("Creating new theme in", createpath)
146146

147-
err = skeletons.CreateTheme(createpath, sourceFs)
147+
err = skeletons.CreateTheme(createpath, sourceFs, format)
148148
if err != nil {
149149
return err
150150
}
151151

152152
return nil
153153
},
154154
withc: func(cmd *cobra.Command, r *rootCommand) {
155-
cmd.ValidArgsFunction = cobra.NoFileCompletions
155+
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
156+
if len(args) != 0 {
157+
return []string{}, cobra.ShellCompDirectiveNoFileComp
158+
}
159+
return []string{}, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveFilterDirs
160+
}
161+
cmd.Flags().StringVar(&format, "format", "toml", "preferred file format (toml, yaml or json)")
162+
_ = cmd.RegisterFlagCompletionFunc("format", cobra.FixedCompletions([]string{"toml", "yaml", "json"}, cobra.ShellCompDirectiveNoFileComp))
156163
},
157164
},
158165
},

create/skeletons/skeletons.go

+67-17
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,60 @@ var siteFs embed.FS
3434
var themeFs embed.FS
3535

3636
// CreateTheme creates a theme skeleton.
37-
func CreateTheme(createpath string, sourceFs afero.Fs) error {
37+
func CreateTheme(createpath string, sourceFs afero.Fs, format string) error {
3838
if exists, _ := helpers.Exists(createpath, sourceFs); exists {
3939
return errors.New(createpath + " already exists")
4040
}
41+
42+
format = strings.ToLower(format)
43+
44+
siteConfig := map[string]any{
45+
"baseURL": "https://example.org/",
46+
"languageCode": "en-US",
47+
"title": "My New Hugo Site",
48+
"menus": map[string]any{
49+
"main": []any{
50+
map[string]any{
51+
"name": "Home",
52+
"pageRef": "/",
53+
"weight": 10,
54+
},
55+
map[string]any{
56+
"name": "Posts",
57+
"pageRef": "/posts",
58+
"weight": 20,
59+
},
60+
map[string]any{
61+
"name": "Tags",
62+
"pageRef": "/tags",
63+
"weight": 30,
64+
},
65+
},
66+
},
67+
"module": map[string]any{
68+
"hugoVersion": map[string]any{
69+
"extended": false,
70+
"min": "0.116.0",
71+
},
72+
},
73+
}
74+
75+
err := createSiteConfig(sourceFs, createpath, siteConfig, format)
76+
if err != nil {
77+
return err
78+
}
79+
80+
defaultArchetype := map[string]any{
81+
"title": "{{ replace .File.ContentBaseName \"-\" \" \" | title }}",
82+
"date": "{{ .Date }}",
83+
"draft": true,
84+
}
85+
86+
err = createDefaultArchetype(sourceFs, createpath, defaultArchetype, format)
87+
if err != nil {
88+
return err
89+
}
90+
4191
return copyFiles(createpath, sourceFs, themeFs)
4292
}
4393

@@ -71,12 +121,24 @@ func CreateSite(createpath string, sourceFs afero.Fs, force bool, format string)
71121
}
72122
}
73123

74-
err := newSiteCreateConfig(sourceFs, createpath, format)
124+
siteConfig := map[string]any{
125+
"baseURL": "https://example.org/",
126+
"title": "My New Hugo Site",
127+
"languageCode": "en-us",
128+
}
129+
130+
err := createSiteConfig(sourceFs, createpath, siteConfig, format)
75131
if err != nil {
76132
return err
77133
}
78134

79-
err = newSiteCreateArchetype(sourceFs, createpath, format)
135+
defaultArchetype := map[string]any{
136+
"title": "{{ replace .File.ContentBaseName \"-\" \" \" | title }}",
137+
"date": "{{ .Date }}",
138+
"draft": true,
139+
}
140+
141+
err = createDefaultArchetype(sourceFs, createpath, defaultArchetype, format)
80142
if err != nil {
81143
return err
82144
}
@@ -99,13 +161,7 @@ func copyFiles(createpath string, sourceFs afero.Fs, skeleton embed.FS) error {
99161
})
100162
}
101163

102-
func newSiteCreateConfig(fs afero.Fs, createpath string, format string) (err error) {
103-
in := map[string]string{
104-
"baseURL": "https://example.org/",
105-
"title": "My New Hugo Site",
106-
"languageCode": "en-us",
107-
}
108-
164+
func createSiteConfig(fs afero.Fs, createpath string, in map[string]any, format string) (err error) {
109165
var buf bytes.Buffer
110166
err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(format), &buf)
111167
if err != nil {
@@ -115,13 +171,7 @@ func newSiteCreateConfig(fs afero.Fs, createpath string, format string) (err err
115171
return helpers.WriteToDisk(filepath.Join(createpath, "hugo."+format), &buf, fs)
116172
}
117173

118-
func newSiteCreateArchetype(fs afero.Fs, createpath string, format string) (err error) {
119-
in := map[string]any{
120-
"title": "{{ replace .File.ContentBaseName \"-\" \" \" | title }}",
121-
"date": "{{ .Date }}",
122-
"draft": true,
123-
}
124-
174+
func createDefaultArchetype(fs afero.Fs, createpath string, in map[string]any, format string) (err error) {
125175
var buf bytes.Buffer
126176
err = parser.InterfaceToFrontMatter(in, metadecoders.FormatFromString(format), &buf)
127177
if err != nil {

create/skeletons/theme/archetypes/default.md

-5
This file was deleted.

create/skeletons/theme/hugo.toml

-23
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{{- with resources.Get "css/main.css" }}
2-
{{- if eq hugo.Environment "development" }}
3-
<link rel="stylesheet" href="{{ .RelPermalink }}">
4-
{{- else }}
2+
{{- if hugo.IsProduction }}
53
{{- with . | minify | fingerprint }}
64
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
75
{{- end }}
6+
{{- else }}
7+
<link rel="stylesheet" href="{{ .RelPermalink }}">
88
{{- end }}
99
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{ with resources.Get "js/main.js" }}
2+
{{ $opts := dict
3+
"minify" hugo.IsProduction
4+
"sourceMap" (cond hugo.IsProduction "" "external")
5+
"targetPath" "js/main.js"
6+
}}
7+
{{ with . | js.Build $opts }}
8+
{{ if hugo.IsProduction }}
9+
{{ with . | fingerprint }}
10+
<script src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script>
11+
{{ end }}
12+
{{ else }}
13+
<script src="{{ .RelPermalink }}"></script>
14+
{{ end }}
15+
{{ end }}
16+
{{ end }}

create/skeletons/theme/layouts/partials/head/js.html

-12
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{{ define "main" }}
2+
<h1>{{ .Title }}</h1>
3+
{{ .Content }}
4+
{{ range .Pages }}
5+
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
6+
{{ end }}
7+
{{ end }}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{{ define "main" }}
2+
<h1>{{ .Title }}</h1>
3+
{{ .Content }}
4+
{{ range .Pages }}
5+
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
6+
{{ end }}
7+
{{ end }}

create/skeletons/theme/theme.toml

-31
This file was deleted.

testscripts/commands/new.txt

+15-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ exists themes
2020

2121
hugo new theme -h
2222
stdout 'Create a new theme \(skeleton\) called \[name\] in ./themes'
23-
hugo new theme mytheme
23+
hugo new theme mytheme --format yml
2424
stdout 'Creating new theme'
2525
! exists resources
2626
cd themes
@@ -34,22 +34,23 @@ checkfile content/posts/post-1.md
3434
checkfile content/posts/post-2.md
3535
checkfile content/posts/post-3/bryce-canyon.jpg
3636
checkfile content/posts/post-3/index.md
37-
checkfile layouts/_default/baseof.html
38-
checkfile layouts/_default/home.html
39-
checkfile layouts/_default/list.html
40-
checkfile layouts/_default/single.html
41-
checkfile layouts/partials/footer.html
42-
checkfile layouts/partials/head.html
43-
checkfile layouts/partials/head/css.html
44-
checkfile layouts/partials/head/js.html
45-
checkfile layouts/partials/header.html
46-
checkfile layouts/partials/menu.html
47-
checkfile layouts/partials/terms.html
37+
checkfile layouts/baseof.html
38+
checkfile layouts/home.html
39+
checkfile layouts/list.html
40+
checkfile layouts/single.html
41+
checkfile layouts/taxonomy.html
42+
checkfile layouts/term.html
43+
checkfile layouts/_partials/footer.html
44+
checkfile layouts/_partials/head.html
45+
checkfile layouts/_partials/head/css.html
46+
checkfile layouts/_partials/head/js.html
47+
checkfile layouts/_partials/header.html
48+
checkfile layouts/_partials/menu.html
49+
checkfile layouts/_partials/terms.html
4850
checkfile static/favicon.ico
4951
checkfile LICENSE
5052
checkfile README.md
51-
checkfile hugo.toml
52-
checkfile theme.toml
53+
checkfile hugo.yml
5354
exists data
5455
exists i18n
5556

0 commit comments

Comments
 (0)