pandorga 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/DESIGN.md +9 -9
- data/_data/themes/dark.yml +2 -1
- data/_includes/content-runtime/30-includes.html +1 -1
- data/_includes/content-runtime/43-blocks.html +1 -1
- data/_includes/content-runtime/50-detail.html +5 -5
- data/_includes/content-runtime/60-fragments.html +3 -3
- data/_includes/page/network-graph.html +2 -2
- data/_includes/page/page-header.html +3 -1
- data/_includes/page/site-footer.html +2 -2
- data/_includes/theme/json-ld.html +35 -2
- data/_layouts/articles.html +1 -1
- data/_layouts/projects.html +2 -2
- data/_layouts/resources.html +1 -1
- data/_layouts/shell.html +4 -4
- data/_layouts/text.html +4 -4
- data/_plugins/lib/writing_entry.rb +1 -1
- data/_plugins/local_detail_rewrites.rb +10 -1
- data/assets/css/article.css +3 -3
- data/assets/css/base.css +0 -79
- data/assets/css/global-link.css +0 -1
- data/assets/css/ledger/chrome.css +1 -1
- data/assets/css/ledger/cv.css +1 -1
- data/assets/css/ledger/detail.css +1 -1
- data/assets/css/ledger/footer.css +1 -1
- data/assets/css/ledger/home.css +13 -42
- data/assets/css/ledger/projects.css +2 -2
- data/assets/css/ledger/sources.css +3 -3
- data/assets/css/ledger/writing.css +1 -1
- data/lib/pandorga/detail_routes.rb +29 -0
- data/lib/pandorga/jekyll/plugins/detail_documents.rb +154 -0
- data/lib/pandorga/jekyll/plugins/lib/writing_entry.rb +1 -1
- data/lib/pandorga/jekyll/plugins/local_detail_rewrites.rb +10 -1
- data/lib/pandorga/version.rb +1 -1
- data/scripts/content/export-content-json.rb +1 -1
- data/scripts/test/render-parity/load-runtime.mjs +1 -1
- data/scripts/test/test-css-structure.rb +20 -0
- data/scripts/test/test-discovery.rb +36 -0
- data/scripts/test/test-examples-build.rb +90 -0
- data/scripts/test/test-fonts.rb +14 -0
- data/scripts/test/test-hero-portraits.mjs +12 -2
- data/scripts/test/test-hero-portraits.rb +12 -4
- data/scripts/test/test-lighthouse-policy.rb +4 -0
- data/scripts/test/test-listing-filter-contract.rb +1 -1
- data/scripts/test/test-shell-a11y.rb +27 -0
- data/scripts/test/test-theme-contrast.rb +43 -0
- data/scripts/validate.sh +6 -0
- metadata +4 -1
|
@@ -33,8 +33,23 @@ end
|
|
|
33
33
|
FileUtils.rm_rf(example.join("_site"))
|
|
34
34
|
FileUtils.rm_rf(example.join("_content_json"))
|
|
35
35
|
|
|
36
|
+
redirects_path = example.join("_redirects")
|
|
37
|
+
original_redirects = redirects_path.file? ? redirects_path.read : nil
|
|
38
|
+
|
|
39
|
+
begin
|
|
36
40
|
run!("bundle", "install", "--quiet", chdir: example) if example.join("Gemfile").file?
|
|
37
41
|
run!("ruby", EXE.to_s, "export", "content", "_content_json", chdir: example)
|
|
42
|
+
if name == "full" && redirects_path.file?
|
|
43
|
+
splat = <<~TXT
|
|
44
|
+
|
|
45
|
+
/articles/:slug /pages/articles/ 200
|
|
46
|
+
/posts/:slug /pages/blog/ 200
|
|
47
|
+
/blog/:slug /pages/blog/ 200
|
|
48
|
+
/projects/:slug /pages/projects/ 200
|
|
49
|
+
/products/:slug /pages/cv/ 200
|
|
50
|
+
TXT
|
|
51
|
+
redirects_path.write("#{redirects_path.read.rstrip}\n#{splat}")
|
|
52
|
+
end
|
|
38
53
|
run!("bundle", "exec", "jekyll", "build", "--quiet", chdir: example)
|
|
39
54
|
|
|
40
55
|
index = example.join("_site/index.html")
|
|
@@ -65,6 +80,18 @@ end
|
|
|
65
80
|
warn "FAIL test-examples-build: full home still hydrates the summary"
|
|
66
81
|
exit 1
|
|
67
82
|
end
|
|
83
|
+
{
|
|
84
|
+
"pages/articles/index.html" => "Articles",
|
|
85
|
+
"pages/blog/index.html" => "Rascunhos",
|
|
86
|
+
"pages/projects/index.html" => "Projects"
|
|
87
|
+
}.each do |rel, title|
|
|
88
|
+
listing = example.join("_site", rel).read
|
|
89
|
+
heading = listing[/<h1 class="page-header-title.*?<\/h1>/m].to_s
|
|
90
|
+
unless heading.include?(title) && heading.include?("data-content-static") && !heading.include?("Loading...")
|
|
91
|
+
warn "FAIL test-examples-build: #{rel} static h1 is #{heading.inspect}"
|
|
92
|
+
exit 1
|
|
93
|
+
end
|
|
94
|
+
end
|
|
68
95
|
else
|
|
69
96
|
unless html.include?('id="home-cv-summary" class="home-hero-summary font-body" data-content-fragment="cv/summary" data-content-quiet')
|
|
70
97
|
warn "FAIL test-examples-build: minimal home dropped the summary fallback"
|
|
@@ -86,6 +113,66 @@ end
|
|
|
86
113
|
warn "FAIL test-examples-build: #{name} robots missing the sitemap line\n#{robots}"
|
|
87
114
|
exit 1
|
|
88
115
|
end
|
|
116
|
+
if name == "full"
|
|
117
|
+
{
|
|
118
|
+
"/articles/2026-01-01-welcome/" => "Article",
|
|
119
|
+
"/posts/2026-01-02-note/" => "BlogPosting"
|
|
120
|
+
}.each do |path, schema|
|
|
121
|
+
loc = "#{origin}#{path}"
|
|
122
|
+
unless sitemap.include?("<loc>#{loc}</loc>")
|
|
123
|
+
warn "FAIL test-examples-build: sitemap missing #{loc}\n#{sitemap}"
|
|
124
|
+
exit 1
|
|
125
|
+
end
|
|
126
|
+
page = example.join("_site#{path}index.html")
|
|
127
|
+
unless page.file?
|
|
128
|
+
warn "FAIL test-examples-build: missing static detail #{page}"
|
|
129
|
+
exit 1
|
|
130
|
+
end
|
|
131
|
+
body = page.read
|
|
132
|
+
canonical = body[/rel="canonical" href="([^"]+)"/, 1].to_s
|
|
133
|
+
og_url = body[/property="og:url" content="([^"]+)"/, 1].to_s
|
|
134
|
+
unless canonical.include?(path) && !canonical.include?("/pages/")
|
|
135
|
+
warn "FAIL test-examples-build: canonical for #{path} is #{canonical}"
|
|
136
|
+
exit 1
|
|
137
|
+
end
|
|
138
|
+
unless og_url.include?(path) && !og_url.include?("/pages/")
|
|
139
|
+
warn "FAIL test-examples-build: og:url for #{path} is #{og_url}"
|
|
140
|
+
exit 1
|
|
141
|
+
end
|
|
142
|
+
unless body.include?(%("@type": "#{schema}"))
|
|
143
|
+
warn "FAIL test-examples-build: #{path} missing #{schema} JSON-LD"
|
|
144
|
+
exit 1
|
|
145
|
+
end
|
|
146
|
+
listing_attr = path.include?("/posts/") ? "/pages/blog/" : "/pages/articles/"
|
|
147
|
+
unless body.include?(%(data-listing-path="#{listing_attr}"))
|
|
148
|
+
warn "FAIL test-examples-build: #{path} lost the listing path"
|
|
149
|
+
exit 1
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
["/projects/demo-kit/", "/products/ledger-tool/"].each do |path|
|
|
153
|
+
loc = "#{origin}#{path}"
|
|
154
|
+
unless sitemap.include?("<loc>#{loc}</loc>")
|
|
155
|
+
warn "FAIL test-examples-build: sitemap missing #{loc}\n#{sitemap}"
|
|
156
|
+
exit 1
|
|
157
|
+
end
|
|
158
|
+
page = example.join("_site#{path}index.html")
|
|
159
|
+
body = page.file? ? page.read : ""
|
|
160
|
+
canonical = body[/rel="canonical" href="([^"]+)"/, 1].to_s
|
|
161
|
+
unless canonical.include?(path)
|
|
162
|
+
warn "FAIL test-examples-build: canonical for #{path} is #{canonical}"
|
|
163
|
+
exit 1
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
built_redirects = example.join("_site/_redirects").read
|
|
167
|
+
if built_redirects.match?(%r{/(?:articles|posts|blog|projects|products)/:slug})
|
|
168
|
+
warn "FAIL test-examples-build: built _redirects still rewrites detail URLs\n#{built_redirects}"
|
|
169
|
+
exit 1
|
|
170
|
+
end
|
|
171
|
+
unless redirects_path.read.match?(%r{/articles/:slug\s+/pages/articles/\s+200})
|
|
172
|
+
warn "FAIL test-examples-build: the build edited the source _redirects"
|
|
173
|
+
exit 1
|
|
174
|
+
end
|
|
175
|
+
end
|
|
89
176
|
unless html.include?('application/ld+json') && html.include?('"@type": "Person"')
|
|
90
177
|
warn "FAIL test-examples-build: #{name} home is missing JSON-LD"
|
|
91
178
|
exit 1
|
|
@@ -99,6 +186,9 @@ end
|
|
|
99
186
|
warn "FAIL test-examples-build: #{name} home dropped the title face"
|
|
100
187
|
exit 1
|
|
101
188
|
end
|
|
189
|
+
ensure
|
|
190
|
+
redirects_path.write(original_redirects) if original_redirects
|
|
191
|
+
end
|
|
102
192
|
end
|
|
103
193
|
|
|
104
194
|
puts "PASS test-examples-build"
|
data/scripts/test/test-fonts.rb
CHANGED
|
@@ -47,6 +47,20 @@ fail!("body weights were not sorted") unless custom_href.include?("family=Source
|
|
|
47
47
|
fail!("mono italic axis is wrong") unless custom_href.include?("family=IBM+Plex+Mono:ital,wght@0,400;0,500;1,400;1,500")
|
|
48
48
|
fail!("unset label left Marcellus") unless custom_href.include?("family=Marcellus+SC:wght@400;700")
|
|
49
49
|
fail!("body change left the tagline on Newsreader") unless Pandorga::Fonts.css_stack(custom, "subtitle").start_with?("'Source Serif 4'")
|
|
50
|
+
|
|
51
|
+
# A font rename once replaced the letters "hind" inside the word "behind".
|
|
52
|
+
token = "be" + "Newsreader"
|
|
53
|
+
broken = []
|
|
54
|
+
Dir.glob(ROOT.join("**/*.{css,html,rb,js,mjs,md,liquid,yml}")).each do |path|
|
|
55
|
+
next if path.include?("/studio/assets/")
|
|
56
|
+
next if path.include?("/node_modules/")
|
|
57
|
+
next if path.end_with?("test-fonts.rb")
|
|
58
|
+
text = File.read(path)
|
|
59
|
+
next unless text.include?(token)
|
|
60
|
+
|
|
61
|
+
broken << Pathname.new(path).relative_path_from(ROOT).to_s
|
|
62
|
+
end
|
|
63
|
+
fail!("corrupted 'behind' left by a font rename (#{broken.size} files): #{broken.join(', ')}") unless broken.empty?
|
|
50
64
|
fail!("code face did not follow mono") unless Pandorga::Fonts.css_stack(custom, "code").start_with?("'IBM Plex Mono'")
|
|
51
65
|
|
|
52
66
|
kept = Pandorga::Fonts.resolve({ "title" => "Cinzel Decorative" }, theme)
|
|
@@ -13,14 +13,24 @@ const source = fs.readFileSync(
|
|
|
13
13
|
);
|
|
14
14
|
|
|
15
15
|
const start = source.indexOf('function heroPortraitEntries');
|
|
16
|
-
|
|
16
|
+
// applyHeroPortraitSources is defined before pickHeroPortrait. Ending at
|
|
17
|
+
// applyHeroPortrait( still works today, and it is one character away from
|
|
18
|
+
// stopping on the Sources function. showHeroPortrait is the next function
|
|
19
|
+
// after the picker, so the slice always includes pickHeroPortrait.
|
|
20
|
+
const end = source.indexOf('function showHeroPortrait');
|
|
17
21
|
if (start < 0 || end < start) {
|
|
18
22
|
console.error('hero portrait functions missing from 60-fragments.html');
|
|
19
23
|
process.exit(1);
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
const slice = source.slice(start, end);
|
|
27
|
+
if (!slice.includes('function pickHeroPortrait')) {
|
|
28
|
+
console.error('hero portrait crop stopped before pickHeroPortrait');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
const api = new Function(
|
|
23
|
-
`${
|
|
33
|
+
`${slice}\nreturn { heroPortraitEntries, pickHeroPortrait };`
|
|
24
34
|
)();
|
|
25
35
|
|
|
26
36
|
const { heroPortraitEntries, pickHeroPortrait } = api;
|
|
@@ -37,13 +37,19 @@ puts "Testing home hero portraits..."
|
|
|
37
37
|
|
|
38
38
|
# ── AC-HERO-01 ──────────────────────────────────────────────────────────────
|
|
39
39
|
|
|
40
|
-
check!(POOL.directory?, "missing #{POOL}")
|
|
41
40
|
check!(!ROOT.join("content/pages/home/portraits.yml").exist?,
|
|
42
41
|
"the author does not keep a portrait list")
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
# The four photographs live with the site, not in the gem. When they are
|
|
44
|
+
# here, the folder must be exactly that set. When they are not, the picker
|
|
45
|
+
# extracted from the runtime still has to run.
|
|
46
|
+
personal_pool = %w[DSC00571.JPG DSC00632.JPG DSC00721.JPG DSC00727.JPG]
|
|
47
|
+
pool_names = POOL.directory? ? POOL.children.select(&:file?).map { |path| path.basename.to_s }.sort : []
|
|
48
|
+
if pool_names.empty?
|
|
49
|
+
puts "AC-HERO-01: no hero photographs in this checkout"
|
|
50
|
+
elsif pool_names != personal_pool
|
|
51
|
+
check!(false, "the hero folder must hold the four uploaded photographs, got #{pool_names.inspect}")
|
|
52
|
+
end
|
|
47
53
|
|
|
48
54
|
Dir.mktmpdir("hero-pool") do |dir|
|
|
49
55
|
root = Pathname.new(dir)
|
|
@@ -135,6 +141,7 @@ check!(status.success?, "picker cases failed")
|
|
|
135
141
|
|
|
136
142
|
# ── AC-HERO-02 ──────────────────────────────────────────────────────────────
|
|
137
143
|
|
|
144
|
+
if pool_names == personal_pool
|
|
138
145
|
Dir.mktmpdir("hero-portraits") do |dir|
|
|
139
146
|
out = Pathname.new(dir).join("export")
|
|
140
147
|
env = { "CONTENT_API_BASE_URL" => "", "CONTENT_EXPORT_SKIP_VALIDATE" => "1" }
|
|
@@ -158,5 +165,6 @@ Dir.mktmpdir("hero-portraits") do |dir|
|
|
|
158
165
|
check!(listed.include?("pages/home/portraits.json"),
|
|
159
166
|
"manifest page_headers must include the portrait list, got #{listed.inspect}")
|
|
160
167
|
end
|
|
168
|
+
end
|
|
161
169
|
|
|
162
170
|
puts "All home hero portrait checks passed."
|
|
@@ -101,6 +101,10 @@ fail!("band note is still painted by script") unless band.include?("page_headers
|
|
|
101
101
|
fail!("project inventory has a name and no role") unless band.include?('role="region"') && band.include?('aria-label="Project inventory"')
|
|
102
102
|
headers = File.read(File.expand_path("../../_plugins/content_headers.rb", __dir__))
|
|
103
103
|
fail!("page headers are not loaded at build time") unless headers.include?('site.data["page_headers"]')
|
|
104
|
+
page_header = File.read(File.expand_path("../../_includes/page/page-header.html", __dir__))
|
|
105
|
+
fail!("listing h1 is still Loading...") if page_header.include?("Loading...")
|
|
106
|
+
fail!("listing h1 does not read page headers") unless page_header.include?("page_headers")
|
|
107
|
+
fail!("listing h1 is not marked static") unless page_header.include?("data-content-static")
|
|
104
108
|
home = File.read(File.expand_path("../../_layouts/home.html", __dir__))
|
|
105
109
|
fail!("hero subtitle is still painted by script") unless home.include?("page_headers.home") && home.include?("data-content-static")
|
|
106
110
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# on click; `filterItems` reads a fixed set of names. Nothing connects the
|
|
8
8
|
# two, so renaming a facet in a layout — `category` to `tag`, say — leaves the
|
|
9
9
|
# chips rendering, highlighting and pushing a query string while the list
|
|
10
|
-
#
|
|
10
|
+
# behind them never changes. That shipped on the Sources page: every click set
|
|
11
11
|
# a key nothing read.
|
|
12
12
|
#
|
|
13
13
|
# There is no build error and no console error to notice, so the contract is
|
|
@@ -27,4 +27,31 @@ fail!("footer home link still uses site.author alone") if FOOTER.include?(bare)
|
|
|
27
27
|
fail!("shell home link needs an identity.name fallback") unless SHELL.include?("site.pandorga.identity.name")
|
|
28
28
|
fail!("footer home link needs an identity.name fallback") unless FOOTER.include?("site.pandorga.identity.name")
|
|
29
29
|
|
|
30
|
+
fail!("top bar is still a nav") if SHELL.include?('<nav class="sticky')
|
|
31
|
+
fail!("top bar is not a header") unless SHELL.include?('<header class="sticky top-0 z-50 bg-surface">')
|
|
32
|
+
fail!("section links lost their name") unless SHELL.include?('aria-label="Sections"')
|
|
33
|
+
navs = SHELL.scan(/<nav\b/).size
|
|
34
|
+
fail!("shell should have one nav landmark, found #{navs}") unless navs == 1
|
|
35
|
+
|
|
36
|
+
# Decorative Material Symbols sit beside a text label. Without aria-hidden
|
|
37
|
+
# the ligature ("arrow_left_alt", "shuffle", an icon name) is read aloud.
|
|
38
|
+
ICON_FILES = [
|
|
39
|
+
ROOT.join("_layouts/text.html"),
|
|
40
|
+
ROOT.join("_includes/content-runtime/50-detail.html"),
|
|
41
|
+
ROOT.join("_includes/content-runtime/60-fragments.html"),
|
|
42
|
+
ROOT.join("_includes/content-runtime/30-includes.html")
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
ICON_FILES.each do |path|
|
|
46
|
+
path.read.each_line.with_index(1) do |line, number|
|
|
47
|
+
next unless line.include?("material-symbols-outlined")
|
|
48
|
+
next if line.include?("querySelector")
|
|
49
|
+
next if line.include?("aria-hidden")
|
|
50
|
+
# Class token handed to a later span that already sets aria-hidden.
|
|
51
|
+
next if line.include?("cls:")
|
|
52
|
+
|
|
53
|
+
fail!("#{path.relative_path_from(ROOT)}:#{number}: decorative icon is exposed")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
30
57
|
puts "PASS test-shell-a11y"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Dark tertiary container text must clear WCAG AA for normal text.
|
|
5
|
+
# PLT-AC-33
|
|
6
|
+
|
|
7
|
+
require "pathname"
|
|
8
|
+
require "yaml"
|
|
9
|
+
|
|
10
|
+
ROOT = Pathname.new(__dir__).join("..", "..").expand_path
|
|
11
|
+
|
|
12
|
+
def fail!(message)
|
|
13
|
+
warn "FAIL test-theme-contrast: #{message}"
|
|
14
|
+
exit 1
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def channel(value)
|
|
18
|
+
value = value / 255.0
|
|
19
|
+
value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055)**2.4
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def luminance(hex)
|
|
23
|
+
rgb = hex.delete("#").scan(/../).map { |part| part.to_i(16) }
|
|
24
|
+
fail!("not a hex colour: #{hex}") unless rgb.length == 3
|
|
25
|
+
|
|
26
|
+
(0.2126 * channel(rgb[0])) + (0.7152 * channel(rgb[1])) + (0.0722 * channel(rgb[2]))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def contrast(foreground, background)
|
|
30
|
+
lighter, darker = [luminance(foreground), luminance(background)].sort.reverse
|
|
31
|
+
(lighter + 0.05) / (darker + 0.05)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
dark = YAML.safe_load(ROOT.join("_data/themes/dark.yml").read) || {}
|
|
35
|
+
colors = dark["colors"] || {}
|
|
36
|
+
background = colors["tertiary_container"].to_s
|
|
37
|
+
foreground = colors["on_tertiary_container"].to_s
|
|
38
|
+
fail!("dark tertiary container moved") unless background.casecmp("#6a684f").zero?
|
|
39
|
+
|
|
40
|
+
ratio = contrast(foreground, background)
|
|
41
|
+
fail!("#{foreground} on #{background} is #{ratio.round(2)}:1") unless ratio >= 4.5
|
|
42
|
+
|
|
43
|
+
puts "PASS test-theme-contrast (#{foreground} on #{background} = #{ratio.round(2)}:1)"
|
data/scripts/validate.sh
CHANGED
|
@@ -57,6 +57,7 @@ TESTS=(
|
|
|
57
57
|
scripts/test/test-examples-build.rb
|
|
58
58
|
scripts/test/test-validate-allowlist.rb
|
|
59
59
|
scripts/test/test-shell-a11y.rb
|
|
60
|
+
scripts/test/test-theme-contrast.rb
|
|
60
61
|
scripts/test/test-hydrate-reserve.rb
|
|
61
62
|
scripts/test/test-hero-summary.rb
|
|
62
63
|
scripts/test/test-lighthouse-policy.rb
|
|
@@ -82,6 +83,11 @@ for test in "${TESTS[@]}"; do
|
|
|
82
83
|
fi
|
|
83
84
|
done
|
|
84
85
|
|
|
86
|
+
echo "-- scripts/test/test-hero-portraits.mjs"
|
|
87
|
+
if ! node scripts/test/test-hero-portraits.mjs; then
|
|
88
|
+
failed=1
|
|
89
|
+
fi
|
|
90
|
+
|
|
85
91
|
echo "-- scripts/test/test-studio-pipeline-config.mjs"
|
|
86
92
|
if ! node scripts/test/test-studio-pipeline-config.mjs; then
|
|
87
93
|
failed=1
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pandorga
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The Pandorga contributors
|
|
@@ -287,6 +287,7 @@ files:
|
|
|
287
287
|
- lib/pandorga/commands/publish.rb
|
|
288
288
|
- lib/pandorga/commands/serve.rb
|
|
289
289
|
- lib/pandorga/commands/studio_schema.rb
|
|
290
|
+
- lib/pandorga/detail_routes.rb
|
|
290
291
|
- lib/pandorga/discovery.rb
|
|
291
292
|
- lib/pandorga/fonts.rb
|
|
292
293
|
- lib/pandorga/hero_summary.rb
|
|
@@ -303,6 +304,7 @@ files:
|
|
|
303
304
|
- lib/pandorga/jekyll/plugins/content_validators_hook.rb
|
|
304
305
|
- lib/pandorga/jekyll/plugins/content_writing_index.rb
|
|
305
306
|
- lib/pandorga/jekyll/plugins/content_writing_paths.rb
|
|
307
|
+
- lib/pandorga/jekyll/plugins/detail_documents.rb
|
|
306
308
|
- lib/pandorga/jekyll/plugins/discovery.rb
|
|
307
309
|
- lib/pandorga/jekyll/plugins/fonts.rb
|
|
308
310
|
- lib/pandorga/jekyll/plugins/force_utf8_encoding.rb
|
|
@@ -466,6 +468,7 @@ files:
|
|
|
466
468
|
- scripts/test/test-studio-slug-config.rb
|
|
467
469
|
- scripts/test/test-template-packages.rb
|
|
468
470
|
- scripts/test/test-text-excerpt.rb
|
|
471
|
+
- scripts/test/test-theme-contrast.rb
|
|
469
472
|
- scripts/test/test-unwrap-media-src.mjs
|
|
470
473
|
- scripts/test/test-unwrap-media-src.rb
|
|
471
474
|
- scripts/test/test-validate-allowlist.rb
|