Compare commits

..

5 Commits
v0.5.3 ... main

Author SHA1 Message Date
5bb69bac34 fix: minifiing 2026-07-20 10:03:41 +03:00
a8e009b957 feat(links): open in new tab 2026-07-20 01:14:56 +03:00
348dc8819d fix: manifes 2026-07-17 15:20:02 +03:00
027b9517e1 feat: add minification 2026-07-17 15:12:00 +03:00
df4abd2ee6 feat(emoji): add emoji parsing + subscript/superscript 2026-07-17 00:04:40 +03:00
11 changed files with 2245 additions and 37 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
notes/ notes/
target/ target/
assets/ assets/
templates/*.min.html

View File

@ -6,6 +6,35 @@ Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/lang/en/). [Semantic Versioning](https://semver.org/lang/en/).
## `v0.6.3` - 20.07.2026
### Fixed
- Fixed minify script and templates.
---
## `v0.6.2` - 20.07.2026
### Changed
- Links are now opens in new tab.
---
## `v0.6.1` - 17.07.2026
### Added
- Add compile-time templates minificattion.
---
## `v0.6.0` - 17.07.2026
### Added
- Add text emoji support (`:smile:` for example).
---
## `v0.5.3` - 16.07.2026 ## `v0.5.3` - 16.07.2026
### Fixed ### Fixed
- Fixed contend width - Fixed contend width

1261
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mdpreview" name = "mdpreview"
version = "0.5.3" version = "0.6.3"
edition = "2024" edition = "2024"
authors = ["Vladislav Kan <thek4n@yandex.ru>"] authors = ["Vladislav Kan <thek4n@yandex.ru>"]
build = "build.rs" build = "build.rs"
@ -14,6 +14,7 @@ strip = true
[build-dependencies] [build-dependencies]
reqwest = { version = "0.11", features = ["blocking"] } reqwest = { version = "0.11", features = ["blocking"] }
minify-html = "0.18"
[dependencies] [dependencies]
pulldown-cmark = { version = "0.13.4", features = ["simd"] } pulldown-cmark = { version = "0.13.4", features = ["simd"] }

View File

@ -1,5 +1,7 @@
use minify_html::{Cfg, minify};
use std::env; use std::env;
use std::fs; use std::fs;
use std::io;
use std::path::Path; use std::path::Path;
const HIGHLIGHT_STYLE_URL_TEMPLATE: &str = const HIGHLIGHT_STYLE_URL_TEMPLATE: &str =
@ -14,6 +16,11 @@ fn main() {
println!("cargo:rerun-if-changed=assets/"); println!("cargo:rerun-if-changed=assets/");
println!("cargo:rerun-if-env-changed=FORCE_DEPS_DOWNLOAD"); println!("cargo:rerun-if-env-changed=FORCE_DEPS_DOWNLOAD");
println!("cargo:rerun-if-changed=templates/");
minify_template_file("templates/base.html", "templates/.base.min.html").unwrap();
minify_template_file("templates/dir.html", "templates/.dir.min.html").unwrap();
minify_template_file("templates/file.html", "templates/.file.min.html").unwrap();
let out_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let out_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let assets_path = Path::new(&out_dir).join("assets"); let assets_path = Path::new(&out_dir).join("assets");
fs::create_dir_all(&assets_path).expect("Fail to create directory"); fs::create_dir_all(&assets_path).expect("Fail to create directory");
@ -79,3 +86,30 @@ fn should_download(path: &Path) -> bool {
true true
} }
fn minify_template_file<P: AsRef<str>>(input_path: P, output_path: P) -> io::Result<()> {
let html_content = fs::read_to_string(input_path.as_ref())?;
let minified = minify_template_content(&html_content)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
fs::write(output_path.as_ref(), minified)?;
Ok(())
}
#[allow(clippy::missing_errors_doc)]
pub fn minify_template_content(template: &str) -> Result<String, String> {
let mut cfg = Cfg::new();
cfg.allow_removing_spaces_between_attributes = true;
cfg.keep_comments = false;
cfg.minify_css = true;
cfg.minify_js = true;
cfg.keep_html_and_head_opening_tags = true;
cfg.keep_closing_tags = true;
cfg.remove_processing_instructions = true;
let minified_bytes = minify(template.as_bytes(), &cfg);
String::from_utf8(minified_bytes).map_err(|e| format!("Invalid UTF-8 in output: {e}"))
}

View File

@ -52,7 +52,7 @@ pub struct FileEntry {
} }
#[derive(Template)] #[derive(Template)]
#[template(path = "dir.html")] #[template(path = ".dir.min.html")]
pub struct DirectoryTemplate { pub struct DirectoryTemplate {
pub title_path: String, pub title_path: String,
pub files: Vec<FileEntry>, pub files: Vec<FileEntry>,
@ -65,7 +65,7 @@ pub struct DirectoryTemplate {
} }
#[derive(Template)] #[derive(Template)]
#[template(path = "file.html")] #[template(path = ".file.min.html")]
pub struct NoteTemplate { pub struct NoteTemplate {
pub filename: String, pub filename: String,
pub back_link: String, pub back_link: String,

910
src/markdown/emoji.rs Normal file
View File

@ -0,0 +1,910 @@
use std::collections::HashMap;
use std::sync::LazyLock;
static EMOJIS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
HashMap::from([
("bowtie", "🙇"),
("smile", "😄"),
("laughing", "😆"),
("blush", "😊"),
("smiley", "😃"),
("relaxed", "☺️"),
("smirk", "😏"),
("heart_eyes", "😍"),
("kissing_heart", "😘"),
("kissing_closed_eyes", "😚"),
("flushed", "😳"),
("relieved", "😌"),
("satisfied", "😌"),
("grin", "😁"),
("wink", "😉"),
("stuck_out_tongue_winking_eye", "😜"),
("stuck_out_tongue_closed_eyes", "😝"),
("grinning", "😀"),
("kissing", "😗"),
("kissing_smiling_eyes", "😙"),
("stuck_out_tongue", "😛"),
("sleeping", "😴"),
("worried", "😟"),
("frowning", "😦"),
("anguished", "😧"),
("open_mouth", "😮"),
("grimacing", "😬"),
("confused", "😕"),
("hushed", "😯"),
("expressionless", "😑"),
("unamused", "😒"),
("sweat_smile", "😅"),
("sweat", "😓"),
("disappointed_relieved", "😥"),
("weary", "😩"),
("pensive", "😔"),
("disappointed", "😞"),
("confounded", "😖"),
("fearful", "😨"),
("cold_sweat", "😰"),
("persevere", "😣"),
("cry", "😢"),
("sob", "😭"),
("joy", "😂"),
("astonished", "😲"),
("scream", "😱"),
("neckbeard", "🧔"),
("tired_face", "😫"),
("angry", "😠"),
("rage", "😡"),
("triumph", "😤"),
("sleepy", "😪"),
("yum", "😋"),
("mask", "😷"),
("sunglasses", "😎"),
("dizzy_face", "😵"),
("imp", "👿"),
("smiling_imp", "😈"),
("neutral_face", "😐"),
("no_mouth", "😶"),
("innocent", "😇"),
("alien", "👽"),
("yellow_heart", "💛"),
("blue_heart", "💙"),
("purple_heart", "💜"),
("heart", "❤️"),
("green_heart", "💚"),
("broken_heart", "💔"),
("heartbeat", "💓"),
("heartpulse", "💗"),
("two_hearts", "💕"),
("revolving_hearts", "💞"),
("cupid", "💘"),
("sparkling_heart", "💖"),
("sparkles", ""),
("star", ""),
("star2", "🌟"),
("dizzy", "💫"),
("boom", "💥"),
("collision", "💥"),
("anger", "💢"),
("exclamation", ""),
("question", ""),
("grey_exclamation", ""),
("grey_question", ""),
("zzz", "💤"),
("dash", "💨"),
("sweat_drops", "💦"),
("notes", "🎶"),
("musical_note", "🎵"),
("fire", "🔥"),
("hankey", "💩"),
("poop", "💩"),
("shit", "💩"),
("+1", "👍"),
("thumbsup", "👍"),
("-1", "👎"),
("thumbsdown", "👎"),
("ok_hand", "👌"),
("punch", "👊"),
("facepunch", "👊"),
("fist", ""),
("v", "✌️"),
("wave", "👋"),
("hand", ""),
("raised_hand", ""),
("open_hands", "👐"),
("point_up", "☝️"),
("point_down", "👇"),
("point_left", "👈"),
("point_right", "👉"),
("raised_hands", "🙌"),
("pray", "🙏"),
("point_up_2", "👆"),
("clap", "👏"),
("muscle", "💪"),
("metal", "🤘"),
("fu", "🖕"),
("walking", "🚶"),
("runner", "🏃"),
("running", "🏃"),
("couple", "👫"),
("family", "👨‍👩‍👦"),
("two_men_holding_hands", "👬"),
("two_women_holding_hands", "👭"),
("dancer", "💃"),
("dancers", "👯"),
("ok_woman", "🙆"),
("no_good", "🙅"),
("information_desk_person", "💁"),
("raising_hand", "🙋"),
("bride_with_veil", "👰"),
("person_with_pouting_face", "🙎"),
("person_frowning", "🙍"),
("bow", "🙇"),
("couplekiss", "💏"),
("couple_with_heart", "💑"),
("massage", "💆"),
("haircut", "💇"),
("nail_care", "💅"),
("boy", "👦"),
("girl", "👧"),
("woman", "👩"),
("man", "👨"),
("baby", "👶"),
("older_woman", "👵"),
("older_man", "👴"),
("person_with_blond_hair", "👱"),
("man_with_gua_pi_mao", "👲"),
("man_with_turban", "👳"),
("construction_worker", "👷"),
("cop", "👮"),
("angel", "👼"),
("princess", "👸"),
("smiley_cat", "😺"),
("smile_cat", "😸"),
("heart_eyes_cat", "😻"),
("kissing_cat", "😽"),
("smirk_cat", "😼"),
("scream_cat", "🙀"),
("crying_cat_face", "😿"),
("joy_cat", "😹"),
("pouting_cat", "😾"),
("japanese_ogre", "👹"),
("japanese_goblin", "👺"),
("see_no_evil", "🙈"),
("hear_no_evil", "🙉"),
("speak_no_evil", "🙊"),
("guardsman", "💂"),
("skull", "💀"),
("feet", "🐾"),
("lips", "👄"),
("kiss", "💋"),
("droplet", "💧"),
("ear", "👂"),
("eyes", "👀"),
("nose", "👃"),
("tongue", "👅"),
("love_letter", "💌"),
("bust_in_silhouette", "👤"),
("busts_in_silhouette", "👥"),
("speech_balloon", "💬"),
("thought_balloon", "💭"),
("feelsgood", "😎"),
("finnadie", "😵"),
("goberserk", "😈"),
("godmode", "😇"),
("hurtrealbad", "😰"),
("rage1", "😡"),
("rage2", "😡"),
("rage3", "😡"),
("rage4", "😡"),
("suspect", "😕"),
("trollface", "😂"),
// Nature
("sunny", "☀️"),
("umbrella", "☂️"),
("cloud", "☁️"),
("snowflake", "❄️"),
("snowman", ""),
("zap", ""),
("cyclone", "🌀"),
("foggy", "🌁"),
("ocean", "🌊"),
("cat", "🐱"),
("dog", "🐶"),
("mouse", "🐭"),
("hamster", "🐹"),
("rabbit", "🐰"),
("wolf", "🐺"),
("frog", "🐸"),
("tiger", "🐯"),
("koala", "🐨"),
("bear", "🐻"),
("pig", "🐷"),
("pig_nose", "🐽"),
("cow", "🐮"),
("boar", "🐗"),
("monkey_face", "🐵"),
("monkey", "🐒"),
("horse", "🐴"),
("racehorse", "🐎"),
("camel", "🐫"),
("sheep", "🐑"),
("elephant", "🐘"),
("panda_face", "🐼"),
("snake", "🐍"),
("bird", "🐦"),
("baby_chick", "🐤"),
("hatched_chick", "🐥"),
("hatching_chick", "🐣"),
("chicken", "🐔"),
("penguin", "🐧"),
("turtle", "🐢"),
("bug", "🐛"),
("honeybee", "🐝"),
("ant", "🐜"),
("beetle", "🐞"),
("snail", "🐌"),
("octopus", "🐙"),
("tropical_fish", "🐠"),
("fish", "🐟"),
("whale", "🐳"),
("whale2", "🐋"),
("dolphin", "🐬"),
("cow2", "🐄"),
("ram", "🐏"),
("rat", "🐀"),
("water_buffalo", "🐃"),
("tiger2", "🐅"),
("rabbit2", "🐇"),
("dragon", "🐉"),
("goat", "🐐"),
("rooster", "🐓"),
("dog2", "🐕"),
("pig2", "🐖"),
("mouse2", "🐁"),
("ox", "🐂"),
("dragon_face", "🐲"),
("blowfish", "🐡"),
("crocodile", "🐊"),
("dromedary_camel", "🐪"),
("leopard", "🐆"),
("cat2", "🐈"),
("poodle", "🐩"),
("paw_prints", "🐾"),
("bouquet", "💐"),
("cherry_blossom", "🌸"),
("tulip", "🌷"),
("four_leaf_clover", "🍀"),
("rose", "🌹"),
("sunflower", "🌻"),
("hibiscus", "🌺"),
("maple_leaf", "🍁"),
("leaves", "🍃"),
("fallen_leaf", "🍂"),
("herb", "🌿"),
("mushroom", "🍄"),
("cactus", "🌵"),
("palm_tree", "🌴"),
("evergreen_tree", "🌲"),
("deciduous_tree", "🌳"),
("chestnut", "🌰"),
("seedling", "🌱"),
("blossom", "🌼"),
("ear_of_rice", "🌾"),
("shell", "🐚"),
("globe_with_meridians", "🌐"),
("sun_with_face", "🌞"),
("full_moon_with_face", "🌝"),
("new_moon_with_face", "🌚"),
("new_moon", "🌑"),
("waxing_crescent_moon", "🌒"),
("first_quarter_moon", "🌓"),
("waxing_gibbous_moon", "🌔"),
("full_moon", "🌕"),
("waning_gibbous_moon", "🌖"),
("last_quarter_moon", "🌗"),
("waning_crescent_moon", "🌘"),
("last_quarter_moon_with_face", "🌜"),
("first_quarter_moon_with_face", "🌛"),
("moon", "🌙"),
("earth_africa", "🌍"),
("earth_americas", "🌎"),
("earth_asia", "🌏"),
("volcano", "🌋"),
("milky_way", "🌌"),
("partly_sunny", ""),
("octocat", "🐙"),
("squirrel", "🐿️"),
// Objects
("bamboo", "🎍"),
("gift_heart", "💝"),
("dolls", "🎎"),
("school_satchel", "🎒"),
("mortar_board", "🎓"),
("flags", "🎏"),
("fireworks", "🎆"),
("sparkler", "🎇"),
("wind_chime", "🎐"),
("rice_scene", "🎑"),
("jack_o_lantern", "🎃"),
("ghost", "👻"),
("santa", "🎅"),
("christmas_tree", "🎄"),
("gift", "🎁"),
("bell", "🔔"),
("no_bell", "🔕"),
("tanabata_tree", "🎋"),
("tada", "🎉"),
("confetti_ball", "🎊"),
("balloon", "🎈"),
("crystal_ball", "🔮"),
("cd", "💿"),
("dvd", "📀"),
("floppy_disk", "💾"),
("camera", "📷"),
("video_camera", "📹"),
("movie_camera", "🎥"),
("computer", "💻"),
("tv", "📺"),
("iphone", "📱"),
("phone", "📞"),
("telephone", "☎️"),
("telephone_receiver", "📞"),
("pager", "📟"),
("fax", "📠"),
("minidisc", "💽"),
("vhs", "📼"),
("sound", "🔊"),
("speaker", "🔈"),
("mute", "🔇"),
("loudspeaker", "📢"),
("mega", "📣"),
("hourglass", ""),
("hourglass_flowing_sand", ""),
("alarm_clock", ""),
("watch", ""),
("radio", "📻"),
("satellite", "📡"),
("loop", ""),
("mag", "🔍"),
("mag_right", "🔎"),
("unlock", "🔓"),
("lock", "🔒"),
("lock_with_ink_pen", "🔏"),
("closed_lock_with_key", "🔐"),
("key", "🔑"),
("bulb", "💡"),
("flashlight", "🔦"),
("high_brightness", "🔆"),
("low_brightness", "🔅"),
("electric_plug", "🔌"),
("battery", "🔋"),
("calling", "📲"),
("email", "📧"),
("mailbox", "📫"),
("postbox", "📮"),
("bath", "🛀"),
("bathtub", "🛁"),
("shower", "🚿"),
("toilet", "🚽"),
("wrench", "🔧"),
("nut_and_bolt", "🔩"),
("hammer", "🔨"),
("seat", "💺"),
("moneybag", "💰"),
("yen", "💴"),
("dollar", "💵"),
("pound", "💷"),
("euro", "💶"),
("credit_card", "💳"),
("money_with_wings", "💸"),
("e-mail", "📧"),
("inbox_tray", "📥"),
("outbox_tray", "📤"),
("envelope", "✉️"),
("incoming_envelope", "📨"),
("postal_horn", "📯"),
("mailbox_closed", "📪"),
("mailbox_with_mail", "📬"),
("mailbox_with_no_mail", "📭"),
("door", "🚪"),
("smoking", "🚬"),
("bomb", "💣"),
("gun", "🔫"),
("hocho", "🔪"),
("pill", "💊"),
("syringe", "💉"),
("page_facing_up", "📄"),
("page_with_curl", "📃"),
("bookmark_tabs", "📑"),
("bar_chart", "📊"),
("chart_with_upwards_trend", "📈"),
("chart_with_downwards_trend", "📉"),
("scroll", "📜"),
("clipboard", "📋"),
("calendar", "📅"),
("date", "📆"),
("card_index", "📇"),
("file_folder", "📁"),
("open_file_folder", "📂"),
("scissors", "✂️"),
("pushpin", "📌"),
("paperclip", "📎"),
("black_nib", "✒️"),
("pencil2", "✏️"),
("straight_ruler", "📏"),
("triangular_ruler", "📐"),
("closed_book", "📕"),
("green_book", "📗"),
("blue_book", "📘"),
("orange_book", "📙"),
("notebook", "📓"),
("notebook_with_decorative_cover", "📔"),
("ledger", "📒"),
("books", "📚"),
("bookmark", "🔖"),
("name_badge", "📛"),
("microscope", "🔬"),
("telescope", "🔭"),
("newspaper", "📰"),
("football", "🏈"),
("basketball", "🏀"),
("soccer", ""),
("baseball", ""),
("tennis", "🎾"),
("8ball", "🎱"),
("rugby_football", "🏉"),
("bowling", "🎳"),
("golf", ""),
("mountain_bicyclist", "🚵"),
("bicyclist", "🚴"),
("horse_racing", "🏇"),
("snowboarder", "🏂"),
("swimmer", "🏊"),
("surfer", "🏄"),
("ski", "⛷️"),
("spades", "♠️"),
("hearts", "♥️"),
("clubs", "♣️"),
("diamonds", "♦️"),
("gem", "💎"),
("ring", "💍"),
("trophy", "🏆"),
("musical_score", "🎼"),
("musical_keyboard", "🎹"),
("violin", "🎻"),
("space_invader", "👾"),
("video_game", "🎮"),
("black_joker", "🃏"),
("flower_playing_cards", "🎴"),
("game_die", "🎲"),
("dart", "🎯"),
("mahjong", "🀄"),
("clapper", "🎬"),
("memo", "📝"),
("pencil", "📝"),
("book", "📖"),
("art", "🎨"),
("microphone", "🎤"),
("headphones", "🎧"),
("trumpet", "🎺"),
("saxophone", "🎷"),
("guitar", "🎸"),
("shoe", "👞"),
("sandal", "👡"),
("high_heel", "👠"),
("lipstick", "💄"),
("boot", "👢"),
("shirt", "👕"),
("tshirt", "👕"),
("necktie", "👔"),
("womans_clothes", "👚"),
("dress", "👗"),
("running_shirt_with_sash", "🎽"),
("jeans", "👖"),
("kimono", "👘"),
("bikini", "👙"),
("ribbon", "🎀"),
("tophat", "🎩"),
("crown", "👑"),
("womans_hat", "👒"),
("mans_shoe", "👞"),
("closed_umbrella", "🌂"),
("briefcase", "💼"),
("handbag", "👜"),
("pouch", "👝"),
("purse", "👛"),
("eyeglasses", "👓"),
("fishing_pole_and_fish", "🎣"),
("coffee", ""),
("tea", "🍵"),
("sake", "🍶"),
("baby_bottle", "🍼"),
("beer", "🍺"),
("beers", "🍻"),
("cocktail", "🍸"),
("tropical_drink", "🍹"),
("wine_glass", "🍷"),
("fork_and_knife", "🍴"),
("pizza", "🍕"),
("hamburger", "🍔"),
("fries", "🍟"),
("poultry_leg", "🍗"),
("meat_on_bone", "🍖"),
("spaghetti", "🍝"),
("curry", "🍛"),
("fried_shrimp", "🍤"),
("bento", "🍱"),
("sushi", "🍣"),
("fish_cake", "🍥"),
("rice_ball", "🍙"),
("rice_cracker", "🍘"),
("rice", "🍚"),
("ramen", "🍜"),
("stew", "🍲"),
("oden", "🍢"),
("dango", "🍡"),
("egg", "🍳"),
("bread", "🍞"),
("doughnut", "🍩"),
("custard", "🍮"),
("icecream", "🍦"),
("ice_cream", "🍨"),
("shaved_ice", "🍧"),
("birthday", "🎂"),
("cake", "🍰"),
("cookie", "🍪"),
("chocolate_bar", "🍫"),
("candy", "🍬"),
("lollipop", "🍭"),
("honey_pot", "🍯"),
("apple", "🍎"),
("green_apple", "🍏"),
("tangerine", "🍊"),
("lemon", "🍋"),
("cherries", "🍒"),
("grapes", "🍇"),
("watermelon", "🍉"),
("strawberry", "🍓"),
("peach", "🍑"),
("melon", "🍈"),
("banana", "🍌"),
("pear", "🍐"),
("pineapple", "🍍"),
("sweet_potato", "🍠"),
("eggplant", "🍆"),
("tomato", "🍅"),
("corn", "🌽"),
// Places
("house", "🏠"),
("house_with_garden", "🏡"),
("school", "🏫"),
("office", "🏢"),
("post_office", "🏣"),
("hospital", "🏥"),
("bank", "🏦"),
("convenience_store", "🏪"),
("love_hotel", "🏩"),
("hotel", "🏨"),
("wedding", "💒"),
("church", ""),
("department_store", "🏬"),
("european_post_office", "🏤"),
("city_sunrise", "🌇"),
("city_sunset", "🌆"),
("japanese_castle", "🏯"),
("european_castle", "🏰"),
("tent", ""),
("factory", "🏭"),
("tokyo_tower", "🗼"),
("japan", "🗾"),
("mount_fuji", "🗻"),
("sunrise_over_mountains", "🌄"),
("sunrise", "🌅"),
("stars", "🌠"),
("statue_of_liberty", "🗽"),
("bridge_at_night", "🌉"),
("carousel_horse", "🎠"),
("rainbow", "🌈"),
("ferris_wheel", "🎡"),
("fountain", ""),
("roller_coaster", "🎢"),
("ship", "🚢"),
("speedboat", "🚤"),
("boat", ""),
("sailboat", ""),
("rowboat", "🚣"),
("anchor", ""),
("rocket", "🚀"),
("airplane", "✈️"),
("helicopter", "🚁"),
("steam_locomotive", "🚂"),
("tram", "🚋"),
("mountain_railway", "🚞"),
("bike", "🚲"),
("aerial_tramway", "🚡"),
("suspension_railway", "🚟"),
("mountain_cableway", "🚠"),
("tractor", "🚜"),
("blue_car", "🚙"),
("oncoming_automobile", "🚘"),
("car", "🚗"),
("red_car", "🚗"),
("taxi", "🚕"),
("oncoming_taxi", "🚖"),
("articulated_lorry", "🚛"),
("bus", "🚌"),
("oncoming_bus", "🚍"),
("rotating_light", "🚨"),
("police_car", "🚓"),
("oncoming_police_car", "🚔"),
("fire_engine", "🚒"),
("ambulance", "🚑"),
("minibus", "🚐"),
("truck", "🚚"),
("train", "🚆"),
("station", "🚉"),
("train2", "🚄"),
("bullettrain_front", "🚅"),
("bullettrain_side", "🚄"),
("light_rail", "🚈"),
("monorail", "🚝"),
("railway_car", "🚃"),
("trolleybus", "🚎"),
("ticket", "🎫"),
("fuelpump", ""),
("vertical_traffic_light", "🚦"),
("traffic_light", "🚥"),
("warning", "⚠️"),
("construction", "🚧"),
("beginner", "🔰"),
("atm", "🏧"),
("slot_machine", "🎰"),
("busstop", "🚏"),
("barber", "💈"),
("hotsprings", "♨️"),
("checkered_flag", "🏁"),
("crossed_flags", "🎌"),
("izakaya_lantern", "🏮"),
("moyai", "🗿"),
("circus_tent", "🎪"),
("performing_arts", "🎭"),
("round_pushpin", "📍"),
("triangular_flag_on_post", "🚩"),
("jp", "🇯🇵"),
("kr", "🇰🇷"),
("cn", "🇨🇳"),
("us", "🇺🇸"),
("fr", "🇫🇷"),
("es", "🇪🇸"),
("it", "🇮🇹"),
("ru", "🇷🇺"),
("gb", "🇬🇧"),
("uk", "🇬🇧"),
("de", "🇩🇪"),
// Symbols
("one", "1"),
("two", "2"),
("three", "3"),
("four", "4"),
("five", "5"),
("six", "6"),
("seven", "7"),
("eight", "8"),
("nine", "9"),
("keycap_ten", "🔟"),
("1234", "🔢"),
("zero", "0"),
("hash", "#️⃣"),
("symbols", "🔣"),
("arrow_backward", "◀️"),
("arrow_down", "⬇️"),
("arrow_forward", "▶️"),
("arrow_left", "⬅️"),
("capital_abcd", "🔠"),
("abcd", "🔡"),
("abc", "🔤"),
("arrow_lower_left", "↙️"),
("arrow_lower_right", "↘️"),
("arrow_right", "➡️"),
("arrow_up", "⬆️"),
("arrow_upper_left", "↖️"),
("arrow_upper_right", "↗️"),
("arrow_double_down", ""),
("arrow_double_up", ""),
("arrow_down_small", "🔽"),
("arrow_heading_down", "↘️"),
("arrow_heading_up", "↗️"),
("leftwards_arrow_with_hook", "↩️"),
("arrow_right_hook", "↪️"),
("left_right_arrow", "↔️"),
("arrow_up_down", "↕️"),
("arrow_up_small", "🔼"),
("arrows_clockwise", "🔃"),
("arrows_counterclockwise", "🔄"),
("rewind", ""),
("fast_forward", ""),
("information_source", ""),
("ok", "🆗"),
("twisted_rightwards_arrows", "🔀"),
("repeat", "🔁"),
("repeat_one", "🔂"),
("new", "🆕"),
("top", "🔝"),
("up", "🆙"),
("cool", "🆒"),
("free", "🆓"),
("ng", "🆖"),
("cinema", "🎦"),
("koko", "🈁"),
("signal_strength", "📶"),
("u5272", "🈹"),
("u5408", "🈴"),
("u55b6", "🈺"),
("u6307", "🈯"),
("u6708", "🈷️"),
("u6709", "🈶"),
("u6e80", "🈵"),
("u7121", "🈚"),
("u7533", "🈸"),
("u7a7a", "🈳"),
("u7981", "🈲"),
("sa", "🈂️"),
("restroom", "🚻"),
("mens", "🚹"),
("womens", "🚺"),
("baby_symbol", "🚼"),
("no_smoking", "🚭"),
("parking", "🅿️"),
("wheelchair", ""),
("metro", "🚇"),
("baggage_claim", "🛄"),
("accept", "🉑"),
("wc", "🚾"),
("potable_water", "🚰"),
("put_litter_in_its_place", "🚮"),
("secret", "㊙️"),
("congratulations", "㊗️"),
("m", "Ⓜ️"),
("passport_control", "🛂"),
("left_luggage", "🛅"),
("customs", "🛃"),
("ideograph_advantage", "🉐"),
("cl", "🆑"),
("sos", "🆘"),
("id", "🆔"),
("no_entry_sign", "🚫"),
("underage", "🔞"),
("no_mobile_phones", "📵"),
("do_not_litter", "🚯"),
("non-potable_water", "🚱"),
("no_bicycles", "🚳"),
("no_pedestrians", "🚷"),
("children_crossing", "🚸"),
("no_entry", ""),
("eight_spoked_asterisk", "✳️"),
("eight_pointed_black_star", "✴️"),
("heart_decoration", "💟"),
("vs", "🆚"),
("vibration_mode", "📳"),
("mobile_phone_off", "📴"),
("chart", "💹"),
("currency_exchange", "💱"),
("aries", ""),
("taurus", ""),
("gemini", ""),
("cancer", ""),
("leo", ""),
("virgo", ""),
("libra", ""),
("scorpius", ""),
("sagittarius", ""),
("capricorn", ""),
("aquarius", ""),
("pisces", ""),
("ophiuchus", ""),
("six_pointed_star", "🔯"),
("negative_squared_cross_mark", ""),
("a", "🅰️"),
("b", "🅱️"),
("ab", "🆎"),
("o2", "🅾️"),
("diamond_shape_with_a_dot_inside", "💠"),
("recycle", "♻️"),
("end", "🔚"),
("on", "🔛"),
("soon", "🔜"),
("clock1", "🕐"),
("clock130", "🕜"),
("clock10", "🕙"),
("clock1030", "🕥"),
("clock11", "🕚"),
("clock1130", "🕦"),
("clock12", "🕛"),
("clock1230", "🕧"),
("clock2", "🕑"),
("clock230", "🕝"),
("clock3", "🕒"),
("clock330", "🕞"),
("clock4", "🕓"),
("clock430", "🕟"),
("clock5", "🕔"),
("clock530", "🕠"),
("clock6", "🕕"),
("clock630", "🕡"),
("clock7", "🕖"),
("clock730", "🕢"),
("clock8", "🕗"),
("clock830", "🕣"),
("clock9", "🕘"),
("clock930", "🕤"),
("heavy_dollar_sign", "💲"),
("copyright", "©️"),
("registered", "®️"),
("tm", "™️"),
("x", ""),
("heavy_exclamation_mark", ""),
("bangbang", "‼️"),
("interrobang", "⁉️"),
("o", ""),
("heavy_multiplication_x", "✖️"),
("heavy_plus_sign", ""),
("heavy_minus_sign", ""),
("heavy_division_sign", ""),
("white_flower", "💮"),
("100", "💯"),
("heavy_check_mark", "✔️"),
("ballot_box_with_check", "☑️"),
("radio_button", "🔘"),
("link", "🔗"),
("curly_loop", ""),
("wavy_dash", "〰️"),
("part_alternation_mark", "〽️"),
("trident", "🔱"),
("black_square", ""),
("white_square", ""),
("white_check_mark", ""),
("black_square_button", "🔲"),
("white_square_button", "🔳"),
("black_circle", ""),
("white_circle", ""),
("red_circle", "🔴"),
("large_blue_circle", "🔵"),
("large_blue_diamond", "🔷"),
("large_orange_diamond", "🔶"),
("small_blue_diamond", "🔹"),
("small_orange_diamond", "🔸"),
("small_red_triangle", "🔺"),
("small_red_triangle_down", "🔻"),
("shipit", "🚢"),
])
});
pub fn replace_emoji(text: &str) -> String {
let mut result = String::with_capacity(text.len());
let mut current = text;
while let Some((before, after)) = current.split_once(':') {
result.push_str(before);
if let Some((name, rest)) = after.split_once(':') {
if let Some(emoji) = EMOJIS.get(name) {
result.push_str(emoji);
} else {
result.push(':');
result.push_str(name);
result.push(':');
}
current = rest;
} else {
result.push(':');
result.push_str(after);
current = "";
break;
}
}
if !current.is_empty() {
result.push_str(current);
}
result
}

View File

@ -6,7 +6,9 @@ use pulldown_cmark::{
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Write; use std::fmt::Write;
// ========== Класс состояния таблицы ========== mod emoji;
use emoji::replace_emoji;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum AlignmentState { pub enum AlignmentState {
Left, Left,
@ -219,12 +221,18 @@ impl MarkdownRenderer {
let _ = write!(output, "<sup><a href=\"#{fref}\" id=\"{fref}\">"); let _ = write!(output, "<sup><a href=\"#{fref}\" id=\"{fref}\">");
} }
Tag::Superscript => {
output.push_str("<sup>");
}
Tag::Subscript => {
output.push_str("<sub>");
}
Tag::HtmlBlock Tag::HtmlBlock
| Tag::DefinitionList | Tag::DefinitionList
| Tag::DefinitionListTitle | Tag::DefinitionListTitle
| Tag::DefinitionListDefinition | Tag::DefinitionListDefinition
| Tag::Superscript
| Tag::Subscript
| Tag::MetadataBlock(_) => (), | Tag::MetadataBlock(_) => (),
} }
@ -281,12 +289,18 @@ impl MarkdownRenderer {
output.push_str("</a></sup>"); output.push_str("</a></sup>");
} }
TagEnd::Superscript => {
output.push_str("</sup>");
}
TagEnd::Subscript => {
output.push_str("</sub>");
}
TagEnd::HtmlBlock TagEnd::HtmlBlock
| TagEnd::DefinitionList | TagEnd::DefinitionList
| TagEnd::DefinitionListTitle | TagEnd::DefinitionListTitle
| TagEnd::DefinitionListDefinition | TagEnd::DefinitionListDefinition
| TagEnd::Superscript
| TagEnd::Subscript
| TagEnd::MetadataBlock(_) => (), | TagEnd::MetadataBlock(_) => (),
} }
@ -303,6 +317,8 @@ pub fn markdown_to_html(markdown: &str, _file_path: &str) -> String {
options.insert(Options::ENABLE_TASKLISTS); options.insert(Options::ENABLE_TASKLISTS);
options.insert(Options::ENABLE_HEADING_ATTRIBUTES); options.insert(Options::ENABLE_HEADING_ATTRIBUTES);
options.insert(Options::ENABLE_GFM); options.insert(Options::ENABLE_GFM);
options.insert(Options::ENABLE_SUBSCRIPT);
options.insert(Options::ENABLE_SUPERSCRIPT);
let mut renderer = MarkdownRenderer::new(); let mut renderer = MarkdownRenderer::new();
let mut html_output = String::new(); let mut html_output = String::new();
@ -329,7 +345,7 @@ pub fn markdown_to_html(markdown: &str, _file_path: &str) -> String {
if renderer.in_code_block { if renderer.in_code_block {
renderer.code_content.push_str(&text); renderer.code_content.push_str(&text);
} else { } else {
html_output.push_str(&escape_html(&text)); html_output.push_str(&escape_html(&replace_emoji(&text)));
} }
} }
Event::TaskListMarker(true) => { Event::TaskListMarker(true) => {
@ -419,7 +435,9 @@ fn render_blockquote(quote_kind: Option<BlockQuoteKind>) -> String {
fn render_link(link_type: LinkType, dest_url: &CowStr<'_>, title: &CowStr<'_>) -> String { fn render_link(link_type: LinkType, dest_url: &CowStr<'_>, title: &CowStr<'_>) -> String {
match link_type { match link_type {
LinkType::Email => format!("<a href=\"mailto:{dest_url}\" title=\"{title}\">"), LinkType::Email => format!("<a href=\"mailto:{dest_url}\" title=\"{title}\">"),
_ => format!("<a href=\"{dest_url}\" title=\"{title}\">"), _ => format!(
"<a href=\"{dest_url}\" title=\"{title}\" target=\"_blank\" rel=\"noopener noreferrer\">"
),
} }
} }

View File

@ -236,8 +236,6 @@
<script src="{{ mermaid_script_url }}"></script> <script src="{{ mermaid_script_url }}"></script>
<script src="{{ highlight_script_url }}"></script> <script src="{{ highlight_script_url }}"></script>
<script> <script>
{% block scripts %}{% endblock %}
function copyCode(button) { function copyCode(button) {
const wrapper = button.closest('.code-block-wrapper'); const wrapper = button.closest('.code-block-wrapper');
if (!wrapper) return; if (!wrapper) return;
@ -276,6 +274,6 @@
hljs.highlightAll(); hljs.highlightAll();
</script> </script>
<script>{% block scripts %}{% endblock %}</script>
</body> </body>
</html> </html>

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% extends ".base.min.html" %}
{% block title %}Directory: /{{ title_path }}{% endblock %} {% block title %}Directory: /{{ title_path }}{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "base.html" %} {% extends ".base.min.html" %}
{% block title %}{{ filename }}{% endblock %} {% block title %}{{ filename }}{% endblock %}