pandorga 1.7.6 → 1.8.1
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 +29 -0
- data/_includes/content-runtime/20-markdown.html +35 -0
- data/assets/css/article.css +85 -0
- data/assets/css/ledger/detail.css +4 -3
- data/lib/pandorga/commands/new.rb +1 -1
- data/lib/pandorga/version.rb +1 -1
- data/scripts/test/render-parity/proof.json +5 -0
- data/scripts/test/render-parity/run-fixture.mjs +19 -0
- data/scripts/test/render-parity/theorem.json +5 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 03c8db4a237e9092a2f0d9256c118a162476cb1d056fc88518cfeccd60379bed
|
|
4
|
+
data.tar.gz: e8a2725fbc96d9c02ad55e39dce2c8e98d1eec14f20996ae5636d60f2d54181e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4e9108eac5982492245285b4954dc1e43a0ca10534411a8a221af35c5520a5a65c3a0fc9e8700bfc9c27588e41ee332a0204ebb697b9339514128e70b5237d1
|
|
7
|
+
data.tar.gz: 8ae715831b65d21cf206f071841f6c444f0b99598d93a2917ccaa09f4eecce658e2e93c0b61a75e375afa9b9a9baf0a6f17a47c70584f4ac6c5f656f8a728e75
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.1] — 2026-10-12
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Theorems are bare (no gray plate); only proofs carry the surface band
|
|
8
|
+
- Proof gray bleeds to the edges of `.text-page-main` while body text stays
|
|
9
|
+
on the reading measure
|
|
10
|
+
- Proofs prefix **Proof.** from the runtime, like theorem heads — authors
|
|
11
|
+
no longer write `*Proof.*` in the body
|
|
12
|
+
|
|
13
|
+
No `pandorga:` config keys were added or renamed. Font roles and the
|
|
14
|
+
ledger fallbacks are unchanged.
|
|
15
|
+
|
|
16
|
+
## [1.8.0] — 2026-10-12
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Theorem and proof Markdown wrappers in the content runtime, same
|
|
21
|
+
`markdown="1"` contract as `article-note` and `poem`:
|
|
22
|
+
- `<div class="theorem" name="Corollary 1" description="nadir camera" markdown="1">…</div>`
|
|
23
|
+
builds the head from `name` / `description` and italicizes the body
|
|
24
|
+
- `<div class="proof" markdown="1">…</div>` wraps a proof and places a
|
|
25
|
+
QED square on the last line
|
|
26
|
+
- Full-column styles for `.theorem` and `.proof` in `article.css`
|
|
27
|
+
- Render-parity fixtures `theorem.json` and `proof.json`
|
|
28
|
+
|
|
29
|
+
No `pandorga:` config keys were added or renamed. Font roles and the
|
|
30
|
+
ledger fallbacks are unchanged.
|
|
31
|
+
|
|
3
32
|
## [1.7.6] — 2026-10-12
|
|
4
33
|
|
|
5
34
|
### Fixed
|
|
@@ -109,6 +109,31 @@
|
|
|
109
109
|
return parts.join('');
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
function attrValue(openTag, name) {
|
|
113
|
+
var re = new RegExp('\\b' + name + '\\s*=\\s*(?:"([^"]*)"|\'([^\']*)\')', 'i');
|
|
114
|
+
var m = String(openTag || '').match(re);
|
|
115
|
+
return m ? String(m[1] != null ? m[1] : m[2] || '') : '';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function renderTheoremHtml(openTag, inner) {
|
|
119
|
+
var name = attrValue(openTag, 'name').trim();
|
|
120
|
+
var description = attrValue(openTag, 'description').trim();
|
|
121
|
+
var head = '';
|
|
122
|
+
if (name) {
|
|
123
|
+
head = '<p class="theorem-head"><span class="theorem-name">' + escapeHtml(name) + '</span>';
|
|
124
|
+
if (description) {
|
|
125
|
+
head += ' <span class="theorem-description">(' + escapeHtml(description) + ')</span>';
|
|
126
|
+
}
|
|
127
|
+
head += '.</p>';
|
|
128
|
+
}
|
|
129
|
+
return '<div class="theorem">' + head + '<div class="theorem-body">' + parseInlineMarkdown(inner) + '</div></div>';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renderProofHtml(inner) {
|
|
133
|
+
var head = '<p class="proof-head"><span class="proof-name">Proof</span>.</p>';
|
|
134
|
+
return '<div class="proof">' + head + '<div class="proof-body">' + parseInlineMarkdown(inner) + '</div></div>';
|
|
135
|
+
}
|
|
136
|
+
|
|
112
137
|
function preprocessMarkdownDivs(markdown) {
|
|
113
138
|
var text = String(markdown || '');
|
|
114
139
|
text = text.replace(/<div\s+([^>]*class="[^"]*\barticle-note\b[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi, function (match, openTag, inner) {
|
|
@@ -119,6 +144,16 @@
|
|
|
119
144
|
if (!hasMarkdownAttr(openTag)) return match;
|
|
120
145
|
return renderPoemHtml(inner);
|
|
121
146
|
});
|
|
147
|
+
// Theorem / proof: same markdown="1" contract as article-note. Without
|
|
148
|
+
// this pass, CommonMark ends the HTML block at the first blank line.
|
|
149
|
+
text = text.replace(/<div\s+([^>]*class="[^"]*\btheorem\b[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi, function (match, openTag, inner) {
|
|
150
|
+
if (!hasMarkdownAttr(openTag)) return match;
|
|
151
|
+
return renderTheoremHtml(openTag, inner);
|
|
152
|
+
});
|
|
153
|
+
text = text.replace(/<div\s+([^>]*class="[^"]*\bproof\b[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi, function (match, openTag, inner) {
|
|
154
|
+
if (!hasMarkdownAttr(openTag)) return match;
|
|
155
|
+
return renderProofHtml(inner);
|
|
156
|
+
});
|
|
122
157
|
return text;
|
|
123
158
|
}
|
|
124
159
|
|
data/assets/css/article.css
CHANGED
|
@@ -1007,6 +1007,91 @@ a.xcite-ref:hover {
|
|
|
1007
1007
|
margin-bottom: 0;
|
|
1008
1008
|
}
|
|
1009
1009
|
|
|
1010
|
+
/* ── Theorem and proof blocks ──
|
|
1011
|
+
Authored as `<div class="theorem" name="…" description="…" markdown="1">`
|
|
1012
|
+
and `<div class="proof" markdown="1">`. Theorems are bare (no plate): the
|
|
1013
|
+
runtime builds the head from name / description and italicizes the body.
|
|
1014
|
+
Proofs sit on a gray band that bleeds to the edges of `.text-page-main`
|
|
1015
|
+
while the text keeps the body measure; the runtime prefixes "Proof." and
|
|
1016
|
+
a QED square lands on the last line of the body. */
|
|
1017
|
+
.article-content .theorem {
|
|
1018
|
+
display: block;
|
|
1019
|
+
width: 100%;
|
|
1020
|
+
box-sizing: border-box;
|
|
1021
|
+
margin: 1.5em 0;
|
|
1022
|
+
font-size: inherit;
|
|
1023
|
+
line-height: inherit;
|
|
1024
|
+
color: var(--color-on-surface);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.article-content .theorem-head,
|
|
1028
|
+
.article-content .proof-head {
|
|
1029
|
+
margin: 0 0 0.5em;
|
|
1030
|
+
font-style: normal;
|
|
1031
|
+
font-weight: var(--weight-body);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.article-content .theorem-name,
|
|
1035
|
+
.article-content .proof-name {
|
|
1036
|
+
font-weight: var(--weight-emphasis);
|
|
1037
|
+
font-style: normal;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.article-content .theorem-description {
|
|
1041
|
+
font-weight: var(--weight-body);
|
|
1042
|
+
font-style: normal;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
.article-content .theorem-body {
|
|
1046
|
+
font-style: italic;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.article-content .theorem-body > :first-child,
|
|
1050
|
+
.article-content .proof-body > :first-child {
|
|
1051
|
+
margin-top: 0;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.article-content .theorem-body > :last-child,
|
|
1055
|
+
.article-content .proof-body > :last-child {
|
|
1056
|
+
margin-bottom: 0;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.article-content .proof {
|
|
1060
|
+
display: flow-root;
|
|
1061
|
+
box-sizing: border-box;
|
|
1062
|
+
position: relative;
|
|
1063
|
+
width: auto;
|
|
1064
|
+
max-width: none;
|
|
1065
|
+
margin: 1.5em calc(-1 * var(--space-md));
|
|
1066
|
+
padding: 1rem var(--space-md);
|
|
1067
|
+
background: var(--color-surface-container-low);
|
|
1068
|
+
font-size: inherit;
|
|
1069
|
+
line-height: inherit;
|
|
1070
|
+
color: var(--color-on-surface);
|
|
1071
|
+
-webkit-print-color-adjust: exact;
|
|
1072
|
+
print-color-adjust: exact;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
@media (min-width: 768px) {
|
|
1076
|
+
.article-content .proof {
|
|
1077
|
+
margin-left: calc(-1 * var(--space-2xl));
|
|
1078
|
+
margin-right: calc(-1 * var(--space-2xl));
|
|
1079
|
+
padding-left: var(--space-2xl);
|
|
1080
|
+
padding-right: var(--space-2xl);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.article-content .proof-body > :last-child::after {
|
|
1085
|
+
content: "□";
|
|
1086
|
+
float: right;
|
|
1087
|
+
margin-left: 0.35em;
|
|
1088
|
+
font-size: inherit;
|
|
1089
|
+
line-height: inherit;
|
|
1090
|
+
color: var(--color-on-surface);
|
|
1091
|
+
pointer-events: none;
|
|
1092
|
+
user-select: none;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1010
1095
|
/* ══ Code blocks ══
|
|
1011
1096
|
A fence used to render as a bare grey box: no indication of what language
|
|
1012
1097
|
was in it, and nothing to do with it but select the text by hand. It now
|
|
@@ -818,9 +818,10 @@ aside:has(> .text-detail-sidebar) {
|
|
|
818
818
|
font-weight: inherit;
|
|
819
819
|
}
|
|
820
820
|
|
|
821
|
-
/* ──
|
|
822
|
-
Authored
|
|
823
|
-
|
|
821
|
+
/* ── Field-note callout ──
|
|
822
|
+
Authored as `<div class="article-note" markdown="1">`; styled here, never
|
|
823
|
+
injected. Ochre wash + tertiary spine = scannable field note. Formal
|
|
824
|
+
theorem / proof blocks use `.theorem` / `.proof` in article.css instead. */
|
|
824
825
|
.article-content .article-note {
|
|
825
826
|
position: relative;
|
|
826
827
|
background: color-mix(in srgb, var(--color-tertiary) 10%, var(--color-panel-contrast));
|
|
@@ -24,7 +24,7 @@ module Pandorga
|
|
|
24
24
|
|
|
25
25
|
gem "pandorga", "~> 1.3"
|
|
26
26
|
# Local checkout: gem "pandorga", path: "../pandorga"
|
|
27
|
-
# GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.
|
|
27
|
+
# GitHub tag: gem "pandorga", github: "alexandrelheinen/pandorga", tag: "v1.8.1"
|
|
28
28
|
gem "csv"
|
|
29
29
|
gem "base64"
|
|
30
30
|
RUBY
|
data/lib/pandorga/version.rb
CHANGED
|
@@ -128,6 +128,25 @@ function preprocessMarkdownDivs(markdown) {
|
|
|
128
128
|
if (!hasMarkdownAttr(openTag)) return match;
|
|
129
129
|
return `<div class="poem"><p>${inner.trim()}</p></div>`;
|
|
130
130
|
});
|
|
131
|
+
text = text.replace(/<div\s+([^>]*class="[^"]*\btheorem\b[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi, (match, openTag, inner) => {
|
|
132
|
+
if (!hasMarkdownAttr(openTag)) return match;
|
|
133
|
+
const nameMatch = openTag.match(/\bname\s*=\s*(?:"([^"]*)"|'([^']*)')/i);
|
|
134
|
+
const descMatch = openTag.match(/\bdescription\s*=\s*(?:"([^"]*)"|'([^']*)')/i);
|
|
135
|
+
const n = nameMatch ? (nameMatch[1] ?? nameMatch[2] ?? '') : '';
|
|
136
|
+
const d = descMatch ? (descMatch[1] ?? descMatch[2] ?? '') : '';
|
|
137
|
+
let head = '';
|
|
138
|
+
if (n) {
|
|
139
|
+
head = `<p class="theorem-head"><span class="theorem-name">${escapeAttr(n)}</span>`;
|
|
140
|
+
if (d) head += ` <span class="theorem-description">(${escapeAttr(d)})</span>`;
|
|
141
|
+
head += '.</p>';
|
|
142
|
+
}
|
|
143
|
+
return `<div class="theorem">${head}<div class="theorem-body">${marked.parse(inner.trim())}</div></div>`;
|
|
144
|
+
});
|
|
145
|
+
text = text.replace(/<div\s+([^>]*class="[^"]*\bproof\b[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi, (match, openTag, inner) => {
|
|
146
|
+
if (!hasMarkdownAttr(openTag)) return match;
|
|
147
|
+
const head = '<p class="proof-head"><span class="proof-name">Proof</span>.</p>';
|
|
148
|
+
return `<div class="proof">${head}<div class="proof-body">${marked.parse(inner.trim())}</div></div>`;
|
|
149
|
+
});
|
|
131
150
|
return text;
|
|
132
151
|
}
|
|
133
152
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "theorem",
|
|
3
|
+
"markdown": "<div class=\"theorem\" name=\"Corollary 1\" description=\"nadir camera\" markdown=\"1\">\n\nLet the camera look straight down.\n\n</div>",
|
|
4
|
+
"selectors": ["theorem", "theorem-head", "theorem-name", "theorem-description", "theorem-body"]
|
|
5
|
+
}
|
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.
|
|
4
|
+
version: 1.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The Pandorga contributors
|
|
@@ -393,12 +393,14 @@ files:
|
|
|
393
393
|
- scripts/test/render-parity/ongoing-product.json
|
|
394
394
|
- scripts/test/render-parity/plotly.json
|
|
395
395
|
- scripts/test/render-parity/poem.json
|
|
396
|
+
- scripts/test/render-parity/proof.json
|
|
396
397
|
- scripts/test/render-parity/run-absent-field-checks.mjs
|
|
397
398
|
- scripts/test/render-parity/run-block-fixture.mjs
|
|
398
399
|
- scripts/test/render-parity/run-detail-parity-checks.mjs
|
|
399
400
|
- scripts/test/render-parity/run-field-flow-checks.mjs
|
|
400
401
|
- scripts/test/render-parity/run-fixture.mjs
|
|
401
402
|
- scripts/test/render-parity/selectors.mjs
|
|
403
|
+
- scripts/test/render-parity/theorem.json
|
|
402
404
|
- scripts/test/render-parity/video.json
|
|
403
405
|
- scripts/test/render-parity/youtube-short.json
|
|
404
406
|
- scripts/test/render-parity/youtube.json
|