From f8f656fcd020cd847e21eb966640e62cc4f735fe Mon Sep 17 00:00:00 2001 From: p11 Date: Sat, 31 May 2025 15:45:06 +0200 Subject: [PATCH] Moved tabs to separate module --- src/main.rs | 231 +------------------------------------------------- src/tabs.rs | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 228 deletions(-) create mode 100644 src/tabs.rs diff --git a/src/main.rs b/src/main.rs index bb5844c..803c627 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,20 +20,19 @@ use data_stream::{ from_stream, to_stream, }; use header_config::parse_config; -use indexmap::IndexMap; use maud::html; use percent_encoding::percent_decode_str; -use pukram2html::{Settings, convert, convert_extended, convert_subheader}; +use pukram2html::convert; use threadpool::ThreadPool; mod chara; mod dialog; mod request; +mod tabs; mod vn; -use chara::render_character; use request::Request; -use vn::render_novel; +use tabs::{Tab, TabInfo, write_tab_styles}; #[derive(Clone)] struct Comment { @@ -593,230 +592,6 @@ impl<'a> RequestData<'a> { } } -static GENERAL_TAB_STYLE: &str = r" -.tab-system { - margin: 20px; -} - -.tab-radio { - display: none; -} - -.tab-nav { - display: flex; - gap: 5px; - margin-bottom: -1px; -} - -.tab-button { - padding: 8px 15px; - background: #f0f0f0; - border: 1px solid #ddd; - border-bottom: 1px solid transparent; - cursor: pointer; - border-radius: 4px 4px 0 0; - position: relative; -} - -.tab-button:hover { - background: #e0e0e0; -} - -.tab-radio:checked + .tab-button { - background: white; - border-color: #ddd; - border-bottom-color: white; - z-index: 1; -} - -.tab-content { - display: none; - padding: 15px; - border: 1px solid #ddd; -}"; - -fn write_tab_styles(stream: &mut TcpStream, count: usize) { - let _ = writeln!(stream, ""); -} - -fn render_comments(stream: &mut TcpStream, comments: Vec) { - let html = html! { - h2 { "Comments" } - form method="POST" { - input type="text" name="name" value="anon" placeholder="Name"; - br; - textarea rows="5" cols="60" name="text" placeholder="Enter comment..." {} - br; - input type="submit" value="Send!"; - } - form method="POST" { - input type="submit" value="💖️" name="up"; - input type="submit" value="💔️" name="down"; - } - @for comment in comments { - fieldset { - legend { (comment.name) } - (maud::PreEscaped(comment.text)) - } - } - }; - let _ = stream.write_all(html.into_string().as_bytes()); -} - -enum TabInfo { - Lines(Vec), - Chara(Vec), - Game(IndexMap, Box>), - Description, - Comment(Vec), -} - -impl TabInfo { - fn render_tab_content( - self, - stream: &mut TcpStream, - path: &Path, - relative_path: &str, - censored: bool, - choice: usize, - progress: &str, - mlc_path: Option<&Path>, - file_paths: &DocumentPaths, - ) { - match self { - Self::Lines(lines) => { - convert_extended( - lines, - stream, - Settings::default() - .with_handler(entry_handler(path, relative_path, censored)) - .with_start_level(1) - .with_use_textboxes(true), - ); - } - Self::Chara(lines) => { - convert_extended( - lines, - stream, - Settings::default() - .with_handler(chara_handler(path, relative_path)) - .with_start_level(1) - .with_use_textboxes(true), - ); - } - Self::Game(config_map) => { - let _ = render_novel( - config_map, - file_paths.pk, - mlc_path, - file_paths.mld, - relative_path, - stream, - choice, - progress, - ); - } - Self::Description => { - let Ok(pki_file) = File::open(file_paths.pki.unwrap()) else { - return; - }; - - let _ = writeln!(stream, "

Description

"); - - if let Some(audio_path) = &file_paths.audio { - if audio_path.is_file() { - let _ = writeln!( - stream, - "

" - ); - } - } - - let lines = BufReader::new(pki_file).lines().map_while(Result::ok); - convert_subheader(lines, stream, 1); - } - Self::Comment(comments) => { - render_comments(stream, comments); - } - } - } -} - -struct Tab { - title: Box, - info: TabInfo, -} - -fn entry_handler( - path: &Path, - relative_path: &str, - censored: bool, -) -> impl Fn(&str, &mut W, usize) { - move |mut entry, output, level| { - let level = level + 1; - let mut pki_path = path.to_path_buf(); - let mut audio_path = path.to_path_buf(); - if let Some((real_entry, _)) = entry.split_once(':') { - entry = real_entry - } - let pki_extension = if censored { "pkc" } else { "pki" }; - if relative_path.is_empty() { - pki_path.push(format!("{entry}.{pki_extension}")); - audio_path.push(format!("{entry}.mp3")); - } else { - pki_path.push(format!("{relative_path}/{entry}.{pki_extension}")); - audio_path.push(format!("{relative_path}/{entry}.mp3")); - } - - let Ok(file) = File::open(pki_path) else { - return; - }; - - let _ = writeln!( - output, - "{entry}" - ); - - if Path::is_file(&audio_path) { - let _ = writeln!( - output, - "

