@udx/md2html 1.2.1 → 1.4.0
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.
- package/index.js +83 -3
- package/package.json +1 -1
- package/static/chapter-navigation.css +62 -30
- package/static/scripts.js +52 -74
- package/static/styles.css +299 -27
- package/static/themes/legal.css +134 -0
- package/static/view.hbs +2 -0
package/index.js
CHANGED
|
@@ -89,7 +89,7 @@ const CHAPTER_NAV_STYLES_PATH = path.join(path.dirname(new URL(import.meta.url).
|
|
|
89
89
|
const SCRIPTS_PATH = path.join(path.dirname(new URL(import.meta.url).pathname), 'static/scripts.js');
|
|
90
90
|
|
|
91
91
|
program
|
|
92
|
-
.version('1.
|
|
92
|
+
.version('1.3.0')
|
|
93
93
|
.description('Convert markdown files to a single HTML document with Google Docs styling')
|
|
94
94
|
.option('-s, --src <file>', 'Source markdown file or directory')
|
|
95
95
|
.option('-o, --out <file>', 'Output HTML file path (optional - defaults to ./output.html)')
|
|
@@ -97,6 +97,8 @@ program
|
|
|
97
97
|
.option('-d, --debug', 'Enable debug logging', false)
|
|
98
98
|
.option('-p, --preview', 'Open generated HTML in browser with live preview server', false)
|
|
99
99
|
.option('--port <number>', 'Port for preview server (default: random)', parseInt)
|
|
100
|
+
.option('-c, --css <file>', 'Custom CSS file to include (or auto-detect custom.css in source directory)')
|
|
101
|
+
.option('--theme <name>', 'Built-in theme: default, legal', 'default')
|
|
100
102
|
.addHelpText('after', `
|
|
101
103
|
Examples:
|
|
102
104
|
Basic conversion:
|
|
@@ -111,7 +113,11 @@ Examples:
|
|
|
111
113
|
md2html -s content/docs --preview --port 3000
|
|
112
114
|
|
|
113
115
|
Single file:
|
|
114
|
-
md2html -s document.md --preview
|
|
116
|
+
md2html -s document.md --preview
|
|
117
|
+
|
|
118
|
+
Custom styling:
|
|
119
|
+
md2html -s content/docs --css=custom.css
|
|
120
|
+
md2html -s content/docs --theme=legal`)
|
|
115
121
|
.parse(process.argv);
|
|
116
122
|
|
|
117
123
|
const options = program.opts();
|
|
@@ -147,6 +153,40 @@ async function buildHtml(srcDir, outputFile) {
|
|
|
147
153
|
const chapterNavStyles = fs.readFileSync(CHAPTER_NAV_STYLES_PATH, 'utf8');
|
|
148
154
|
const jsScripts = fs.readFileSync(SCRIPTS_PATH, 'utf8');
|
|
149
155
|
|
|
156
|
+
// Load custom CSS if specified or auto-detect
|
|
157
|
+
let customStyles = '';
|
|
158
|
+
const srcDirResolved = fs.statSync(srcDir).isDirectory() ? srcDir : path.dirname(srcDir);
|
|
159
|
+
|
|
160
|
+
// Check for custom CSS in order of priority:
|
|
161
|
+
// 1. Explicit --css flag
|
|
162
|
+
// 2. custom.css in source directory
|
|
163
|
+
// 3. styles.css in source directory
|
|
164
|
+
const customCssPaths = [
|
|
165
|
+
options.css ? path.resolve(options.css) : null,
|
|
166
|
+
path.join(srcDirResolved, 'custom.css'),
|
|
167
|
+
path.join(srcDirResolved, 'styles.css')
|
|
168
|
+
].filter(Boolean);
|
|
169
|
+
|
|
170
|
+
for (const cssPath of customCssPaths) {
|
|
171
|
+
if (fs.existsSync(cssPath)) {
|
|
172
|
+
customStyles = fs.readFileSync(cssPath, 'utf8');
|
|
173
|
+
debug(`Loaded custom CSS from: ${cssPath}`);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Apply built-in theme styles from files
|
|
179
|
+
let themeStyles = '';
|
|
180
|
+
if (options.theme && options.theme !== 'default') {
|
|
181
|
+
const themePath = path.join(path.dirname(new URL(import.meta.url).pathname), `static/themes/${options.theme}.css`);
|
|
182
|
+
if (fs.existsSync(themePath)) {
|
|
183
|
+
themeStyles = fs.readFileSync(themePath, 'utf8');
|
|
184
|
+
debug(`Applied ${options.theme} theme from: ${themePath}`);
|
|
185
|
+
} else {
|
|
186
|
+
console.warn(`Warning: Theme '${options.theme}' not found at ${themePath}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
150
190
|
// Register custom Handlebars helpers
|
|
151
191
|
Handlebars.registerHelper('slugify', function(text) {
|
|
152
192
|
return text
|
|
@@ -552,6 +592,41 @@ async function buildHtml(srcDir, outputFile) {
|
|
|
552
592
|
|
|
553
593
|
processedContent = processedContent.replace(/<table>/g, '<table aria-hidden="true" role="presentation">');
|
|
554
594
|
|
|
595
|
+
// Convert checkbox syntax to FontAwesome icons
|
|
596
|
+
// Unchecked: - [ ] or * [ ] becomes FontAwesome square icon
|
|
597
|
+
// Checked: - [x] or * [x] becomes FontAwesome check-square icon
|
|
598
|
+
processedContent = processedContent.replace(
|
|
599
|
+
/<li>\s*\[\s*\]\s*/gi,
|
|
600
|
+
'<li class="checkbox-item"><i class="far fa-square checkbox-icon"></i> '
|
|
601
|
+
);
|
|
602
|
+
processedContent = processedContent.replace(
|
|
603
|
+
/<li>\s*\[x\]\s*/gi,
|
|
604
|
+
'<li class="checkbox-item checkbox-checked"><i class="fas fa-check-square checkbox-icon"></i> '
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
// Process inline SVG elements for proper sizing
|
|
608
|
+
// Add responsive wrapper and ensure viewBox is preserved
|
|
609
|
+
processedContent = processedContent.replace(
|
|
610
|
+
/<svg([^>]*)>/gi,
|
|
611
|
+
(match, attrs) => {
|
|
612
|
+
// Check if it already has a class
|
|
613
|
+
if (attrs.includes('class=')) {
|
|
614
|
+
return match.replace(/class="([^"]*)"/, 'class="$1 svg-responsive"');
|
|
615
|
+
}
|
|
616
|
+
return `<svg class="svg-responsive"${attrs}>`;
|
|
617
|
+
}
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
// Wrap standalone SVG elements in a figure for better layout control
|
|
621
|
+
processedContent = processedContent.replace(
|
|
622
|
+
/(<p>)?(<svg[^>]*>[\s\S]*?<\/svg>)(<\/p>)?/gi,
|
|
623
|
+
(match, openP, svg, closeP) => {
|
|
624
|
+
// If SVG is already in a figure, don't wrap again
|
|
625
|
+
if (match.includes('<figure')) return match;
|
|
626
|
+
return `<figure class="svg-container">${svg}</figure>`;
|
|
627
|
+
}
|
|
628
|
+
);
|
|
629
|
+
|
|
555
630
|
// If it's an imgix URL, add width parameter
|
|
556
631
|
processedContent = processedContent.replace(/src="(https:\/\/[^"]*imgix\.net\/[^"]+)(?:\?([^"]*))?"/g, (match, url, params) => {
|
|
557
632
|
if (params && params.includes('w=')) {
|
|
@@ -635,6 +710,11 @@ async function buildHtml(srcDir, outputFile) {
|
|
|
635
710
|
processedWithHeadingAttrs += `\n<script type="application/json" id="document-chapters-data">${chaptersJSON}</script>\n`;
|
|
636
711
|
|
|
637
712
|
// Prepare data for template
|
|
713
|
+
// Combine all styles: base + chapter nav + theme + custom (custom overrides all)
|
|
714
|
+
const allStyles = [cssStyles, chapterNavStyles, themeStyles, customStyles]
|
|
715
|
+
.filter(Boolean)
|
|
716
|
+
.join('\n\n');
|
|
717
|
+
|
|
638
718
|
const templateData = {
|
|
639
719
|
title,
|
|
640
720
|
description,
|
|
@@ -642,7 +722,7 @@ async function buildHtml(srcDir, outputFile) {
|
|
|
642
722
|
date,
|
|
643
723
|
version,
|
|
644
724
|
content: processedWithHeadingAttrs,
|
|
645
|
-
styles:
|
|
725
|
+
styles: allStyles,
|
|
646
726
|
scripts: jsScripts,
|
|
647
727
|
chapters: chaptersInfo
|
|
648
728
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/* Chapter Navigation Styles */
|
|
2
2
|
:root {
|
|
3
|
-
--chapter-nav-width:
|
|
4
|
-
--chapter-nav-text-color: #
|
|
5
|
-
--chapter-nav-text-faded: rgba(51, 51, 51, 0.
|
|
6
|
-
--chapter-
|
|
7
|
-
--chapter-text-
|
|
8
|
-
--chapter-text-inactive-size: calc(var(--chapter-text-normal-size) * 0.8);
|
|
3
|
+
--chapter-nav-width: 220px;
|
|
4
|
+
--chapter-nav-text-color: #1a1a1a;
|
|
5
|
+
--chapter-nav-text-faded: rgba(51, 51, 51, 0.65);
|
|
6
|
+
--chapter-nav-active-color: #991b1b;
|
|
7
|
+
--chapter-text-size: 0.85rem;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
/* Container for the floating navigation */
|
|
@@ -17,16 +16,16 @@
|
|
|
17
16
|
/* Floating navigation styles - clean and minimal */
|
|
18
17
|
.chapter-navigation {
|
|
19
18
|
position: fixed;
|
|
20
|
-
top:
|
|
21
|
-
|
|
22
|
-
left: 20px;
|
|
19
|
+
top: 0;
|
|
20
|
+
left: 0;
|
|
23
21
|
width: var(--chapter-nav-width);
|
|
24
|
-
|
|
22
|
+
height: 100vh;
|
|
25
23
|
overflow-y: auto;
|
|
26
|
-
background-color:
|
|
27
|
-
padding:
|
|
24
|
+
background-color: #fff;
|
|
25
|
+
padding: 40px 20px 60px 20px;
|
|
28
26
|
z-index: 100;
|
|
29
|
-
scrollbar-width:
|
|
27
|
+
scrollbar-width: thin; /* Show thin scrollbar for Firefox */
|
|
28
|
+
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
|
30
29
|
transition: transform 0.3s ease;
|
|
31
30
|
border: 0 none transparent !important;
|
|
32
31
|
box-shadow: none !important;
|
|
@@ -35,9 +34,18 @@
|
|
|
35
34
|
-moz-box-shadow: none !important;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
/*
|
|
37
|
+
/* Show thin scrollbar for Chrome, Safari and Opera */
|
|
39
38
|
.chapter-navigation::-webkit-scrollbar {
|
|
40
|
-
|
|
39
|
+
width: 4px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.chapter-navigation::-webkit-scrollbar-track {
|
|
43
|
+
background: transparent;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.chapter-navigation::-webkit-scrollbar-thumb {
|
|
47
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
48
|
+
border-radius: 2px;
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
.chapter-nav-list {
|
|
@@ -47,20 +55,24 @@
|
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
.chapter-nav-item {
|
|
50
|
-
margin-bottom:
|
|
58
|
+
margin-bottom: 12px;
|
|
51
59
|
transition: all 0.3s ease;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
.chapter-nav-link {
|
|
55
63
|
display: block;
|
|
56
|
-
padding:
|
|
57
|
-
font-size: var(--chapter-text-
|
|
64
|
+
padding: 6px 0;
|
|
65
|
+
font-size: var(--chapter-text-size);
|
|
58
66
|
color: var(--chapter-nav-text-faded);
|
|
59
67
|
text-decoration: none;
|
|
60
|
-
transition:
|
|
68
|
+
transition: color 0.2s ease, text-decoration 0.2s ease;
|
|
61
69
|
background-color: transparent;
|
|
62
70
|
border-radius: 0;
|
|
63
|
-
line-height: 1.
|
|
71
|
+
line-height: 1.4;
|
|
72
|
+
/* Better text handling for long titles */
|
|
73
|
+
word-wrap: break-word;
|
|
74
|
+
overflow-wrap: break-word;
|
|
75
|
+
hyphens: auto;
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
.chapter-nav-link:hover {
|
|
@@ -68,9 +80,12 @@
|
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
.chapter-nav-item.active .chapter-nav-link {
|
|
71
|
-
font-size
|
|
72
|
-
|
|
83
|
+
/* Use color and underline instead of font-size to prevent jumping */
|
|
84
|
+
font-size: var(--chapter-text-size);
|
|
85
|
+
color: var(--chapter-nav-active-color);
|
|
73
86
|
font-weight: 500;
|
|
87
|
+
text-decoration: underline;
|
|
88
|
+
text-underline-offset: 3px;
|
|
74
89
|
}
|
|
75
90
|
|
|
76
91
|
/* Mobile dropdown styles - native-looking and minimal */
|
|
@@ -169,19 +184,28 @@
|
|
|
169
184
|
|
|
170
185
|
.chapter-dropdown-menu li.active a {
|
|
171
186
|
font-weight: 500;
|
|
172
|
-
color: var(--chapter-nav-
|
|
173
|
-
|
|
187
|
+
color: var(--chapter-nav-active-color);
|
|
188
|
+
text-decoration: underline;
|
|
189
|
+
text-underline-offset: 3px;
|
|
174
190
|
}
|
|
175
191
|
|
|
176
192
|
/* Add padding to the content to prevent floating nav from overlapping */
|
|
193
|
+
/* Content is centered in the remaining space to the right of the sidebar */
|
|
177
194
|
.chapter-content {
|
|
178
|
-
|
|
195
|
+
/* Leave space for sidebar on the left - push content further right */
|
|
196
|
+
margin-left: calc(var(--chapter-nav-width) + 120px);
|
|
197
|
+
/* Add margin on the right for balance */
|
|
198
|
+
margin-right: 80px;
|
|
199
|
+
/* Remove padding-left since we're using margin */
|
|
200
|
+
padding-left: 0;
|
|
201
|
+
padding-right: 0;
|
|
179
202
|
}
|
|
180
203
|
|
|
181
204
|
/* Responsive adjustments */
|
|
182
205
|
@media (max-width: 1024px) {
|
|
183
206
|
.chapter-content {
|
|
184
|
-
|
|
207
|
+
margin-left: calc(var(--chapter-nav-width) + 60px);
|
|
208
|
+
margin-right: 40px;
|
|
185
209
|
}
|
|
186
210
|
}
|
|
187
211
|
|
|
@@ -195,12 +219,14 @@
|
|
|
195
219
|
}
|
|
196
220
|
|
|
197
221
|
.chapter-content {
|
|
198
|
-
|
|
199
|
-
|
|
222
|
+
margin-left: 20px;
|
|
223
|
+
margin-right: 20px;
|
|
224
|
+
padding-left: 0;
|
|
225
|
+
padding-right: 0;
|
|
200
226
|
}
|
|
201
227
|
}
|
|
202
228
|
|
|
203
|
-
/* Hide nav when printing */
|
|
229
|
+
/* Hide nav when printing - let browser print dialog control all margins */
|
|
204
230
|
@media print {
|
|
205
231
|
.chapter-navigation,
|
|
206
232
|
.mobile-chapter-nav {
|
|
@@ -208,6 +234,12 @@
|
|
|
208
234
|
}
|
|
209
235
|
|
|
210
236
|
.chapter-content {
|
|
211
|
-
padding
|
|
237
|
+
/* Remove all margins and padding so browser print dialog controls page margins */
|
|
238
|
+
margin-left: 0 !important;
|
|
239
|
+
margin-right: 0 !important;
|
|
240
|
+
padding-left: 0 !important;
|
|
241
|
+
padding-right: 0 !important;
|
|
242
|
+
max-width: 100% !important;
|
|
243
|
+
width: 100% !important;
|
|
212
244
|
}
|
|
213
245
|
}
|
package/static/scripts.js
CHANGED
|
@@ -44,51 +44,16 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
//
|
|
47
|
+
// Table enhancement - add responsive wrapper and basic styling
|
|
48
|
+
// Note: We do NOT set inline styles for table-layout or width to avoid conflicts with CSS
|
|
48
49
|
document.querySelectorAll('table').forEach(table => {
|
|
49
|
-
// Force full width with inline style AND classes
|
|
50
|
-
table.style.width = '100%';
|
|
51
|
-
table.style.tableLayout = 'fixed';
|
|
52
|
-
table.setAttribute('width', '100%');
|
|
53
|
-
table.classList.add('w-full');
|
|
54
|
-
table.classList.add('table-fixed');
|
|
55
|
-
|
|
56
50
|
// Add responsive wrapper if not already wrapped
|
|
57
51
|
if (table.parentElement.tagName !== 'DIV' || !table.parentElement.classList.contains('table-responsive')) {
|
|
58
52
|
const wrapper = document.createElement('div');
|
|
59
|
-
wrapper.className = 'table-responsive
|
|
60
|
-
wrapper.style.width = '100%';
|
|
61
|
-
wrapper.style.maxWidth = '100%';
|
|
53
|
+
wrapper.className = 'table-responsive';
|
|
62
54
|
table.parentNode.insertBefore(wrapper, table);
|
|
63
55
|
wrapper.appendChild(table);
|
|
64
56
|
}
|
|
65
|
-
|
|
66
|
-
// Add proper classes and styles to table headers
|
|
67
|
-
table.querySelectorAll('th').forEach(th => {
|
|
68
|
-
th.classList.add('bg-gray-50');
|
|
69
|
-
th.classList.add('font-semibold');
|
|
70
|
-
th.classList.add('p-3');
|
|
71
|
-
th.classList.add('text-left');
|
|
72
|
-
th.classList.add('border');
|
|
73
|
-
th.classList.add('border-gray-200');
|
|
74
|
-
th.style.padding = '0.75rem 1rem';
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Add proper classes and styles to table cells
|
|
78
|
-
table.querySelectorAll('td').forEach(td => {
|
|
79
|
-
td.classList.add('p-3');
|
|
80
|
-
td.classList.add('text-left');
|
|
81
|
-
td.classList.add('border');
|
|
82
|
-
td.classList.add('border-gray-200');
|
|
83
|
-
td.style.padding = '0.75rem 1rem';
|
|
84
|
-
td.style.borderColor = 'rgba(0, 0, 0, 0.1)';
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Force table to use entire container width
|
|
88
|
-
const parentWidth = table.parentElement.offsetWidth;
|
|
89
|
-
if (parentWidth > 0) {
|
|
90
|
-
table.style.minWidth = parentWidth + 'px';
|
|
91
|
-
}
|
|
92
57
|
});
|
|
93
58
|
|
|
94
59
|
// Remove any blue highlights
|
|
@@ -122,24 +87,6 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
122
87
|
}
|
|
123
88
|
});
|
|
124
89
|
|
|
125
|
-
// Improve table layout and ensure proper alignment
|
|
126
|
-
document.querySelectorAll('table').forEach(table => {
|
|
127
|
-
// Add a container for horizontal scrolling if needed
|
|
128
|
-
const wrapper = document.createElement('div');
|
|
129
|
-
wrapper.style.width = '100%';
|
|
130
|
-
wrapper.style.overflowX = 'auto';
|
|
131
|
-
table.parentNode.insertBefore(wrapper, table);
|
|
132
|
-
wrapper.appendChild(table);
|
|
133
|
-
|
|
134
|
-
// Ensure consistent styling
|
|
135
|
-
table.querySelectorAll('th, td').forEach(cell => {
|
|
136
|
-
cell.style.padding = '0.75em 1em';
|
|
137
|
-
cell.style.verticalAlign = 'top';
|
|
138
|
-
cell.style.textAlign = 'left';
|
|
139
|
-
cell.style.fontSize = '18px';
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
90
|
// Process quote attributions with em dash
|
|
144
91
|
document.querySelectorAll('blockquote + p').forEach(p => {
|
|
145
92
|
const text = p.textContent || '';
|
|
@@ -206,10 +153,11 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
206
153
|
|
|
207
154
|
window.updateActiveChapter = () => {
|
|
208
155
|
try {
|
|
209
|
-
//
|
|
210
|
-
const
|
|
156
|
+
// Target H2 and H3 headings for navigation
|
|
157
|
+
const allHeadings = Array.from(document.querySelectorAll('h2, h3'));
|
|
158
|
+
const h2Headings = Array.from(document.querySelectorAll('h2'));
|
|
211
159
|
|
|
212
|
-
if (!
|
|
160
|
+
if (!allHeadings.length || !chapterNavItems.length) return;
|
|
213
161
|
|
|
214
162
|
// Calculate which heading is most visible in the viewport
|
|
215
163
|
const viewportHeight = window.innerHeight;
|
|
@@ -218,7 +166,7 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
218
166
|
let bestVisibleHeading = null;
|
|
219
167
|
let bestVisibleScore = -1;
|
|
220
168
|
|
|
221
|
-
|
|
169
|
+
allHeadings.forEach(heading => {
|
|
222
170
|
if (!heading) return;
|
|
223
171
|
|
|
224
172
|
const rect = heading.getBoundingClientRect();
|
|
@@ -240,10 +188,29 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
240
188
|
}
|
|
241
189
|
});
|
|
242
190
|
|
|
191
|
+
// Find the parent H2 for the current heading (if it's an H3)
|
|
192
|
+
const findParentH2 = (heading) => {
|
|
193
|
+
if (!heading || heading.tagName === 'H2') return heading;
|
|
194
|
+
|
|
195
|
+
// Walk backwards through all headings to find the parent H2
|
|
196
|
+
const headingIndex = allHeadings.indexOf(heading);
|
|
197
|
+
for (let i = headingIndex - 1; i >= 0; i--) {
|
|
198
|
+
if (allHeadings[i].tagName === 'H2') {
|
|
199
|
+
return allHeadings[i];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
};
|
|
204
|
+
|
|
243
205
|
if (bestVisibleHeading) {
|
|
244
206
|
const headingId = bestVisibleHeading.getAttribute('id');
|
|
245
207
|
const headingText = bestVisibleHeading.textContent.trim();
|
|
246
208
|
|
|
209
|
+
// Get parent H2 if current heading is H3
|
|
210
|
+
const parentH2 = findParentH2(bestVisibleHeading);
|
|
211
|
+
const parentH2Text = parentH2 ? parentH2.textContent.trim() : null;
|
|
212
|
+
const parentH2Id = parentH2 ? parentH2.getAttribute('id') : null;
|
|
213
|
+
|
|
247
214
|
chapterNavItems.forEach(item => {
|
|
248
215
|
if (!item) return;
|
|
249
216
|
|
|
@@ -251,22 +218,30 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
251
218
|
if (!navLink) return;
|
|
252
219
|
|
|
253
220
|
const itemText = navLink.textContent.trim();
|
|
254
|
-
const
|
|
221
|
+
const itemId = item.getAttribute('data-chapter-id');
|
|
222
|
+
|
|
223
|
+
// Check if this nav item matches the current heading OR its parent H2
|
|
224
|
+
const isCurrentHeading = itemText === headingText || itemId === headingId;
|
|
225
|
+
const isParentSection = parentH2 && (itemText === parentH2Text || itemId === parentH2Id);
|
|
226
|
+
const isActive = isCurrentHeading || isParentSection;
|
|
255
227
|
|
|
256
228
|
if (isActive) {
|
|
257
229
|
item.classList.add('active');
|
|
258
230
|
|
|
259
|
-
|
|
260
|
-
if (
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
231
|
+
// Only scroll to and update text for the most specific (current) heading
|
|
232
|
+
if (isCurrentHeading) {
|
|
233
|
+
const navContainer = document.querySelector('.chapter-navigation');
|
|
234
|
+
if (navContainer) {
|
|
235
|
+
const itemOffset = item.offsetTop;
|
|
236
|
+
const navHeight = navContainer.offsetHeight;
|
|
237
|
+
const itemHeight = item.offsetHeight;
|
|
238
|
+
|
|
239
|
+
navContainer.scrollTop = itemOffset - (navHeight / 2) + (itemHeight / 2);
|
|
240
|
+
}
|
|
264
241
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (currentChapterText) {
|
|
269
|
-
currentChapterText.textContent = itemText;
|
|
242
|
+
if (currentChapterText) {
|
|
243
|
+
currentChapterText.textContent = itemText;
|
|
244
|
+
}
|
|
270
245
|
}
|
|
271
246
|
} else {
|
|
272
247
|
item.classList.remove('active');
|
|
@@ -281,7 +256,10 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
281
256
|
if (!link) return;
|
|
282
257
|
|
|
283
258
|
const itemText = link.textContent.trim();
|
|
284
|
-
const
|
|
259
|
+
const itemId = item.getAttribute('data-chapter-id');
|
|
260
|
+
const isCurrentHeading = itemText === headingText || itemId === headingId;
|
|
261
|
+
const isParentSection = parentH2 && (itemText === parentH2Text || itemId === parentH2Id);
|
|
262
|
+
const isActive = isCurrentHeading || isParentSection;
|
|
285
263
|
|
|
286
264
|
if (isActive) {
|
|
287
265
|
item.classList.add('active');
|
|
@@ -289,8 +267,8 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
289
267
|
item.classList.remove('active');
|
|
290
268
|
}
|
|
291
269
|
});
|
|
292
|
-
} else if (
|
|
293
|
-
const firstHeading =
|
|
270
|
+
} else if (h2Headings.length > 0) {
|
|
271
|
+
const firstHeading = h2Headings[0];
|
|
294
272
|
const firstHeadingText = firstHeading.textContent.trim();
|
|
295
273
|
|
|
296
274
|
chapterNavItems.forEach(item => {
|
package/static/styles.css
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
@media print {
|
|
2
|
+
/* Remove all margins so browser print dialog controls page margins */
|
|
3
|
+
html, body {
|
|
4
|
+
margin: 0 !important;
|
|
5
|
+
padding: 0 !important;
|
|
6
|
+
}
|
|
7
|
+
|
|
2
8
|
pre, pre code {
|
|
3
9
|
white-space: pre-wrap !important;
|
|
4
10
|
overflow-x: hidden !important;
|
|
@@ -27,11 +33,15 @@
|
|
|
27
33
|
.content-container {
|
|
28
34
|
max-width: 100% !important;
|
|
29
35
|
width: 100% !important;
|
|
36
|
+
margin: 0 !important;
|
|
37
|
+
padding: 0 !important;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
article {
|
|
40
|
+
article, main, section {
|
|
33
41
|
width: 100% !important;
|
|
34
42
|
max-width: 100% !important;
|
|
43
|
+
margin: 0 !important;
|
|
44
|
+
padding: 0 !important;
|
|
35
45
|
}
|
|
36
46
|
}
|
|
37
47
|
|
|
@@ -182,42 +192,41 @@ blockquote + p {
|
|
|
182
192
|
margin-top: 2em;
|
|
183
193
|
}
|
|
184
194
|
|
|
185
|
-
/* Enhanced table styling
|
|
195
|
+
/* Enhanced table styling - use auto layout for natural column sizing */
|
|
186
196
|
.prose table,
|
|
187
197
|
table.w-full,
|
|
188
198
|
article table,
|
|
189
199
|
div table,
|
|
190
200
|
.table-responsive table {
|
|
191
|
-
width: 100
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
table-layout: fixed !important;
|
|
197
|
-
display: table !important;
|
|
201
|
+
width: 100%;
|
|
202
|
+
margin: 2em 0;
|
|
203
|
+
border-collapse: collapse;
|
|
204
|
+
table-layout: auto;
|
|
205
|
+
display: table;
|
|
198
206
|
}
|
|
199
207
|
|
|
200
208
|
/* Table wrapper to handle overflow properly */
|
|
201
209
|
.table-responsive,
|
|
202
210
|
div.overflow-x-auto {
|
|
203
|
-
width: 100
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
display: block !important;
|
|
211
|
+
width: 100%;
|
|
212
|
+
max-width: 100%;
|
|
213
|
+
overflow-x: auto;
|
|
214
|
+
margin: 2em 0;
|
|
215
|
+
display: block;
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
.prose table th, .prose table td {
|
|
212
|
-
padding: 0.75em 1em
|
|
213
|
-
border: 1px solid rgba(0, 0, 0, 0.1)
|
|
214
|
-
text-align: left
|
|
215
|
-
vertical-align: top
|
|
219
|
+
padding: 0.75em 1em;
|
|
220
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
221
|
+
text-align: left;
|
|
222
|
+
vertical-align: top;
|
|
223
|
+
word-wrap: break-word;
|
|
224
|
+
overflow-wrap: break-word;
|
|
216
225
|
}
|
|
217
226
|
|
|
218
227
|
.prose table th {
|
|
219
|
-
font-weight: 600
|
|
220
|
-
background-color: rgba(0, 0, 0, 0.05)
|
|
228
|
+
font-weight: 600;
|
|
229
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
221
230
|
}
|
|
222
231
|
|
|
223
232
|
/* Grid-based tables for special formatting needs */
|
|
@@ -338,26 +347,60 @@ pre:has(.file-type-badge) .copy-button {
|
|
|
338
347
|
display: none;
|
|
339
348
|
}
|
|
340
349
|
|
|
341
|
-
/*
|
|
350
|
+
/* ============================================
|
|
351
|
+
VISUAL ELEMENT SPACING
|
|
352
|
+
Consistent spacing for images, SVG, mermaid, figures
|
|
353
|
+
============================================ */
|
|
354
|
+
|
|
355
|
+
/* Base visual element spacing - consistent 1.5em above and below */
|
|
356
|
+
:root {
|
|
357
|
+
--visual-spacing-top: 1.5em;
|
|
358
|
+
--visual-spacing-bottom: 1.5em;
|
|
359
|
+
--visual-spacing-print-top: 1em;
|
|
360
|
+
--visual-spacing-print-bottom: 1em;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Figure element - wrapper for images with captions */
|
|
342
364
|
figure {
|
|
343
|
-
margin-top:
|
|
344
|
-
margin-bottom:
|
|
365
|
+
margin-top: var(--visual-spacing-top);
|
|
366
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
345
367
|
text-align: center;
|
|
368
|
+
display: block;
|
|
346
369
|
}
|
|
347
370
|
|
|
371
|
+
/* Images - standalone or within figures */
|
|
348
372
|
img {
|
|
349
373
|
max-width: 100%;
|
|
350
374
|
height: auto;
|
|
351
375
|
border-radius: 0.25em;
|
|
352
|
-
|
|
353
|
-
margin-
|
|
376
|
+
display: block;
|
|
377
|
+
margin-left: auto;
|
|
378
|
+
margin-right: auto;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* Standalone images (not in figure) get vertical spacing */
|
|
382
|
+
p > img,
|
|
383
|
+
article > img,
|
|
384
|
+
section > img,
|
|
385
|
+
main > img,
|
|
386
|
+
.prose > img {
|
|
387
|
+
margin-top: var(--visual-spacing-top);
|
|
388
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* Images inside figures don't need extra spacing */
|
|
392
|
+
figure img {
|
|
393
|
+
margin-top: 0;
|
|
394
|
+
margin-bottom: 0;
|
|
354
395
|
}
|
|
355
396
|
|
|
397
|
+
/* Figure captions */
|
|
356
398
|
figcaption {
|
|
357
|
-
margin-top: 0.
|
|
399
|
+
margin-top: 0.75em;
|
|
358
400
|
font-size: 0.9em;
|
|
359
401
|
color: #64748b;
|
|
360
402
|
font-style: italic;
|
|
403
|
+
text-align: center;
|
|
361
404
|
}
|
|
362
405
|
|
|
363
406
|
/* Alt text is visually hidden but accessible for screen readers */
|
|
@@ -482,3 +525,232 @@ a:hover {
|
|
|
482
525
|
.MathJax {
|
|
483
526
|
font-size: 1.1em !important;
|
|
484
527
|
}
|
|
528
|
+
|
|
529
|
+
/* Checkbox styling with FontAwesome icons */
|
|
530
|
+
.checkbox-item {
|
|
531
|
+
list-style: none;
|
|
532
|
+
margin-left: -1.5em;
|
|
533
|
+
padding-left: 0;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.checkbox-icon {
|
|
537
|
+
color: #6b7280;
|
|
538
|
+
font-size: 1.1em;
|
|
539
|
+
margin-right: 0.5em;
|
|
540
|
+
vertical-align: middle;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.checkbox-checked .checkbox-icon {
|
|
544
|
+
color: #10b981;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/* SVG responsive styling */
|
|
548
|
+
.svg-responsive {
|
|
549
|
+
max-width: 100%;
|
|
550
|
+
height: auto;
|
|
551
|
+
display: block;
|
|
552
|
+
margin-left: auto;
|
|
553
|
+
margin-right: auto;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/* SVG container with consistent spacing */
|
|
557
|
+
.svg-container {
|
|
558
|
+
margin-top: var(--visual-spacing-top);
|
|
559
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
560
|
+
margin-left: auto;
|
|
561
|
+
margin-right: auto;
|
|
562
|
+
text-align: center;
|
|
563
|
+
max-width: 100%;
|
|
564
|
+
overflow-x: auto;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.svg-container svg {
|
|
568
|
+
max-width: 100%;
|
|
569
|
+
height: auto;
|
|
570
|
+
display: block;
|
|
571
|
+
margin-left: auto;
|
|
572
|
+
margin-right: auto;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* Standalone SVG elements (not in container) */
|
|
576
|
+
article > svg,
|
|
577
|
+
section > svg,
|
|
578
|
+
main > svg,
|
|
579
|
+
.prose > svg {
|
|
580
|
+
margin-top: var(--visual-spacing-top);
|
|
581
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
582
|
+
display: block;
|
|
583
|
+
margin-left: auto;
|
|
584
|
+
margin-right: auto;
|
|
585
|
+
max-width: 100%;
|
|
586
|
+
height: auto;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* Mermaid diagram containers - consistent spacing */
|
|
590
|
+
.mermaid {
|
|
591
|
+
margin-top: var(--visual-spacing-top);
|
|
592
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
593
|
+
text-align: center;
|
|
594
|
+
overflow-x: auto;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.mermaid svg {
|
|
598
|
+
max-width: 100%;
|
|
599
|
+
height: auto;
|
|
600
|
+
display: block;
|
|
601
|
+
margin-left: auto;
|
|
602
|
+
margin-right: auto;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/* Signature block styling for SVG signatures */
|
|
606
|
+
.signature-block {
|
|
607
|
+
margin-top: var(--visual-spacing-top);
|
|
608
|
+
margin-bottom: var(--visual-spacing-bottom);
|
|
609
|
+
padding: 1em;
|
|
610
|
+
border-top: 1px solid #e5e7eb;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.signature-block svg {
|
|
614
|
+
max-width: 300px;
|
|
615
|
+
height: auto;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/* Print styling for visual elements */
|
|
619
|
+
@media print {
|
|
620
|
+
/* Consistent print spacing for all visual elements */
|
|
621
|
+
figure,
|
|
622
|
+
.svg-container,
|
|
623
|
+
.mermaid,
|
|
624
|
+
article > img,
|
|
625
|
+
section > img,
|
|
626
|
+
main > img,
|
|
627
|
+
.prose > img {
|
|
628
|
+
margin-top: var(--visual-spacing-print-top);
|
|
629
|
+
margin-bottom: var(--visual-spacing-print-bottom);
|
|
630
|
+
page-break-inside: avoid;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.svg-responsive {
|
|
634
|
+
max-width: 6in;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/* Ensure images don't overflow in print */
|
|
638
|
+
img, svg {
|
|
639
|
+
max-width: 100% !important;
|
|
640
|
+
height: auto !important;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/* ============================================
|
|
645
|
+
PRINT PAGE BREAK SUPPORT
|
|
646
|
+
============================================ */
|
|
647
|
+
|
|
648
|
+
/* Manual page break - use <!-- pagebreak --> in markdown */
|
|
649
|
+
.page-break {
|
|
650
|
+
page-break-before: always;
|
|
651
|
+
break-before: page;
|
|
652
|
+
height: 0;
|
|
653
|
+
margin: 0;
|
|
654
|
+
padding: 0;
|
|
655
|
+
border: none;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/* Print-specific page break rules */
|
|
659
|
+
@media print {
|
|
660
|
+
/* Force page break before h1 (new chapters/volumes) */
|
|
661
|
+
h1 {
|
|
662
|
+
page-break-before: always;
|
|
663
|
+
break-before: page;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/* First h1 should not have page break before it */
|
|
667
|
+
section:first-of-type h1:first-child,
|
|
668
|
+
article:first-of-type h1:first-child,
|
|
669
|
+
main > h1:first-child {
|
|
670
|
+
page-break-before: auto;
|
|
671
|
+
break-before: auto;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/* Keep headings with their following content */
|
|
675
|
+
h1, h2, h3, h4, h5, h6 {
|
|
676
|
+
page-break-after: avoid;
|
|
677
|
+
break-after: avoid;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/* Prevent page breaks inside these elements */
|
|
681
|
+
table, figure, pre, blockquote, ul, ol {
|
|
682
|
+
page-break-inside: avoid;
|
|
683
|
+
break-inside: avoid;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/* For very long tables, allow breaks but keep header visible */
|
|
687
|
+
table.allow-break {
|
|
688
|
+
page-break-inside: auto;
|
|
689
|
+
break-inside: auto;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
table.allow-break thead {
|
|
693
|
+
display: table-header-group;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
table.allow-break tr {
|
|
697
|
+
page-break-inside: avoid;
|
|
698
|
+
break-inside: avoid;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/* Orphan and widow control for paragraphs */
|
|
702
|
+
p {
|
|
703
|
+
orphans: 3;
|
|
704
|
+
widows: 3;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* Keep images with their captions */
|
|
708
|
+
figure {
|
|
709
|
+
page-break-inside: avoid;
|
|
710
|
+
break-inside: avoid;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* Keep list items together */
|
|
714
|
+
li {
|
|
715
|
+
page-break-inside: avoid;
|
|
716
|
+
break-inside: avoid;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/* ============================================
|
|
721
|
+
TABLE STYLING
|
|
722
|
+
============================================ */
|
|
723
|
+
|
|
724
|
+
/* Tables use auto layout to fit content naturally */
|
|
725
|
+
table {
|
|
726
|
+
table-layout: auto;
|
|
727
|
+
width: 100%;
|
|
728
|
+
border-collapse: collapse;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/* Ensure table cells don't overlap */
|
|
732
|
+
table th,
|
|
733
|
+
table td {
|
|
734
|
+
padding: 0.75em 1em;
|
|
735
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
736
|
+
text-align: left;
|
|
737
|
+
vertical-align: top;
|
|
738
|
+
word-wrap: break-word;
|
|
739
|
+
overflow-wrap: break-word;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
table th {
|
|
743
|
+
font-weight: 600;
|
|
744
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Print table sizing */
|
|
748
|
+
@media print {
|
|
749
|
+
table {
|
|
750
|
+
font-size: 10pt;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
table th, table td {
|
|
754
|
+
padding: 4pt 8pt;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/* Legal Theme - Professional government proposal and legal document styling */
|
|
2
|
+
/* Inspired by NSF GOALI proposal formatting and federal document standards */
|
|
3
|
+
|
|
4
|
+
body {
|
|
5
|
+
font-family: "Times New Roman", Times, Georgia, serif;
|
|
6
|
+
font-size: 12pt;
|
|
7
|
+
line-height: 1.5;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.content-container {
|
|
11
|
+
max-width: 8.5in;
|
|
12
|
+
padding: 1in;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Formal heading styles */
|
|
16
|
+
.prose h1, h1 {
|
|
17
|
+
font-size: 18pt !important;
|
|
18
|
+
font-weight: bold !important;
|
|
19
|
+
text-align: center !important;
|
|
20
|
+
margin-bottom: 24pt !important;
|
|
21
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.prose h2, h2 {
|
|
25
|
+
font-size: 14pt !important;
|
|
26
|
+
font-weight: bold !important;
|
|
27
|
+
margin-top: 18pt !important;
|
|
28
|
+
margin-bottom: 12pt !important;
|
|
29
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.prose h3, h3 {
|
|
33
|
+
font-size: 12pt !important;
|
|
34
|
+
font-weight: bold !important;
|
|
35
|
+
margin-top: 12pt !important;
|
|
36
|
+
margin-bottom: 6pt !important;
|
|
37
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.prose h4, h4, .prose h5, h5, .prose h6, h6 {
|
|
41
|
+
font-size: 12pt !important;
|
|
42
|
+
font-weight: bold !important;
|
|
43
|
+
font-style: italic !important;
|
|
44
|
+
margin-top: 12pt !important;
|
|
45
|
+
margin-bottom: 6pt !important;
|
|
46
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.prose p, p {
|
|
50
|
+
font-size: 12pt !important;
|
|
51
|
+
text-align: justify !important;
|
|
52
|
+
margin-bottom: 12pt !important;
|
|
53
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.prose li {
|
|
57
|
+
font-size: 12pt !important;
|
|
58
|
+
font-family: "Times New Roman", Times, Georgia, serif !important;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Table styling for government documents */
|
|
62
|
+
.prose table {
|
|
63
|
+
font-size: 10pt !important;
|
|
64
|
+
border-collapse: collapse !important;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.prose table th {
|
|
68
|
+
background-color: #f0f0f0 !important;
|
|
69
|
+
font-weight: bold !important;
|
|
70
|
+
border: 1px solid #333 !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.prose table td {
|
|
74
|
+
border: 1px solid #333 !important;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Sidebar adjustments for formal documents */
|
|
78
|
+
.chapter-navigation {
|
|
79
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Visual element spacing for legal documents - tighter than default */
|
|
83
|
+
:root {
|
|
84
|
+
--visual-spacing-top: 12pt;
|
|
85
|
+
--visual-spacing-bottom: 12pt;
|
|
86
|
+
--visual-spacing-print-top: 10pt;
|
|
87
|
+
--visual-spacing-print-bottom: 10pt;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Figure and image styling for legal documents */
|
|
91
|
+
figure {
|
|
92
|
+
margin-top: 12pt;
|
|
93
|
+
margin-bottom: 12pt;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
figcaption {
|
|
97
|
+
font-size: 10pt !important;
|
|
98
|
+
font-style: italic;
|
|
99
|
+
text-align: center;
|
|
100
|
+
margin-top: 6pt;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* SVG and diagram styling */
|
|
104
|
+
.svg-container,
|
|
105
|
+
.mermaid {
|
|
106
|
+
margin-top: 12pt;
|
|
107
|
+
margin-bottom: 12pt;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Images in legal documents */
|
|
111
|
+
img {
|
|
112
|
+
margin-top: 12pt;
|
|
113
|
+
margin-bottom: 12pt;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
figure img {
|
|
117
|
+
margin-top: 0;
|
|
118
|
+
margin-bottom: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Print-optimized styling */
|
|
122
|
+
@media print {
|
|
123
|
+
body {
|
|
124
|
+
font-size: 12pt !important;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.chapter-navigation, .mobile-chapter-nav {
|
|
128
|
+
display: none !important;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.chapter-content {
|
|
132
|
+
padding-left: 0 !important;
|
|
133
|
+
}
|
|
134
|
+
}
|
package/static/view.hbs
CHANGED
|
@@ -317,6 +317,8 @@
|
|
|
317
317
|
if (code) {
|
|
318
318
|
const mermaidDiv = document.createElement('div');
|
|
319
319
|
mermaidDiv.className = 'mermaid';
|
|
320
|
+
mermaidDiv.setAttribute('aria-hidden', 'true');
|
|
321
|
+
mermaidDiv.setAttribute('role', 'presentation');
|
|
320
322
|
mermaidDiv.textContent = code.textContent;
|
|
321
323
|
pre.parentNode.replaceChild(mermaidDiv, pre);
|
|
322
324
|
}
|