--- /dev/null
+/*
+ Processes existing <RT-TOC> tags.
+ Populates each with headings found below it that are exactly one level deeper.
+ Stops scanning if a heading of the same or higher level is encountered.
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.RT_TOC = function() {
+ const debug = window.StyleRT.debug;
+ const toc_tags = document.querySelectorAll('rt-toc');
+
+ toc_tags.forEach((container, toc_index) => {
+ container.style.display = 'block';
+
+ // 1. Determine the context level of this TOC
+ // We look backward to find the most recent heading (H1-H6)
+ let context_level = 0; // Default to 0 (looking for H1s)
+ let prev = container.previousElementSibling;
+
+ while (prev) {
+ const match = prev.tagName.match(/^H([1-6])$/);
+ if (match) {
+ context_level = parseInt(match[1]);
+ break;
+ }
+ prev = prev.previousElementSibling;
+ }
+
+ const target_level = context_level + 1;
+ const stop_at_or_above = context_level;
+
+ if (debug) debug.log('RT_TOC', `TOC #${toc_index} context: H${context_level}. Targeting: H${target_level}`);
+
+ // 2. Setup Internal Structure
+ container.innerHTML = ''; // Clear any placeholder content
+ const title = document.createElement('h1');
+ title.textContent = context_level === 0 ? 'Table of Contents' : 'Section Contents';
+ title.style.textAlign = 'center';
+ container.appendChild(title);
+
+ const list = document.createElement('ul');
+ list.style.listStyle = 'none';
+ list.style.paddingLeft = '0';
+ container.appendChild(list);
+
+ // 3. Scan Forward for headings
+ let next_el = container.nextElementSibling;
+ while (next_el) {
+ const match = next_el.tagName.match(/^H([1-6])$/);
+ if (match) {
+ const found_level = parseInt(match[1]);
+
+ // STOP condition: We hit a heading at our level or higher
+ // (e.g., if we are under an H1 looking for H2s, we stop at the next H1)
+ if (context_level !== 0 && found_level <= stop_at_or_above) {
+ break;
+ }
+
+ // COLLECT condition: Heading is exactly one level deeper
+ if (found_level === target_level) {
+ if (!next_el.id) next_el.id = `toc-ref-${toc_index}-${found_level}-${list.children.length}`;
+
+ const li = document.createElement('li');
+ li.style.marginBottom = '0.5rem';
+
+ const a = document.createElement('a');
+ a.href = `#${next_el.id}`;
+ a.textContent = next_el.textContent;
+ a.style.textDecoration = 'none';
+ a.style.color = 'inherit';
+ a.style.display = 'block';
+
+ // Hover effects
+ a.onmouseover = () => a.style.color = 'hsl(42, 100%, 50%)';
+ a.onmouseout = () => a.style.color = 'inherit';
+
+ li.appendChild(a);
+ list.appendChild(li);
+ }
+ }
+ next_el = next_el.nextElementSibling;
+ }
+ });
+};
/*
- Sets basic document theme colors.
- No layout enforcement (leaves flow to default HTML block behavior).
+ Sets basic document theme colors and dimensions.
+ Sets width immediately so layout-based pagination is accurate.
*/
window.StyleRT = window.StyleRT || {};
const body = document.body;
- // Basic Theme Colors (Required for RT_code physics)
- body.style.backgroundColor = theme.background || '#000';
- body.style.color = theme.foreground || '#ddd';
+ // 1. Basic Theme Colors
+ body.style.backgroundColor = theme.background || 'hsl(0, 0%, 0%)';
+ body.style.color = theme.foreground || 'hsl(42, 100%, 80%)';
body.style.fontFamily = '"Noto Sans JP", sans-serif';
- // Reset margins to prevent browser defaults from interfering with your page.js
+ // 2. Global Flow Reset
+ body.style.display = 'block';
body.style.margin = '0';
body.style.padding = '0';
+
+ // 3. Dimensions
+ // We apply the width to the body now so that getBoundingClientRect()
+ // in the paginator reflects the final text wrapping.
+ body.style.maxWidth = '50rem';
+ body.style.margin = '0 auto'; // Center the content area
+
+ // We store the target page height on the RT object for the paginator to find.
+ // This avoids assigning a height to the body itself (which would clip content).
+ RT.page_height = 1056;
};
/*
Master Loader & Orchestrator for StyleRT.
-
- PIPELINE DEPENDENCY CHAIN:
- 1. PHYSICS (Utility, Theme) -> Required by everything.
- 2. GLOBAL (Article) -> Sets background for contrast checks.
- 3. SEMANTICS (Code, Math) -> Expands text size; must run before pagination.
- 4. STRUCTURE (H1, TOC) -> Creates .page containers.
- 5. STYLING (Page) -> Applies borders/margins to .page containers.
- 6. REVEAL -> Shows the result.
+ Loads utility.js first to ensure infrastructure (RT.debug) exists.
*/
window.StyleRT = window.StyleRT || {};
window.StyleRT.do_style = function() {
+ const RT = window.StyleRT;
- // 1. Manifest
const modules = [
- 'style/utility.js',
'style/theme_RT.js',
'style/RT_term.js',
'style/RT_math.js',
'style/RT_code.js',
'style/article_generic.js',
- 'style/page_each_H1.js',
- 'style/toc.js',
- 'style/page.js',
+ 'style/RT_TOC.js',
+ 'style/paginate_by_element.js',
+ // 'style/page.js',
+ 'style/page_css.js',
'style/body_visibility_visible.js'
];
- // 2. Loader
+ // 1. Bootloader: Get the utility/logger in place first
+ const utility = document.createElement('script');
+ utility.src = 'style/utility.js';
+
+ utility.onload = () => {
+ // Infrastructure ready; begin module sequence
+ load_next(0);
+ };
+
+ utility.onerror = () => {
+ console.error("StyleRT: Critical failure - utility.js missing.");
+ };
+
+ document.head.appendChild(utility);
+
+ // 2. The Chain Loader
const load_next = (index) => {
if (index >= modules.length) {
- run_pipeline();
+ run_style();
return;
}
+
const src = modules[index];
+
+ // Accessing the property live so it doesn't matter if it was set late
+ if (RT.debug) RT.debug.log('style', `Loading: ${src}`);
+
const script = document.createElement('script');
script.src = src;
script.onload = () => load_next(index + 1);
- script.onerror = () => { console.error(`StyleRT: Failed ${src}`); load_next(index + 1); };
+ script.onerror = () => {
+ console.error(`StyleRT: Failed load on ${src}`);
+ load_next(index + 1);
+ };
document.head.appendChild(script);
};
- // 3. Execution Pipeline
- const run_pipeline = () => {
- const RT = window.StyleRT;
- const debug = RT.debug;
+ // 3. Phase 1: Semantics
+ const run_style = () => {
+ RT.debug.log('style', 'Starting Phase 1: Setup & Semantics');
- debug.log('pipeline', 'Starting execution...');
-
- // PHASE 1: GLOBAL SETUP
- if(RT.article_generic) {
- debug.log('pipeline', 'Phase 1: Global Setup (article_generic)');
- RT.article_generic();
- }
-
- // PHASE 2: SEMANTICS (In-place modification)
- debug.log('pipeline', 'Phase 2: Semantics (Term, Math, Code)');
+ if(RT.article_generic) RT.article_generic();
if(RT.RT_term) RT.RT_term();
if(RT.RT_math) RT.RT_math();
if(RT.RT_code) RT.RT_code();
- // PHASE 3: STRUCTURE (DOM Surgery)
- debug.log('pipeline', 'Phase 3: Structure (Pagination & TOC)');
-
- // A. Content Pagination (Breaks body into pages)
- if(RT.page_each_H1) RT.page_each_H1();
-
- // B. TOC Generation (Creates the TOC Page)
- // Must run AFTER H1s are processed (or scan them), but definitely creates a .page
- if(RT.toc) RT.toc();
-
- // PHASE 4: STYLING (The Frame)
- // Must run LAST, after all .page elements (Content + TOC) exist.
- if(RT.page) {
- debug.log('pipeline', 'Phase 4: Styling (Applying Page Borders)');
- RT.page();
+ // Hand off to MathJax task queue
+ if (window.MathJax && MathJax.Hub && MathJax.Hub.Queue) {
+ RT.debug.log('style', 'MathJax detected. Queueing layout tasks...');
+ MathJax.Hub.Queue(["Typeset", MathJax.Hub], continue_style);
+ } else {
+ continue_style();
}
+ };
- // PHASE 5: REVEAL
- debug.log('pipeline', 'Phase 5: Reveal');
+ // 4. Phase 2: Layout
+ const continue_style = () => {
+ RT.debug.log('style', 'Starting Phase 2: Layout & Reveal');
+
+ if(RT.RT_TOC) RT.RT_TOC();
+ if(RT.paginate_by_element) RT.paginate_by_element();
+ if(RT.page) RT.page();
if(RT.body_visibility_visible) RT.body_visibility_visible();
- debug.log('pipeline', 'Execution complete.');
+ RT.debug.log('style', 'Style execution complete.');
};
-
- load_next(0);
};
/*
- Defines the appearance of a "Page" container.
- Restores the Original "Gold Glow" Scheme.
+ Defines the appearance of the <RT-PAGE> container via a CSS block.
+ Uses high-contrast offsets to ensure the drop shadow is visible.
*/
window.StyleRT = window.StyleRT || {};
window.StyleRT.page = function() {
const RT = window.StyleRT;
+ const style_id = 'rt-page-styles';
- // Fetch Theme
- const theme = RT.active_theme ? RT.active_theme() : {};
- // Use the bright accent for the glow
- const glowColor = theme.accent || 'gold';
+ if (!document.getElementById(style_id)) {
+ const style_el = document.createElement('style');
+ style_el.id = style_id;
+ style_el.textContent = `
+ html, body {
+ background-color: #1a1a1a !important;
+ margin: 0;
+ padding: 0;
+ }
- document.querySelectorAll('.page').forEach(el => {
- // A. Dimensions (The "Web" Look)
- el.style.width = '1200px';
- el.style.maxWidth = '95vw'; // Responsive safety
- el.style.height = 'auto'; // Hug content
- el.style.minHeight = '200px'; // Minimum sanity check
- el.style.boxSizing = 'border-box';
-
- // B. The "Original" Visuals
- // 1. Background: Likely darker/transparent to let the theme breathe
- el.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
-
- // 2. Border: Thin accent line
- el.style.border = `1px solid ${glowColor}`;
-
- // 3. Shadow: The "Gold Drop Shadow" you missed
- // Format: offset-x | offset-y | blur-radius | color
- el.style.boxShadow = `0 0 15px ${glowColor}`;
-
- el.style.margin = '0 auto';
-
- // C. Typography Base
- el.style.padding = '2rem 4rem'; // Standard comfortable web reading padding
- el.style.lineHeight = '1.6';
- });
+ rt-page {
+ display: block;
+ max-width: 50rem;
+ width: 100%;
+
+ /* Increased vertical margin to prevent shadow clipping */
+ margin: 4rem auto 6rem auto;
+ padding: 3rem;
+ box-sizing: border-box;
+ background-color: hsl(0, 0%, 0%);
+ border: 1px solid hsl(42, 100%, 50%);
+
+ /* 1. The Offset Drop Shadow (Bottom-Right)
+ 2. The Ambient Glow (Centered)
+ */
+ box-shadow: 15px 15px 30px rgba(0, 0, 0, 0.9),
+ 0 0 15px hsl(42, 100%, 15%);
+
+ height: auto;
+
+ /* Ensure the shadow isn't cut off by the container's edges */
+ overflow: visible;
+ }
+ `;
+ document.head.appendChild(style_el);
+ }
+
+ if (RT.debug) RT.debug.log('style', 'CSS block updated with 15px shadow offset.');
};
--- /dev/null
+/*
+ Defines the appearance of the <RT-PAGE> container.
+ Uses the high-performance 'filter: drop-shadow' discovered in testing.
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.page = function() {
+ const RT = window.StyleRT;
+ const style_id = 'rt-page-styles';
+
+ if (!document.getElementById(style_id)) {
+ const style_el = document.createElement('style');
+ style_el.id = style_id;
+ style_el.textContent = `
+ rt-page {
+ display: block;
+ max-width: 50rem;
+ width: 100%;
+ margin: 4rem auto 6rem auto;
+ padding: 3rem;
+ box-sizing: border-box;
+ background-color: hsl(0, 0%, 0%);
+ border: 1px solid hsl(42, 100%, 50%);
+
+ /* Using the discovered Gold Leaf HSL */
+ filter: drop-shadow(8px 12px 40px hsl(40, 96%, 47%));
+
+ height: auto;
+ }
+ `;
+ document.head.appendChild(style_el);
+ }
+
+ if (RT.debug) RT.debug.log('style', 'CSS block updated with Gold Leaf drop-shadow filter.');
+};
+++ /dev/null
-/*
- Wraps child elements into pages based on H1 headers.
-*/
-function page_each_H1(){
- const body = document.body;
- const elements = Array.from(body.children);
- const pages = [];
- let current_page_elements = [];
-
- elements.forEach(el => {
- if ( el.tagName === 'SCRIPT' || el.tagName === 'STYLE' ){
- return;
- }
-
- if (el.tagName === 'H1'){
- if (current_page_elements.length > 0){
- pages.push(current_page_elements);
- }
- current_page_elements = [el];
- } else {
- current_page_elements.push(el);
- }
- });
-
- if (current_page_elements.length > 0){
- pages.push(current_page_elements);
- }
-
- const scripts = Array.from(document.querySelectorAll('script'));
- body.innerHTML = '';
-
- pages.forEach(element_list => {
- const page_div = document.createElement('div');
- page_div.className = 'page';
- element_list.forEach(el => page_div.appendChild(el));
- body.appendChild(page_div);
- });
-
- scripts.forEach(s => body.appendChild(s));
-}
-
-window.StyleRT = window.StyleRT || {};
-window.StyleRT.page_each_H1 = page_each_H1;
--- /dev/null
+/*
+ Layout Paginator: paginate_by_element
+ Measures heights and groups elements.
+ Logic: Headings must stay with the element immediately following them.
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.paginate_by_element = function() {
+ const RT = window.StyleRT;
+ const body = document.body;
+ const limit = RT.page_height || 1000;
+
+ const elements = Array.from(body.children).filter(el =>
+ el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' && el.tagName !== 'RT-PAGE'
+ );
+
+ const pages = [];
+ let current_batch = [];
+ let current_h = 0;
+
+ const get_el_height = (el) => {
+ const rect = el.getBoundingClientRect();
+ const style = window.getComputedStyle(el);
+ const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+ return rect.height + margin;
+ };
+
+ for (let i = 0; i < elements.length; i++) {
+ const el = elements[i];
+ const h = get_el_height(el);
+ const is_heading = /H[1-6]/.test(el.tagName);
+
+ // Lookahead: If this is a heading, check the next element too
+ let total_required_h = h;
+ if (is_heading && i + 1 < elements.length) {
+ total_required_h += get_el_height(elements[i + 1]);
+ }
+
+ // If the element (or heading + next) exceeds limit, start new page
+ if (current_h + total_required_h > limit && current_batch.length > 0) {
+ pages.push(current_batch);
+ current_batch = [];
+ current_h = 0;
+ }
+
+ current_batch.push(el);
+ current_h += h;
+ }
+
+ if (current_batch.length > 0) pages.push(current_batch);
+
+ // Rebuild DOM
+ const assets = Array.from(document.querySelectorAll('script, style'));
+ body.innerHTML = '';
+ pages.forEach(list => {
+ const page_el = document.createElement('rt-page');
+ list.forEach(item => page_el.appendChild(item));
+ body.appendChild(page_el);
+ });
+ assets.forEach(a => body.appendChild(a));
+
+ if (RT.debug) RT.debug.log('layout', `Pagination complete: ${pages.length} pages.`);
+};
/*
- Provides the color palette for the RT theme.
+ Provides the color palette and layout layout for the RT theme.
Registers itself as the active system theme upon load.
*/
function theme_RT(){
foreground: 'hsl(42, 100%, 80%)',
accent: 'hsl(42, 100%, 50%)',
faded: 'hsl(42, 100%, 20%)',
- highlight: 'hsl(42, 100%, 90%)'
+ highlight: 'hsl(42, 100%, 90%)',
};
}
+++ /dev/null
-/*
- Generates a Table of Contents.
- Inserts it at the very top of the document body.
-*/
-window.StyleRT = window.StyleRT || {};
-
-window.StyleRT.toc = function() {
- const RT = window.StyleRT;
- // Use 'pipeline' token if available, otherwise silent
- const debug = RT.debug ? RT.debug.log.bind(RT.debug) : () => {};
-
- debug('pipeline', 'Generating TOC...');
-
- // 1. Create Container (reusing 'page' class so it picks up your gold style)
- const container = document.createElement('div');
- container.className = 'page';
- container.id = 'rt-toc';
-
- // 2. Title
- const title = document.createElement('h1');
- title.textContent = 'Table of Contents';
- title.style.textAlign = 'center';
- container.appendChild(title);
-
- // 3. Build List
- const list = document.createElement('ul');
- document.querySelectorAll('h1').forEach((header, i) => {
- if (header === title) return;
- if (!header.id) header.id = `section-${i}`;
-
- const li = document.createElement('li');
- const a = document.createElement('a');
- a.href = `#${header.id}`;
- a.textContent = header.textContent;
- a.style.textDecoration = 'none';
- a.style.color = 'inherit';
-
- li.appendChild(a);
- list.appendChild(li);
- });
-
- container.appendChild(list);
-
- // 4. Insert at Top (Prepend)
- document.body.insertBefore(container, document.body.firstChild);
-};
// --- DEBUG SYSTEM ---
window.StyleRT.debug = {
- // Add tokens here to enable specific logs: 'RT_code', 'physics', 'pipeline', 'layout'
- active_tokens: new Set(['pipeline', 'layout']),
+ // Add tokens here to enable specific logs: 'RT_code', 'layout', 'style', 'layout'
+ active_tokens: new Set(['style', 'layout']),
log: function(token, message) {
if (this.active_tokens.has(token)) {
// --- FONT PHYSICS ---
measure_ink_ratio: function(target_font, ref_font = null) {
const debug = window.StyleRT.debug;
- debug.log('physics', `Measuring ink ratio for ${target_font}`);
+ debug.log('layout', `Measuring ink ratio for ${target_font}`);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const target_m = get_metrics(target_font);
const ratio = ref_m.ascent / target_m.ascent;
- debug.log('physics', `Ink Ratio calculated: ${ratio.toFixed(3)}`);
+ debug.log('layout', `Ink Ratio calculated: ${ratio.toFixed(3)}`);
return {
ratio: ratio,
if (numbers && numbers.length >= 3) {
const lightness = parseInt(numbers[2]);
const is_light = lightness > 50;
- debug.log('color_physics', `HSL ${color_string} -> Lightness ${lightness}% -> ${is_light ? 'LIGHT' : 'DARK'}`);
+ debug.log('color_layout', `HSL ${color_string} -> Lightness ${lightness}% -> ${is_light ? 'LIGHT' : 'DARK'}`);
return is_light;
}
}
// 2. RGB Check
const rgb = color_string.match(/\d+/g);
if (!rgb) {
- debug.warn('color_physics', `Failed to parse color: "${color_string}". Defaulting to Light.`);
+ debug.warn('color_layout', `Failed to parse color: "${color_string}". Defaulting to Light.`);
return true;
}
const luma = (r * 299 + g * 587 + b * 114) / 1000;
const is_light = luma > 128;
- debug.log('color_physics', `RGB (${r},${g},${b}) -> Luma ${luma.toFixed(1)} -> ${is_light ? 'LIGHT' : 'DARK'}`);
+ debug.log('color_layout', `RGB (${r},${g},${b}) -> Luma ${luma.toFixed(1)} -> ${is_light ? 'LIGHT' : 'DARK'}`);
return is_light;
},