From 1ad2fcd9cb0cc2ec23a20e55d7e7a377a786bf60 Mon Sep 17 00:00:00 2001 From: p11 Date: Sun, 20 Apr 2025 23:17:17 +0200 Subject: [PATCH] Added choices at end of scene --- src/vn.rs | 144 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 112 insertions(+), 32 deletions(-) diff --git a/src/vn.rs b/src/vn.rs index 396e447..b7e2235 100644 --- a/src/vn.rs +++ b/src/vn.rs @@ -26,18 +26,24 @@ fn render_scene(settings: &PlayerSettings, name: &str) -> Markup { } } -fn navigation_controls(total_sections: usize) -> Markup { +fn navigation_controls(total_scenes: usize) -> Markup { html! { div class="nav-controls" { button class="nav-button" onclick="prev()" { "←" } - span id="section-counter" { "1/" (total_sections) } + span id="section-counter" { "1/" (total_scenes) } button class="nav-button" onclick="next()" { "→" } } } } -fn generate_html(scenes: Vec, sections: Vec) -> Markup { - let total_sections = sections.len(); +fn generate_html(mut scenes: Vec, sections: Vec, choices: Markup) -> Markup { + scenes.push(html! { + div class="choices-section" { + (choices) + } + }); + + let total_scenes = scenes.len(); html! { div id="story-container" { @@ -65,9 +71,9 @@ fn generate_html(scenes: Vec, sections: Vec) -> Markup { } } - (navigation_controls(total_sections)) + (navigation_controls(total_scenes)) (global_styles()) - (interactive_script(total_sections)) + (interactive_script(total_scenes)) } } } @@ -229,36 +235,109 @@ fn global_styles() -> Markup { height: 20px; opacity: 0.5; } + + .choices-section { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 3; + background: rgba(0, 0, 0, 0.85); + padding: 2rem; + overflow-y: auto; + display: flex; + flex-direction: column; + align-items: center; + } + + .choice-box:hover { + transform: translateX(-50%) translateY(-0.5vh); + box-shadow: 0 0.6vw 0.8vw rgba(0, 0, 0, 0.15); + } + + .choices-section input[type='submit'] { + width: 100%; + padding: 1rem; + border: none; + background: none; + cursor: pointer; + font-size: 1.1rem; + text-align: left; + } + + .choice-box { + width: 90%; + min-width: 85%; + border: 0.2vw solid #3a3a3a; + border-radius: 1vw; + padding: 2vw; + margin: 1vh auto; + background: rgba(255, 255, 255, 0.9); + box-shadow: 0 0.4vw 0.6vw rgba(0, 0, 0, 0.1); + position: relative; + transform: translateX(-50%); + left: 50%; + } + + .choice-button { + width: 100%; + background: none; + border: none; + padding: 1.5vh 2vw; + font-size: 1.6vw; + line-height: 1.4; + cursor: pointer; + color: #333; + text-align: left; + font-family: inherit; + } + + @media (max-width: 768px) { + .choices-section { + padding: 1rem; + } + + .choice-box { + width: 95%; + padding: 3vw; + } + + .choice-button { + font-size: 1.2rem; + padding: 1rem; + } + } ")) } } } -fn interactive_script(total_sections: usize) -> Markup { +fn interactive_script(total_scenes: usize) -> Markup { html! { script { (maud::PreEscaped(format!(r" - let currentSection = 0; - const totalSections = {total_sections}; + let currentScene = 0; + const totalScenes = {total_scenes}; function updateSection() {{ document.querySelectorAll('.story-section').forEach((el, index) => {{ - el.style.display = index === currentSection ? 'block' : 'none'; + el.style.display = index === currentScene ? 'block' : 'none'; }}); document.querySelectorAll('.scene-section').forEach((el, index) => {{ - el.style.display = index === currentSection ? 'block' : 'none'; + el.style.display = index === currentScene ? 'block' : 'none'; }}); document.getElementById('section-counter').textContent = - `${{currentSection + 1}}/${{totalSections}}`; + `${{currentScene + 1}}/${{totalScenes}}`; }} function prev() {{ - if (currentSection > 0) currentSection--; + if (currentScene > 0) currentScene--; updateSection(); }} function next() {{ - if (currentSection < totalSections - 1) currentSection++; + if (currentScene < totalScenes - 1) currentScene++; updateSection(); }} @@ -300,30 +379,31 @@ pub fn render_novel( let dialogs = parse_map(pk_path, &mut settings_context)?; let (scenes, sections) = process_dialog(&dialogs[choice], &mut player_settings, start_level); - let html = generate_html(scenes, sections); - let _ = write!(stream, "{}", html.into_string()); + let mut choices_html = html! {}; if let Some(_named_multilinear_info) = named_multilinear_info { - for (i, dialog_sequence) in dialogs.iter().enumerate() { - if let Some(block) = dialog_sequence - .blocks - .iter() - .find(|block| !block.lines.is_empty()) - { - let line_text = &block.lines.first().unwrap().text; - - let html = html! { - form method="POST" { - input type="hidden" name="progress" value=(progress); - input type="hidden" name="choice" value=(i); - input type="submit" value=(line_text); + choices_html = html! { + div class="choices-section" { + @for (i, dialog_sequence) in dialogs.iter().enumerate() { + @if let Some(block) = dialog_sequence.blocks.first() { + div class="choice-box" { + form method="POST" { + input type="hidden" name="progress" value=(progress); + input type="hidden" name="choice" value=(i); + button type="submit" class="choice-button" { + (block.lines[0].text) + } + } + } } - }; - let _ = write!(stream, "{}", html.into_string()); + } } - } + }; } + let html = generate_html(scenes, sections, choices_html); + let _ = write!(stream, "{}", html.into_string()); + Ok(()) }