" - ); - } - - convert_subheader( - BufReader::new(file).lines().map(Result::unwrap_or_default), - output, - level, - ); - } -} - -fn chara_handler(path: &Path, relative_path: &str) -> impl Fn(&str, &mut W, usize) { - move |entry, output, _level| { - let mut chara_path = path.to_path_buf(); - chara_path.push(relative_path); - chara_path.push(format!("{entry}.chara")); - - let Some(def) = load_character_file(&chara_path) else { - return; - }; - - let html = render_character(entry, &def, relative_path); - let _ = output.write_all(html.into_string().as_bytes()); - } -} - fn handle_relative_connection( info: Arc, mut stream: TcpStream, diff --git a/src/tabs.rs b/src/tabs.rs new file mode 100644 index 0000000..467b150 --- /dev/null +++ b/src/tabs.rs @@ -0,0 +1,238 @@ +use std::{ + fs::File, + io::{BufRead, BufReader, Write}, + net::TcpStream, + path::Path, +}; + +use indexmap::IndexMap; +use maud::html; +use pukram2html::{Settings, convert_extended, convert_subheader}; + +use crate::{ + Comment, DocumentPaths, chara::render_character, load_character_file, vn::render_novel, +}; + +static GENERAL_TAB_STYLE: &str = r" +.tab-system { + margin: 20px; +} + +.tab-radio { + display: none; +} + +.tab-nav { + display: flex; + gap: 5px; + margin-bottom: -1px; +} + +.tab-button { + padding: 8px 15px; + background: #f0f0f0; + border: 1px solid #ddd; + border-bottom: 1px solid transparent; + cursor: pointer; + border-radius: 4px 4px 0 0; + position: relative; +} + +.tab-button:hover { + background: #e0e0e0; +} + +.tab-radio:checked + .tab-button { + background: white; + border-color: #ddd; + border-bottom-color: white; + z-index: 1; +} + +.tab-content { + display: none; + padding: 15px; + border: 1px solid #ddd; +}"; + +pub fn write_tab_styles(stream: &mut TcpStream, count: usize) { + let _ = writeln!(stream, ""); +} + +pub enum TabInfo { + Lines(Vec), + Chara(Vec), + Game(IndexMap, Box>), + Description, + Comment(Vec), +} + +impl TabInfo { + pub fn render_tab_content( + self, + stream: &mut TcpStream, + path: &Path, + relative_path: &str, + censored: bool, + choice: usize, + progress: &str, + mlc_path: Option<&Path>, + file_paths: &DocumentPaths, + ) { + match self { + Self::Lines(lines) => { + convert_extended( + lines, + stream, + Settings::default() + .with_handler(entry_handler(path, relative_path, censored)) + .with_start_level(1) + .with_use_textboxes(true), + ); + } + Self::Chara(lines) => { + convert_extended( + lines, + stream, + Settings::default() + .with_handler(chara_handler(path, relative_path)) + .with_start_level(1) + .with_use_textboxes(true), + ); + } + Self::Game(config_map) => { + let _ = render_novel( + config_map, + file_paths.pk, + mlc_path, + file_paths.mld, + relative_path, + stream, + choice, + progress, + ); + } + Self::Description => { + let Ok(pki_file) = File::open(file_paths.pki.unwrap()) else { + return; + }; + + let _ = writeln!(stream, "

Description

"); + + if let Some(audio_path) = &file_paths.audio { + if audio_path.is_file() { + let _ = writeln!( + stream, + "

" + ); + } + } + + let lines = BufReader::new(pki_file).lines().map_while(Result::ok); + convert_subheader(lines, stream, 1); + } + Self::Comment(comments) => { + render_comments(stream, comments); + } + } + } +} + +fn render_comments(stream: &mut TcpStream, comments: Vec) { + let html = html! { + h2 { "Comments" } + form method="POST" { + input type="text" name="name" value="anon" placeholder="Name"; + br; + textarea rows="5" cols="60" name="text" placeholder="Enter comment..." {} + br; + input type="submit" value="Send!"; + } + form method="POST" { + input type="submit" value="💖️" name="up"; + input type="submit" value="💔️" name="down"; + } + @for comment in comments { + fieldset { + legend { (comment.name) } + (maud::PreEscaped(comment.text)) + } + } + }; + let _ = stream.write_all(html.into_string().as_bytes()); +} + +pub struct Tab { + pub title: Box, + pub info: TabInfo, +} + +fn entry_handler( + path: &Path, + relative_path: &str, + censored: bool, +) -> impl Fn(&str, &mut W, usize) { + move |mut entry, output, level| { + let level = level + 1; + let mut pki_path = path.to_path_buf(); + let mut audio_path = path.to_path_buf(); + if let Some((real_entry, _)) = entry.split_once(':') { + entry = real_entry + } + let pki_extension = if censored { "pkc" } else { "pki" }; + if relative_path.is_empty() { + pki_path.push(format!("{entry}.{pki_extension}")); + audio_path.push(format!("{entry}.mp3")); + } else { + pki_path.push(format!("{relative_path}/{entry}.{pki_extension}")); + audio_path.push(format!("{relative_path}/{entry}.mp3")); + } + + let Ok(file) = File::open(pki_path) else { + return; + }; + + let _ = writeln!( + output, + "{entry}" + ); + + if Path::is_file(&audio_path) { + let _ = writeln!( + output, + "

" + ); + } + + convert_subheader( + BufReader::new(file).lines().map(Result::unwrap_or_default), + output, + level, + ); + } +} + +fn chara_handler(path: &Path, relative_path: &str) -> impl Fn(&str, &mut W, usize) { + move |entry, output, _level| { + let mut chara_path = path.to_path_buf(); + chara_path.push(relative_path); + chara_path.push(format!("{entry}.chara")); + + let Some(def) = load_character_file(&chara_path) else { + return; + }; + + let html = render_character(entry, &def, relative_path); + let _ = output.write_all(html.into_string().as_bytes()); + } +}