Fix story page scrolling and ellipsis spacing

This commit is contained in:
2026-05-15 07:35:27 +02:00
parent 74be77b267
commit b8fe8535aa
5 changed files with 60 additions and 21 deletions
+13 -4
View File
@@ -401,19 +401,26 @@ ol.choice {
padding: 0 3rem 1rem 1rem;
/* border: 1px dotted rgba(200,200,200,1); */
overflow: visible;
overflow-y: scroll;
overflow-y: auto;
opacity: 0.95;
mix-blend-mode: darken;
}
#story {
overflow-x: visible;
overflow-x: visible;
box-sizing: border-box;
overflow-anchor: none;
text-align: justify;
text-justify: inter-word;
margin-bottom: 1.2em;
margin-bottom: 0;
line-height: 1.5;
}
#paragraphs {
box-sizing: border-box;
overflow-anchor: none;
}
/* #story p span {
font-feature-settings: 'kern' on, 'liga' on, 'onum' on, 'clig' on, 'hlig' on;
} */
@@ -425,8 +432,10 @@ ol.choice {
#page_right {
/* background-color: rgba(200,200,200,0.5); */
right: 7%;
height: calc(28 * 1.45 * 1.2rem);
padding-bottom: 0;
scroll-behavior: smooth;
overscroll-behavior: contain;
overflow-anchor: none;
/* transform: translateX(-1%) translateY(2%) rotateX(0deg) rotateY(-1deg) rotateZ(0deg); */
}
+3 -3
View File
@@ -8,7 +8,7 @@ function kap(text, measureText, measure, hyphenation) {
let spaceWidth = measureText('\u00A0');
let nodes = [];
text.split(/([.,:;!?] |\s|\||<.*?>)/u).forEach(function (fragment) {
text.split(/([.,:;!?] |\s|\||<.*?>)/u).forEach(function (fragment) {
let fragmentWidth = measureText(fragment);
if (fragment === ' ') {
@@ -21,8 +21,8 @@ function kap(text, measureText, measure, hyphenation) {
nodes.push(linebreak.penalty(hyphenWidth * 0.25, 100, 1));
} else if (fragment.match(/(<.*?>)/u)) {
nodes.push(linebreak.tag(fragmentWidth, fragment));
} else if (fragment.match(/[.,:;!?] /u)) {
let punctuation = fragment.match(/([.,:;!?])( )/u);
} else if (fragment.match(/[.,:;!?] /u)) {
let punctuation = fragment.match(/([.,:;!?])( )/u);
let punctuationSymbolWidth = measureText(punctuation[1]) * 0.25;
let punctuationWidth = measureText(punctuation[1]) * 0.75 + spaceWidth;
nodes.push(linebreak.box(punctuationSymbolWidth, punctuation[1]));
+1 -1
View File
@@ -150,7 +150,7 @@ class LayoutRendererModule extends BaseModule {
if (node.type === 'box' && node.value !== '' && j < currentBreak.position) {
const followsGlue = j > 0 && nodes[j - 1].type === 'glue';
const isTrailingPunctuation = /^[,.;:!?)]$/.test(node.value) && !followsGlue;
const isTrailingPunctuation = /^[,.;:!?)]$/.test(node.value) && !followsGlue;
// Check if this box follows a penalty (hyphenation point)
if (lastChild && isTrailingPunctuation) {
+19 -5
View File
@@ -34,6 +34,7 @@ class UIDisplayHandlerModule extends BaseModule {
'displayText',
'renderSentence',
'handleDeferredMediaBlock',
'scrollStoryToEnd',
'rerenderStory',
'clear',
'scheduleRerender',
@@ -397,14 +398,11 @@ class UIDisplayHandlerModule extends BaseModule {
}
});
this.scrollStoryToEnd(true);
// Start coordinated playback (animation + TTS), including chapter headings.
await this.playbackCoordinator.play(sentence);
// Scroll to bottom
if (this.pageRight) {
this.pageRight.scrollTop = this.pageRight.scrollHeight;
}
// Call completion callback
if (sentence.onComplete) {
sentence.onComplete();
@@ -464,6 +462,19 @@ class UIDisplayHandlerModule extends BaseModule {
}
}
scrollStoryToEnd(smooth = true) {
if (!this.pageRight) {
return;
}
window.requestAnimationFrame(() => {
this.pageRight.scrollTo({
top: Math.max(0, this.pageRight.scrollHeight - this.pageRight.clientHeight),
behavior: smooth ? 'smooth' : 'auto'
});
});
}
async handleDeferredMediaBlock(sentence) {
document.dispatchEvent(new CustomEvent('story:media-block', {
detail: {
@@ -496,6 +507,9 @@ class UIDisplayHandlerModule extends BaseModule {
this.container.appendChild(this.paragraphContainer);
}
this.renderedItems = [];
if (this.pageRight) {
this.pageRight.scrollTop = 0;
}
}
/**