mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
feat: Demoted author to a param.
This commit is contained in:
@@ -5,7 +5,7 @@ Thor is a static site generator written in [Odin](https://odin-lang.org), replac
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
thor.json ← site config (title, base_url, author, params, modules)
|
thor.json ← site config (title, base_url, params, modules)
|
||||||
content/ ← markdown and HTML content files
|
content/ ← markdown and HTML content files
|
||||||
layouts/ ← Mustache templates + partials (user overrides)
|
layouts/ ← Mustache templates + partials (user overrides)
|
||||||
assets/ ← CSS (Tufte-based), JS, fonts, images
|
assets/ ← CSS (Tufte-based), JS, fonts, images
|
||||||
@@ -129,7 +129,6 @@ Config precedence: `CLI flags > thor.json values > hardcoded defaults`.
|
|||||||
{
|
{
|
||||||
"title": "...",
|
"title": "...",
|
||||||
"base_url": "...",
|
"base_url": "...",
|
||||||
"author": "...",
|
|
||||||
"modules": ["../path/to/module"],
|
"modules": ["../path/to/module"],
|
||||||
"markdown_extensions": {
|
"markdown_extensions": {
|
||||||
"emoji": true,
|
"emoji": true,
|
||||||
@@ -139,6 +138,7 @@ Config precedence: `CLI flags > thor.json values > hardcoded defaults`.
|
|||||||
"sections": true
|
"sections": true
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
|
"author": "...",
|
||||||
"social": [
|
"social": [
|
||||||
{ "name": "github", "url": "...", "icon": "icons/github" }
|
{ "name": "github", "url": "...", "icon": "icons/github" }
|
||||||
]
|
]
|
||||||
@@ -201,7 +201,6 @@ Data is passed as **typed structs** (not `map[string]any`). Mustache resolves st
|
|||||||
```odin
|
```odin
|
||||||
Base_Data :: struct {
|
Base_Data :: struct {
|
||||||
now: datetime.DateTime,
|
now: datetime.DateTime,
|
||||||
author: string,
|
|
||||||
params: json.Value,
|
params: json.Value,
|
||||||
body: string,
|
body: string,
|
||||||
title: string,
|
title: string,
|
||||||
|
|||||||
@@ -45,7 +45,6 @@
|
|||||||
- [x] Block-override source-template tracking: warnings inside overrides point at the override's source file, not the parent template
|
- [x] Block-override source-template tracking: warnings inside overrides point at the override's source file, not the parent template
|
||||||
- [ ] Partial invocation stack in diagnostics: when an error fires inside a partial, show "invoked from" chain through `{{> name}}` calls. Currently warnings inside partials point at the partial (correct file) but don't show the invocation site.
|
- [ ] Partial invocation stack in diagnostics: when an error fires inside a partial, show "invoked from" chain through `{{> name}}` calls. Currently warnings inside partials point at the partial (correct file) but don't show the invocation site.
|
||||||
- [ ] Could be better error message when missing a closing (or opening) brace
|
- [ ] Could be better error message when missing a closing (or opening) brace
|
||||||
- [ ] Author should be a struct adhering to https://schema.org/author
|
|
||||||
- [ ] Block attributes on code fences (`{ #ex-1 }`) — hello-world.md
|
- [ ] Block attributes on code fences (`{ #ex-1 }`) — hello-world.md
|
||||||
- [ ] include-code shortcode (`{{< include-code ... >}}`) — i-ported-fd-to-odin
|
- [ ] include-code shortcode (`{{< include-code ... >}}`) — i-ported-fd-to-odin
|
||||||
- [ ] follow symlinks in `scan_content`?
|
- [ ] follow symlinks in `scan_content`?
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<footer>
|
<footer>
|
||||||
<p>© {{now.year}} {{author}}</p>
|
<p>© {{now.year}} {{params.author.name}}</p>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -21,7 +21,6 @@ Page_Context :: struct {
|
|||||||
|
|
||||||
Base_Data :: struct {
|
Base_Data :: struct {
|
||||||
now: datetime.DateTime,
|
now: datetime.DateTime,
|
||||||
author: string,
|
|
||||||
params: json.Value,
|
params: json.Value,
|
||||||
body: string,
|
body: string,
|
||||||
title: string,
|
title: string,
|
||||||
@@ -149,7 +148,6 @@ render_site :: proc(site: ^Site) {
|
|||||||
// Build base data once
|
// Build base data once
|
||||||
base := Base_Data {
|
base := Base_Data {
|
||||||
now = now,
|
now = now,
|
||||||
author = site.author,
|
|
||||||
params = site.params,
|
params = site.params,
|
||||||
description = site.description,
|
description = site.description,
|
||||||
og = site.og,
|
og = site.og,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ Site :: struct {
|
|||||||
vfs: VFS,
|
vfs: VFS,
|
||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
author: string,
|
|
||||||
base_url: string,
|
base_url: string,
|
||||||
config_path: string,
|
config_path: string,
|
||||||
content_dir: string,
|
content_dir: string,
|
||||||
@@ -44,7 +43,6 @@ Config_File :: struct {
|
|||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
base_url: string,
|
base_url: string,
|
||||||
author: string,
|
|
||||||
content_dir: string,
|
content_dir: string,
|
||||||
assets_dir: string,
|
assets_dir: string,
|
||||||
output_dir: string,
|
output_dir: string,
|
||||||
@@ -136,7 +134,6 @@ load_config_file :: proc(
|
|||||||
site_apply_config :: proc(site: ^Site, config: Config_File, config_dir: string) {
|
site_apply_config :: proc(site: ^Site, config: Config_File, config_dir: string) {
|
||||||
if config.title != "" do site.title = config.title
|
if config.title != "" do site.title = config.title
|
||||||
if config.description != "" do site.description = config.description
|
if config.description != "" do site.description = config.description
|
||||||
if config.author != "" do site.author = config.author
|
|
||||||
if config.base_url != "" do site.base_url = config.base_url
|
if config.base_url != "" do site.base_url = config.base_url
|
||||||
|
|
||||||
site.content_dir =
|
site.content_dir =
|
||||||
|
|||||||
+13
-6
@@ -25,8 +25,8 @@ test_load_config_file :: proc(t: ^testing.T) {
|
|||||||
"title":"Test Site",
|
"title":"Test Site",
|
||||||
"description":"Test desc",
|
"description":"Test desc",
|
||||||
"base_url":"https://example.com",
|
"base_url":"https://example.com",
|
||||||
"author":"Tester",
|
|
||||||
"params":{
|
"params":{
|
||||||
|
"author":"Tester",
|
||||||
"social":[
|
"social":[
|
||||||
{"name":"github","url":"https://github.com/test"},
|
{"name":"github","url":"https://github.com/test"},
|
||||||
{"name":"rss","url":"/index.xml"}]
|
{"name":"rss","url":"/index.xml"}]
|
||||||
@@ -42,11 +42,15 @@ test_load_config_file :: proc(t: ^testing.T) {
|
|||||||
testing.expect_value(t, cfg.title, "Test Site")
|
testing.expect_value(t, cfg.title, "Test Site")
|
||||||
testing.expect_value(t, cfg.description, "Test desc")
|
testing.expect_value(t, cfg.description, "Test desc")
|
||||||
testing.expect_value(t, cfg.base_url, "https://example.com")
|
testing.expect_value(t, cfg.base_url, "https://example.com")
|
||||||
testing.expect_value(t, cfg.author, "Tester")
|
|
||||||
|
|
||||||
params, has_params := cfg.params.(json.Object)
|
params, has_params := cfg.params.(json.Object)
|
||||||
testing.expect(t, has_params)
|
testing.expect(t, has_params)
|
||||||
|
|
||||||
|
author_val := params["author"]
|
||||||
|
author, has_author := author_val.(json.String)
|
||||||
|
testing.expect(t, has_author)
|
||||||
|
testing.expect_value(t, author, "Tester")
|
||||||
|
|
||||||
social_val := params["social"]
|
social_val := params["social"]
|
||||||
social, has_social := social_val.(json.Array)
|
social, has_social := social_val.(json.Array)
|
||||||
testing.expect(t, has_social)
|
testing.expect(t, has_social)
|
||||||
@@ -94,7 +98,6 @@ test_load_config_file_partial :: proc(t: ^testing.T) {
|
|||||||
testing.expect(t, ok)
|
testing.expect(t, ok)
|
||||||
testing.expect_value(t, cfg.title, "Partial")
|
testing.expect_value(t, cfg.title, "Partial")
|
||||||
testing.expect_value(t, cfg.description, "")
|
testing.expect_value(t, cfg.description, "")
|
||||||
testing.expect_value(t, cfg.author, "")
|
|
||||||
testing.expect(t, cfg.params == nil)
|
testing.expect(t, cfg.params == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +146,7 @@ test_init_site_flag_overrides_default :: proc(t: ^testing.T) {
|
|||||||
test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
||||||
path := write_temp_config(
|
path := write_temp_config(
|
||||||
"pipeline",
|
"pipeline",
|
||||||
`{"title":"Pipeline Test","description":"Full","base_url":"https://config.com","author":"Author"}`,
|
`{"title":"Pipeline Test","description":"Full","base_url":"https://config.com"}`,
|
||||||
)
|
)
|
||||||
defer os.remove(path)
|
defer os.remove(path)
|
||||||
|
|
||||||
@@ -154,7 +157,6 @@ test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
testing.expect_value(t, site.title, "Pipeline Test")
|
testing.expect_value(t, site.title, "Pipeline Test")
|
||||||
testing.expect_value(t, site.description, "Full")
|
testing.expect_value(t, site.description, "Full")
|
||||||
testing.expect_value(t, site.author, "Author")
|
|
||||||
testing.expect(t, .Drafts in site.features)
|
testing.expect(t, .Drafts in site.features)
|
||||||
testing.expect_value(t, site.base_url, "https://config.com")
|
testing.expect_value(t, site.base_url, "https://config.com")
|
||||||
}
|
}
|
||||||
@@ -162,7 +164,12 @@ test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
|||||||
@(test)
|
@(test)
|
||||||
test_init_site_md_enable_disable :: proc(t: ^testing.T) {
|
test_init_site_md_enable_disable :: proc(t: ^testing.T) {
|
||||||
site: Site
|
site: Site
|
||||||
args := []string{"thor", "-config:./nonexistent.json", "-ext:highlight,sections", "-no-ext:emoji"}
|
args := []string {
|
||||||
|
"thor",
|
||||||
|
"-config:./nonexistent.json",
|
||||||
|
"-ext:highlight,sections",
|
||||||
|
"-no-ext:emoji",
|
||||||
|
}
|
||||||
init_site(&site, args)
|
init_site(&site, args)
|
||||||
defer destroy_site(&site)
|
defer destroy_site(&site)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user