From 3075719963bc01dd86c905c6d0582b55d865b657 Mon Sep 17 00:00:00 2001 From: "N0\\A" Date: Thu, 26 Mar 2026 13:16:34 +0100 Subject: [PATCH] feat: might be actually feature-complete by now --- awk/definition_lists.awk | 62 +++ awk/emoji.awk | 857 +++++++++++++++++++++++++++++++++++++ awk/footnotes.awk | 51 +++ awk/markdown_inline.awk | 2 + awk/paragraphs.awk | 2 +- awk/toc.awk | 50 +++ kewt.sh | 215 ++++++++-- markdown.sh | 7 + site/Docs/configuration.md | 26 +- site/Docs/usage.md | 6 + site/index.md | 9 +- styles/kewt.css | 23 + 12 files changed, 1274 insertions(+), 36 deletions(-) create mode 100644 awk/definition_lists.awk create mode 100644 awk/emoji.awk create mode 100644 awk/footnotes.awk create mode 100644 awk/toc.awk diff --git a/awk/definition_lists.awk b/awk/definition_lists.awk new file mode 100644 index 0000000..13ed75d --- /dev/null +++ b/awk/definition_lists.awk @@ -0,0 +1,62 @@ +BEGIN { + in_dl = 0 + has_prev = 0 + prev_line = "" + in_pre = 0 +} +{ + if ($0 ~ /^
/) {
+        if (!in_pre) in_pre = 1
+    }
+    
+    if (!in_pre && $0 ~ /^:[ \t]+[^ \t]/) {
+        if (!in_dl) {
+            in_dl = 1
+            print "
" + print "
" prev_line "
" + has_prev = 0 + } else { + if (has_prev && prev_line != "") { + print "
" prev_line "
" + has_prev = 0 + } + } + def_text = $0 + sub(/^:[ \t]+/, "", def_text) + print "
" def_text "
" + + if ($0 ~ /<\/pre>/) { + if (in_pre) in_pre = 0 + } + next + } else { + if (in_dl) { + if ($0 == "") { + # End of definition list + print "
" + in_dl = 0 + print "" + has_prev = 0 + next + } + } + if (has_prev) { + print prev_line + } + prev_line = $0 + has_prev = 1 + } + + if ($0 ~ /<\/pre>/) { + if (in_pre) in_pre = 0 + } +} +END { + if (in_dl) { + print "" + } else { + if (has_prev) { + print prev_line + } + } +} diff --git a/awk/emoji.awk b/awk/emoji.awk new file mode 100644 index 0000000..2324174 --- /dev/null +++ b/awk/emoji.awk @@ -0,0 +1,857 @@ +BEGIN { + map[":+1:"] = "๐Ÿ‘" + map[":100:"] = "๐Ÿ’ฏ" + map[":1234:"] = "๐Ÿ”ข" + map[":8ball:"] = "๐ŸŽฑ" + map[":a:"] = "๐Ÿ…ฐ๏ธ" + map[":ab:"] = "๐Ÿ†Ž" + map[":abc:"] = "๐Ÿ”ค" + map[":abcd:"] = "๐Ÿ”ก" + map[":accept:"] = "๐Ÿ‰‘" + map[":aerial_tramway:"] = "๐Ÿšก" + map[":airplane:"] = "โœˆ๏ธ" + map[":alarm_clock:"] = "โฐ" + map[":alien:"] = "๐Ÿ‘ฝ" + map[":ambulance:"] = "๐Ÿš‘" + map[":anchor:"] = "โš“" + map[":angel:"] = "๐Ÿ‘ผ" + map[":anger:"] = "๐Ÿ’ข" + map[":angry:"] = "๐Ÿ˜ " + map[":anguished:"] = "๐Ÿ˜ง" + map[":ant:"] = "๐Ÿœ" + map[":apple:"] = "๐ŸŽ" + map[":aquarius:"] = "โ™’" + map[":aries:"] = "โ™ˆ" + map[":arrow_backward:"] = "โ—€๏ธ" + map[":arrow_double_down:"] = "โฌ" + map[":arrow_double_up:"] = "โซ" + map[":arrow_down:"] = "โฌ‡๏ธ" + map[":arrow_down_small:"] = "๐Ÿ”ฝ" + map[":arrow_forward:"] = "โ–ถ๏ธ" + map[":arrow_heading_down:"] = "โคต๏ธ" + map[":arrow_heading_up:"] = "โคด๏ธ" + map[":arrow_left:"] = "โฌ…๏ธ" + map[":arrow_lower_left:"] = "โ†™๏ธ" + map[":arrow_lower_right:"] = "โ†˜๏ธ" + map[":arrow_right:"] = "โžก๏ธ" + map[":arrow_right_hook:"] = "โ†ช๏ธ" + map[":arrow_up:"] = "โฌ†๏ธ" + map[":arrow_up_down:"] = "โ†•๏ธ" + map[":arrow_up_small:"] = "๐Ÿ”ผ" + map[":arrow_upper_left:"] = "โ†–๏ธ" + map[":arrow_upper_right:"] = "โ†—๏ธ" + map[":arrows_clockwise:"] = "๐Ÿ”ƒ" + map[":arrows_counterclockwise:"] = "๐Ÿ”„" + map[":art:"] = "๐ŸŽจ" + map[":articulated_lorry:"] = "๐Ÿš›" + map[":astonished:"] = "๐Ÿ˜ฒ" + map[":atm:"] = "๐Ÿง" + map[":b:"] = "๐Ÿ…ฑ๏ธ" + map[":baby:"] = "๐Ÿ‘ถ" + map[":baby_bottle:"] = "๐Ÿผ" + map[":baby_chick:"] = "๐Ÿค" + map[":baby_symbol:"] = "๐Ÿšผ" + map[":baggage_claim:"] = "๐Ÿ›„" + map[":balloon:"] = "๐ŸŽˆ" + map[":ballot_box_with_check:"] = "โ˜‘๏ธ" + map[":bamboo:"] = "๐ŸŽ" + map[":banana:"] = "๐ŸŒ" + map[":bangbang:"] = "โ€ผ๏ธ" + map[":bank:"] = "๐Ÿฆ" + map[":bar_chart:"] = "๐Ÿ“Š" + map[":barber:"] = "๐Ÿ’ˆ" + map[":baseball:"] = "โšพ" + map[":basketball:"] = "๐Ÿ€" + map[":bath:"] = "๐Ÿ›€" + map[":bathtub:"] = "๐Ÿ›" + map[":battery:"] = "๐Ÿ”‹" + map[":bear:"] = "๐Ÿป" + map[":beer:"] = "๐Ÿบ" + map[":beers:"] = "๐Ÿป" + map[":beetle:"] = "๐Ÿชฒ" + map[":beginner:"] = "๐Ÿ”ฐ" + map[":bell:"] = "๐Ÿ””" + map[":bento:"] = "๐Ÿฑ" + map[":bicyclist:"] = "๐Ÿšด" + map[":bike:"] = "๐Ÿšฒ" + map[":bikini:"] = "๐Ÿ‘™" + map[":bird:"] = "๐Ÿฆ" + map[":birthday:"] = "๐ŸŽ‚" + map[":black_circle:"] = "โšซ" + map[":black_joker:"] = "๐Ÿƒ" + map[":black_nib:"] = "โœ’๏ธ" + map[":black_square_button:"] = "๐Ÿ”ฒ" + map[":blossom:"] = "๐ŸŒผ" + map[":blowfish:"] = "๐Ÿก" + map[":blue_book:"] = "๐Ÿ“˜" + map[":blue_car:"] = "๐Ÿš™" + map[":blue_heart:"] = "๐Ÿ’™" + map[":blush:"] = "๐Ÿ˜Š" + map[":boar:"] = "๐Ÿ—" + map[":boat:"] = "โ›ต" + map[":bomb:"] = "๐Ÿ’ฃ" + map[":book:"] = "๐Ÿ“–" + map[":bookmark:"] = "๐Ÿ”–" + map[":bookmark_tabs:"] = "๐Ÿ“‘" + map[":books:"] = "๐Ÿ“š" + map[":boom:"] = "๐Ÿ’ฅ" + map[":boot:"] = "๐Ÿ‘ข" + map[":bouquet:"] = "๐Ÿ’" + map[":bow:"] = "๐Ÿ™‡" + map[":bowling:"] = "๐ŸŽณ" + map[":boy:"] = "๐Ÿ‘ฆ" + map[":bread:"] = "๐Ÿž" + map[":bride_with_veil:"] = "๐Ÿ‘ฐโ€โ™€๏ธ" + map[":bridge_at_night:"] = "๐ŸŒ‰" + map[":briefcase:"] = "๐Ÿ’ผ" + map[":broken_heart:"] = "๐Ÿ’”" + map[":bug:"] = "๐Ÿ›" + map[":bulb:"] = "๐Ÿ’ก" + map[":bullettrain_front:"] = "๐Ÿš…" + map[":bullettrain_side:"] = "๐Ÿš„" + map[":bus:"] = "๐ŸšŒ" + map[":busstop:"] = "๐Ÿš" + map[":bust_in_silhouette:"] = "๐Ÿ‘ค" + map[":busts_in_silhouette:"] = "๐Ÿ‘ฅ" + map[":cactus:"] = "๐ŸŒต" + map[":cake:"] = "๐Ÿฐ" + map[":calendar:"] = "๐Ÿ“†" + map[":calling:"] = "๐Ÿ“ฒ" + map[":camel:"] = "๐Ÿซ" + map[":camera:"] = "๐Ÿ“ท" + map[":cancer:"] = "โ™‹" + map[":candy:"] = "๐Ÿฌ" + map[":capital_abcd:"] = "๐Ÿ” " + map[":capricorn:"] = "โ™‘" + map[":car:"] = "๐Ÿš—" + map[":card_index:"] = "๐Ÿ“‡" + map[":carousel_horse:"] = "๐ŸŽ " + map[":cat2:"] = "๐Ÿˆ" + map[":cat:"] = "๐Ÿฑ" + map[":cd:"] = "๐Ÿ’ฟ" + map[":chart:"] = "๐Ÿ’น" + map[":chart_with_downwards_trend:"] = "๐Ÿ“‰" + map[":chart_with_upwards_trend:"] = "๐Ÿ“ˆ" + map[":checkered_flag:"] = "๐Ÿ" + map[":cherries:"] = "๐Ÿ’" + map[":cherry_blossom:"] = "๐ŸŒธ" + map[":chestnut:"] = "๐ŸŒฐ" + map[":chicken:"] = "๐Ÿ”" + map[":children_crossing:"] = "๐Ÿšธ" + map[":chocolate_bar:"] = "๐Ÿซ" + map[":christmas_tree:"] = "๐ŸŽ„" + map[":church:"] = "โ›ช" + map[":cinema:"] = "๐ŸŽฆ" + map[":circus_tent:"] = "๐ŸŽช" + map[":city_sunrise:"] = "๐ŸŒ‡" + map[":city_sunset:"] = "๐ŸŒ†" + map[":cl:"] = "๐Ÿ†‘" + map[":clap:"] = "๐Ÿ‘" + map[":clapper:"] = "๐ŸŽฌ" + map[":clipboard:"] = "๐Ÿ“‹" + map[":clock1030:"] = "๐Ÿ•ฅ" + map[":clock10:"] = "๐Ÿ•™" + map[":clock1130:"] = "๐Ÿ•ฆ" + map[":clock11:"] = "๐Ÿ•š" + map[":clock1230:"] = "๐Ÿ•ง" + map[":clock12:"] = "๐Ÿ•›" + map[":clock130:"] = "๐Ÿ•œ" + map[":clock1:"] = "๐Ÿ•" + map[":clock230:"] = "๐Ÿ•" + map[":clock2:"] = "๐Ÿ•‘" + map[":clock330:"] = "๐Ÿ•ž" + map[":clock3:"] = "๐Ÿ•’" + map[":clock430:"] = "๐Ÿ•Ÿ" + map[":clock4:"] = "๐Ÿ•“" + map[":clock530:"] = "๐Ÿ• " + map[":clock5:"] = "๐Ÿ•”" + map[":clock630:"] = "๐Ÿ•ก" + map[":clock6:"] = "๐Ÿ••" + map[":clock730:"] = "๐Ÿ•ข" + map[":clock7:"] = "๐Ÿ•–" + map[":clock830:"] = "๐Ÿ•ฃ" + map[":clock8:"] = "๐Ÿ•—" + map[":clock930:"] = "๐Ÿ•ค" + map[":clock9:"] = "๐Ÿ•˜" + map[":closed_book:"] = "๐Ÿ“•" + map[":closed_lock_with_key:"] = "๐Ÿ”" + map[":closed_umbrella:"] = "๐ŸŒ‚" + map[":cloud:"] = "โ˜๏ธ" + map[":clubs:"] = "โ™ฃ๏ธ" + map[":cn:"] = "๐Ÿ‡จ๐Ÿ‡ณ" + map[":cocktail:"] = "๐Ÿธ" + map[":coffee:"] = "โ˜•" + map[":cold_sweat:"] = "๐Ÿ˜ฐ" + map[":computer:"] = "๐Ÿ’ป" + map[":confetti_ball:"] = "๐ŸŽŠ" + map[":confounded:"] = "๐Ÿ˜–" + map[":confused:"] = "๐Ÿ˜•" + map[":congratulations:"] = "ใŠ—๏ธ" + map[":construction:"] = "๐Ÿšง" + map[":construction_worker:"] = "๐Ÿ‘ท" + map[":convenience_store:"] = "๐Ÿช" + map[":cookie:"] = "๐Ÿช" + map[":cool:"] = "๐Ÿ†’" + map[":cop:"] = "๐Ÿ‘ฎ" + map[":copyright:"] = "ยฉ๏ธ" + map[":corn:"] = "๐ŸŒฝ" + map[":couple:"] = "๐Ÿ‘ซ" + map[":couple_with_heart:"] = "๐Ÿ’‘" + map[":couplekiss:"] = "๐Ÿ’" + map[":cow2:"] = "๐Ÿ„" + map[":cow:"] = "๐Ÿฎ" + map[":credit_card:"] = "๐Ÿ’ณ" + map[":crocodile:"] = "๐ŸŠ" + map[":crossed_flags:"] = "๐ŸŽŒ" + map[":crown:"] = "๐Ÿ‘‘" + map[":cry:"] = "๐Ÿ˜ข" + map[":crying_cat_face:"] = "๐Ÿ˜ฟ" + map[":crystal_ball:"] = "๐Ÿ”ฎ" + map[":cupid:"] = "๐Ÿ’˜" + map[":curly_loop:"] = "โžฐ" + map[":currency_exchange:"] = "๐Ÿ’ฑ" + map[":curry:"] = "๐Ÿ›" + map[":custard:"] = "๐Ÿฎ" + map[":customs:"] = "๐Ÿ›ƒ" + map[":cyclone:"] = "๐ŸŒ€" + map[":dancer:"] = "๐Ÿ’ƒ" + map[":dancers:"] = "๐Ÿ‘ฏ" + map[":dango:"] = "๐Ÿก" + map[":dart:"] = "๐ŸŽฏ" + map[":dash:"] = "๐Ÿ’จ" + map[":date:"] = "๐Ÿ“…" + map[":de:"] = "๐Ÿ‡ฉ๐Ÿ‡ช" + map[":deciduous_tree:"] = "๐ŸŒณ" + map[":department_store:"] = "๐Ÿฌ" + map[":diamond_shape_with_a_dot_inside:"] = "๐Ÿ’ " + map[":diamonds:"] = "โ™ฆ๏ธ" + map[":disappointed:"] = "๐Ÿ˜ž" + map[":disappointed_relieved:"] = "๐Ÿ˜ฅ" + map[":dizzy:"] = "๐Ÿ’ซ" + map[":dizzy_face:"] = "๐Ÿ˜ต" + map[":do_not_litter:"] = "๐Ÿšฏ" + map[":dog2:"] = "๐Ÿ•" + map[":dog:"] = "๐Ÿถ" + map[":dollar:"] = "๐Ÿ’ต" + map[":dolls:"] = "๐ŸŽŽ" + map[":dolphin:"] = "๐Ÿฌ" + map[":door:"] = "๐Ÿšช" + map[":doughnut:"] = "๐Ÿฉ" + map[":dragon:"] = "๐Ÿ‰" + map[":dragon_face:"] = "๐Ÿฒ" + map[":dress:"] = "๐Ÿ‘—" + map[":dromedary_camel:"] = "๐Ÿช" + map[":droplet:"] = "๐Ÿ’ง" + map[":dvd:"] = "๐Ÿ“€" + map[":ear:"] = "๐Ÿ‘‚" + map[":ear_of_rice:"] = "๐ŸŒพ" + map[":earth_africa:"] = "๐ŸŒ" + map[":earth_americas:"] = "๐ŸŒŽ" + map[":earth_asia:"] = "๐ŸŒ" + map[":egg:"] = "๐Ÿฅš" + map[":eggplant:"] = "๐Ÿ†" + map[":eight:"] = "8๏ธโƒฃ" + map[":eight_pointed_black_star:"] = "โœด๏ธ" + map[":eight_spoked_asterisk:"] = "โœณ๏ธ" + map[":electric_plug:"] = "๐Ÿ”Œ" + map[":elephant:"] = "๐Ÿ˜" + map[":email:"] = "๐Ÿ“ง" + map[":end:"] = "๐Ÿ”š" + map[":envelope:"] = "โœ‰๏ธ" + map[":es:"] = "๐Ÿ‡ช๐Ÿ‡ธ" + map[":euro:"] = "๐Ÿ’ถ" + map[":european_castle:"] = "๐Ÿฐ" + map[":european_post_office:"] = "๐Ÿค" + map[":evergreen_tree:"] = "๐ŸŒฒ" + map[":exclamation:"] = "โ—" + map[":expressionless:"] = "๐Ÿ˜‘" + map[":eyeglasses:"] = "๐Ÿ‘“" + map[":eyes:"] = "๐Ÿ‘€" + map[":factory:"] = "๐Ÿญ" + map[":fallen_leaf:"] = "๐Ÿ‚" + map[":family:"] = "๐Ÿ‘ช" + map[":fast_forward:"] = "โฉ" + map[":fax:"] = "๐Ÿ“ " + map[":fearful:"] = "๐Ÿ˜จ" + map[":feet:"] = "๐Ÿพ" + map[":ferris_wheel:"] = "๐ŸŽก" + map[":file_folder:"] = "๐Ÿ“" + map[":fire:"] = "๐Ÿ”ฅ" + map[":fire_engine:"] = "๐Ÿš’" + map[":fireworks:"] = "๐ŸŽ†" + map[":first_quarter_moon:"] = "๐ŸŒ“" + map[":first_quarter_moon_with_face:"] = "๐ŸŒ›" + map[":fish:"] = "๐ŸŸ" + map[":fish_cake:"] = "๐Ÿฅ" + map[":fishing_pole_and_fish:"] = "๐ŸŽฃ" + map[":fist:"] = "โœŠ" + map[":five:"] = "5๏ธโƒฃ" + map[":flags:"] = "๐ŸŽ" + map[":flashlight:"] = "๐Ÿ”ฆ" + map[":floppy_disk:"] = "๐Ÿ’พ" + map[":flower_playing_cards:"] = "๐ŸŽด" + map[":flushed:"] = "๐Ÿ˜ณ" + map[":foggy:"] = "๐ŸŒ" + map[":football:"] = "๐Ÿˆ" + map[":fork_and_knife:"] = "๐Ÿด" + map[":fountain:"] = "โ›ฒ" + map[":four:"] = "4๏ธโƒฃ" + map[":four_leaf_clover:"] = "๐Ÿ€" + map[":fr:"] = "๐Ÿ‡ซ๐Ÿ‡ท" + map[":free:"] = "๐Ÿ†“" + map[":fried_shrimp:"] = "๐Ÿค" + map[":fries:"] = "๐ŸŸ" + map[":frog:"] = "๐Ÿธ" + map[":frowning:"] = "๐Ÿ˜ฆ" + map[":fuelpump:"] = "โ›ฝ" + map[":full_moon:"] = "๐ŸŒ•" + map[":full_moon_with_face:"] = "๐ŸŒ" + map[":game_die:"] = "๐ŸŽฒ" + map[":gem:"] = "๐Ÿ’Ž" + map[":gemini:"] = "โ™Š" + map[":ghost:"] = "๐Ÿ‘ป" + map[":gift:"] = "๐ŸŽ" + map[":gift_heart:"] = "๐Ÿ’" + map[":girl:"] = "๐Ÿ‘ง" + map[":globe_with_meridians:"] = "๐ŸŒ" + map[":goat:"] = "๐Ÿ" + map[":golf:"] = "โ›ณ" + map[":grapes:"] = "๐Ÿ‡" + map[":green_apple:"] = "๐Ÿ" + map[":green_book:"] = "๐Ÿ“—" + map[":green_heart:"] = "๐Ÿ’š" + map[":grey_exclamation:"] = "โ•" + map[":grey_question:"] = "โ”" + map[":grimacing:"] = "๐Ÿ˜ฌ" + map[":grin:"] = "๐Ÿ˜" + map[":grinning:"] = "๐Ÿ˜€" + map[":guardsman:"] = "๐Ÿ’‚โ€โ™‚๏ธ" + map[":guitar:"] = "๐ŸŽธ" + map[":gun:"] = "๐Ÿ”ซ" + map[":haircut:"] = "๐Ÿ’‡" + map[":hamburger:"] = "๐Ÿ”" + map[":hammer:"] = "๐Ÿ”จ" + map[":hamster:"] = "๐Ÿน" + map[":handbag:"] = "๐Ÿ‘œ" + map[":hankey:"] = "๐Ÿ’ฉ" + map[":hash:"] = "#๏ธโƒฃ" + map[":hatched_chick:"] = "๐Ÿฅ" + map[":hatching_chick:"] = "๐Ÿฃ" + map[":headphones:"] = "๐ŸŽง" + map[":hear_no_evil:"] = "๐Ÿ™‰" + map[":heart:"] = "โค๏ธ" + map[":heart_decoration:"] = "๐Ÿ’Ÿ" + map[":heart_eyes:"] = "๐Ÿ˜" + map[":heart_eyes_cat:"] = "๐Ÿ˜ป" + map[":heartbeat:"] = "๐Ÿ’“" + map[":hearts:"] = "โ™ฅ๏ธ" + map[":heavy_check_mark:"] = "โœ”๏ธ" + map[":heavy_division_sign:"] = "โž—" + map[":heavy_dollar_sign:"] = "๐Ÿ’ฒ" + map[":heavy_minus_sign:"] = "โž–" + map[":heavy_multiplication_x:"] = "โœ–๏ธ" + map[":heavy_plus_sign:"] = "โž•" + map[":helicopter:"] = "๐Ÿš" + map[":herb:"] = "๐ŸŒฟ" + map[":hibiscus:"] = "๐ŸŒบ" + map[":high_brightness:"] = "๐Ÿ”†" + map[":high_heel:"] = "๐Ÿ‘ " + map[":honey_pot:"] = "๐Ÿฏ" + map[":horse:"] = "๐Ÿด" + map[":horse_racing:"] = "๐Ÿ‡" + map[":hospital:"] = "๐Ÿฅ" + map[":hotel:"] = "๐Ÿจ" + map[":hotsprings:"] = "โ™จ๏ธ" + map[":hourglass:"] = "โŒ›" + map[":hourglass_flowing_sand:"] = "โณ" + map[":house:"] = "๐Ÿ " + map[":house_with_garden:"] = "๐Ÿก" + map[":hushed:"] = "๐Ÿ˜ฏ" + map[":ice_cream:"] = "๐Ÿจ" + map[":icecream:"] = "๐Ÿฆ" + map[":id:"] = "๐Ÿ†”" + map[":ideograph_advantage:"] = "๐Ÿ‰" + map[":imp:"] = "๐Ÿ‘ฟ" + map[":inbox_tray:"] = "๐Ÿ“ฅ" + map[":incoming_envelope:"] = "๐Ÿ“จ" + map[":information_desk_person:"] = "๐Ÿ’" + map[":information_source:"] = "โ„น๏ธ" + map[":innocent:"] = "๐Ÿ˜‡" + map[":interrobang:"] = "โ‰๏ธ" + map[":iphone:"] = "๐Ÿ“ฑ" + map[":it:"] = "๐Ÿ‡ฎ๐Ÿ‡น" + map[":izakaya_lantern:"] = "๐Ÿฎ" + map[":jack_o_lantern:"] = "๐ŸŽƒ" + map[":japan:"] = "๐Ÿ—พ" + map[":japanese_castle:"] = "๐Ÿฏ" + map[":japanese_goblin:"] = "๐Ÿ‘บ" + map[":japanese_ogre:"] = "๐Ÿ‘น" + map[":jeans:"] = "๐Ÿ‘–" + map[":joy:"] = "๐Ÿ˜‚" + map[":joy_cat:"] = "๐Ÿ˜น" + map[":jp:"] = "๐Ÿ‡ฏ๐Ÿ‡ต" + map[":key:"] = "๐Ÿ”‘" + map[":keycap_ten:"] = "๐Ÿ”Ÿ" + map[":kimono:"] = "๐Ÿ‘˜" + map[":kiss:"] = "๐Ÿ’‹" + map[":kissing:"] = "๐Ÿ˜—" + map[":kissing_cat:"] = "๐Ÿ˜ฝ" + map[":kissing_closed_eyes:"] = "๐Ÿ˜š" + map[":kissing_heart:"] = "๐Ÿ˜˜" + map[":kissing_smiling_eyes:"] = "๐Ÿ˜™" + map[":koala:"] = "๐Ÿจ" + map[":koko:"] = "๐Ÿˆ" + map[":kr:"] = "๐Ÿ‡ฐ๐Ÿ‡ท" + map[":large_blue_diamond:"] = "๐Ÿ”ท" + map[":large_orange_diamond:"] = "๐Ÿ”ถ" + map[":last_quarter_moon:"] = "๐ŸŒ—" + map[":last_quarter_moon_with_face:"] = "๐ŸŒœ" + map[":laughing:"] = "๐Ÿ˜†" + map[":leaves:"] = "๐Ÿƒ" + map[":ledger:"] = "๐Ÿ“’" + map[":left_luggage:"] = "๐Ÿ›…" + map[":left_right_arrow:"] = "โ†”๏ธ" + map[":leftwards_arrow_with_hook:"] = "โ†ฉ๏ธ" + map[":lemon:"] = "๐Ÿ‹" + map[":leo:"] = "โ™Œ" + map[":leopard:"] = "๐Ÿ†" + map[":libra:"] = "โ™Ž" + map[":light_rail:"] = "๐Ÿšˆ" + map[":link:"] = "๐Ÿ”—" + map[":lips:"] = "๐Ÿ‘„" + map[":lipstick:"] = "๐Ÿ’„" + map[":lock:"] = "๐Ÿ”’" + map[":lock_with_ink_pen:"] = "๐Ÿ”" + map[":lollipop:"] = "๐Ÿญ" + map[":loop:"] = "โžฟ" + map[":loudspeaker:"] = "๐Ÿ“ข" + map[":love_hotel:"] = "๐Ÿฉ" + map[":love_letter:"] = "๐Ÿ’Œ" + map[":low_brightness:"] = "๐Ÿ”…" + map[":m:"] = "โ“‚๏ธ" + map[":mag:"] = "๐Ÿ”" + map[":mag_right:"] = "๐Ÿ”Ž" + map[":mahjong:"] = "๐Ÿ€„" + map[":mailbox:"] = "๐Ÿ“ซ" + map[":mailbox_closed:"] = "๐Ÿ“ช" + map[":mailbox_with_mail:"] = "๐Ÿ“ฌ" + map[":mailbox_with_no_mail:"] = "๐Ÿ“ญ" + map[":man:"] = "๐Ÿ‘จ" + map[":man_with_gua_pi_mao:"] = "๐Ÿ‘ฒ" + map[":man_with_turban:"] = "๐Ÿ‘ณโ€โ™‚๏ธ" + map[":mans_shoe:"] = "๐Ÿ‘ž" + map[":maple_leaf:"] = "๐Ÿ" + map[":mask:"] = "๐Ÿ˜ท" + map[":massage:"] = "๐Ÿ’†" + map[":meat_on_bone:"] = "๐Ÿ–" + map[":mega:"] = "๐Ÿ“ฃ" + map[":melon:"] = "๐Ÿˆ" + map[":memo:"] = "๐Ÿ“" + map[":mens:"] = "๐Ÿšน" + map[":metal:"] = "๐Ÿค˜" + map[":metro:"] = "๐Ÿš‡" + map[":microphone:"] = "๐ŸŽค" + map[":microscope:"] = "๐Ÿ”ฌ" + map[":milky_way:"] = "๐ŸŒŒ" + map[":minibus:"] = "๐Ÿš" + map[":minidisc:"] = "๐Ÿ’ฝ" + map[":mobile_phone_off:"] = "๐Ÿ“ด" + map[":money_with_wings:"] = "๐Ÿ’ธ" + map[":moneybag:"] = "๐Ÿ’ฐ" + map[":monkey:"] = "๐Ÿ’" + map[":monkey_face:"] = "๐Ÿต" + map[":monorail:"] = "๐Ÿš" + map[":mortar_board:"] = "๐ŸŽ“" + map[":mount_fuji:"] = "๐Ÿ—ป" + map[":mountain_bicyclist:"] = "๐Ÿšต" + map[":mountain_cableway:"] = "๐Ÿš " + map[":mountain_railway:"] = "๐Ÿšž" + map[":mouse2:"] = "๐Ÿ" + map[":mouse:"] = "๐Ÿญ" + map[":movie_camera:"] = "๐ŸŽฅ" + map[":moyai:"] = "๐Ÿ—ฟ" + map[":muscle:"] = "๐Ÿ’ช" + map[":mushroom:"] = "๐Ÿ„" + map[":musical_keyboard:"] = "๐ŸŽน" + map[":musical_note:"] = "๐ŸŽต" + map[":musical_score:"] = "๐ŸŽผ" + map[":mute:"] = "๐Ÿ”‡" + map[":nail_care:"] = "๐Ÿ’…" + map[":name_badge:"] = "๐Ÿ“›" + map[":necktie:"] = "๐Ÿ‘”" + map[":negative_squared_cross_mark:"] = "โŽ" + map[":neutral_face:"] = "๐Ÿ˜" + map[":new:"] = "๐Ÿ†•" + map[":new_moon:"] = "๐ŸŒ‘" + map[":new_moon_with_face:"] = "๐ŸŒš" + map[":newspaper:"] = "๐Ÿ“ฐ" + map[":ng:"] = "๐Ÿ†–" + map[":nine:"] = "9๏ธโƒฃ" + map[":no_bell:"] = "๐Ÿ”•" + map[":no_bicycles:"] = "๐Ÿšณ" + map[":no_entry:"] = "โ›”" + map[":no_entry_sign:"] = "๐Ÿšซ" + map[":no_good:"] = "๐Ÿ™…" + map[":no_mobile_phones:"] = "๐Ÿ“ต" + map[":no_mouth:"] = "๐Ÿ˜ถ" + map[":no_pedestrians:"] = "๐Ÿšท" + map[":no_smoking:"] = "๐Ÿšญ" + map[":nose:"] = "๐Ÿ‘ƒ" + map[":notebook:"] = "๐Ÿ““" + map[":notebook_with_decorative_cover:"] = "๐Ÿ“”" + map[":notes:"] = "๐ŸŽถ" + map[":nut_and_bolt:"] = "๐Ÿ”ฉ" + map[":o2:"] = "๐Ÿ…พ๏ธ" + map[":o:"] = "โญ•" + map[":ocean:"] = "๐ŸŒŠ" + map[":octopus:"] = "๐Ÿ™" + map[":oden:"] = "๐Ÿข" + map[":office:"] = "๐Ÿข" + map[":ok:"] = "๐Ÿ†—" + map[":ok_hand:"] = "๐Ÿ‘Œ" + map[":ok_woman:"] = "๐Ÿ™†โ€โ™€๏ธ" + map[":older_man:"] = "๐Ÿ‘ด" + map[":older_woman:"] = "๐Ÿ‘ต" + map[":on:"] = "๐Ÿ”›" + map[":oncoming_automobile:"] = "๐Ÿš˜" + map[":oncoming_bus:"] = "๐Ÿš" + map[":oncoming_police_car:"] = "๐Ÿš”" + map[":oncoming_taxi:"] = "๐Ÿš–" + map[":one:"] = "1๏ธโƒฃ" + map[":open_file_folder:"] = "๐Ÿ“‚" + map[":open_hands:"] = "๐Ÿ‘" + map[":open_mouth:"] = "๐Ÿ˜ฎ" + map[":ophiuchus:"] = "โ›Ž" + map[":orange_book:"] = "๐Ÿ“™" + map[":outbox_tray:"] = "๐Ÿ“ค" + map[":ox:"] = "๐Ÿ‚" + map[":page_facing_up:"] = "๐Ÿ“„" + map[":page_with_curl:"] = "๐Ÿ“ƒ" + map[":pager:"] = "๐Ÿ“Ÿ" + map[":palm_tree:"] = "๐ŸŒด" + map[":panda_face:"] = "๐Ÿผ" + map[":paperclip:"] = "๐Ÿ“Ž" + map[":parking:"] = "๐Ÿ…ฟ๏ธ" + map[":part_alternation_mark:"] = "ใ€ฝ๏ธ" + map[":partly_sunny:"] = "โ›…" + map[":passport_control:"] = "๐Ÿ›‚" + map[":paw_prints:"] = "๐Ÿพ" + map[":peach:"] = "๐Ÿ‘" + map[":pear:"] = "๐Ÿ" + map[":pencil2:"] = "โœ๏ธ" + map[":pencil:"] = "๐Ÿ“" + map[":penguin:"] = "๐Ÿง" + map[":pensive:"] = "๐Ÿ˜”" + map[":performing_arts:"] = "๐ŸŽญ" + map[":persevere:"] = "๐Ÿ˜ฃ" + map[":pig2:"] = "๐Ÿ–" + map[":pig:"] = "๐Ÿท" + map[":pig_nose:"] = "๐Ÿฝ" + map[":pill:"] = "๐Ÿ’Š" + map[":pineapple:"] = "๐Ÿ" + map[":pisces:"] = "โ™“" + map[":pizza:"] = "๐Ÿ•" + map[":point_down:"] = "๐Ÿ‘‡" + map[":point_left:"] = "๐Ÿ‘ˆ" + map[":point_right:"] = "๐Ÿ‘‰" + map[":point_up:"] = "โ˜๏ธ" + map[":point_up_2:"] = "๐Ÿ‘†" + map[":police_car:"] = "๐Ÿš“" + map[":poodle:"] = "๐Ÿฉ" + map[":poop:"] = "๐Ÿ’ฉ" + map[":post_office:"] = "๐Ÿฃ" + map[":postal_horn:"] = "๐Ÿ“ฏ" + map[":postbox:"] = "๐Ÿ“ฎ" + map[":potable_water:"] = "๐Ÿšฐ" + map[":pouch:"] = "๐Ÿ‘" + map[":poultry_leg:"] = "๐Ÿ—" + map[":pound:"] = "๐Ÿ’ท" + map[":pouting_cat:"] = "๐Ÿ˜พ" + map[":pray:"] = "๐Ÿ™" + map[":princess:"] = "๐Ÿ‘ธ" + map[":punch:"] = "๐Ÿ‘Š" + map[":purple_heart:"] = "๐Ÿ’œ" + map[":purse:"] = "๐Ÿ‘›" + map[":pushpin:"] = "๐Ÿ“Œ" + map[":put_litter_in_its_place:"] = "๐Ÿšฎ" + map[":question:"] = "โ“" + map[":rabbit2:"] = "๐Ÿ‡" + map[":rabbit:"] = "๐Ÿฐ" + map[":racehorse:"] = "๐ŸŽ" + map[":radio:"] = "๐Ÿ“ป" + map[":radio_button:"] = "๐Ÿ”˜" + map[":rage:"] = "๐Ÿ˜ก" + map[":railway_car:"] = "๐Ÿšƒ" + map[":rainbow:"] = "๐ŸŒˆ" + map[":raised_hand:"] = "โœ‹" + map[":raised_hands:"] = "๐Ÿ™Œ" + map[":raising_hand:"] = "๐Ÿ™‹" + map[":ram:"] = "๐Ÿ" + map[":ramen:"] = "๐Ÿœ" + map[":rat:"] = "๐Ÿ€" + map[":recycle:"] = "โ™ป๏ธ" + map[":red_car:"] = "๐Ÿš—" + map[":red_circle:"] = "๐Ÿ”ด" + map[":registered:"] = "ยฎ๏ธ" + map[":relaxed:"] = "โ˜บ๏ธ" + map[":relieved:"] = "๐Ÿ˜Œ" + map[":repeat:"] = "๐Ÿ”" + map[":repeat_one:"] = "๐Ÿ”‚" + map[":restroom:"] = "๐Ÿšป" + map[":revolving_hearts:"] = "๐Ÿ’ž" + map[":rewind:"] = "โช" + map[":ribbon:"] = "๐ŸŽ€" + map[":rice:"] = "๐Ÿš" + map[":rice_ball:"] = "๐Ÿ™" + map[":rice_cracker:"] = "๐Ÿ˜" + map[":rice_scene:"] = "๐ŸŽ‘" + map[":ring:"] = "๐Ÿ’" + map[":rocket:"] = "๐Ÿš€" + map[":roller_coaster:"] = "๐ŸŽข" + map[":rooster:"] = "๐Ÿ“" + map[":rose:"] = "๐ŸŒน" + map[":rotating_light:"] = "๐Ÿšจ" + map[":round_pushpin:"] = "๐Ÿ“" + map[":rowboat:"] = "๐Ÿšฃ" + map[":ru:"] = "๐Ÿ‡ท๐Ÿ‡บ" + map[":rugby_football:"] = "๐Ÿ‰" + map[":runner:"] = "๐Ÿƒ" + map[":running_shirt_with_sash:"] = "๐ŸŽฝ" + map[":sa:"] = "๐Ÿˆ‚๏ธ" + map[":sagittarius:"] = "โ™" + map[":sailboat:"] = "โ›ต" + map[":sake:"] = "๐Ÿถ" + map[":sandal:"] = "๐Ÿ‘ก" + map[":santa:"] = "๐ŸŽ…" + map[":satellite:"] = "๐Ÿ“ก" + map[":satisfied:"] = "๐Ÿ˜†" + map[":saxophone:"] = "๐ŸŽท" + map[":school:"] = "๐Ÿซ" + map[":school_satchel:"] = "๐ŸŽ’" + map[":scissors:"] = "โœ‚๏ธ" + map[":scorpius:"] = "โ™" + map[":scream:"] = "๐Ÿ˜ฑ" + map[":scream_cat:"] = "๐Ÿ™€" + map[":scroll:"] = "๐Ÿ“œ" + map[":seat:"] = "๐Ÿ’บ" + map[":secret:"] = "ใŠ™๏ธ" + map[":see_no_evil:"] = "๐Ÿ™ˆ" + map[":seedling:"] = "๐ŸŒฑ" + map[":seven:"] = "7๏ธโƒฃ" + map[":shaved_ice:"] = "๐Ÿง" + map[":sheep:"] = "๐Ÿ‘" + map[":shell:"] = "๐Ÿš" + map[":ship:"] = "๐Ÿšข" + map[":shirt:"] = "๐Ÿ‘•" + map[":shit:"] = "๐Ÿ’ฉ" + map[":shower:"] = "๐Ÿšฟ" + map[":signal_strength:"] = "๐Ÿ“ถ" + map[":six:"] = "6๏ธโƒฃ" + map[":six_pointed_star:"] = "๐Ÿ”ฏ" + map[":ski:"] = "๐ŸŽฟ" + map[":skull:"] = "๐Ÿ’€" + map[":sleeping:"] = "๐Ÿ˜ด" + map[":sleepy:"] = "๐Ÿ˜ช" + map[":slot_machine:"] = "๐ŸŽฐ" + map[":small_blue_diamond:"] = "๐Ÿ”น" + map[":small_orange_diamond:"] = "๐Ÿ”ธ" + map[":small_red_triangle:"] = "๐Ÿ”บ" + map[":small_red_triangle_down:"] = "๐Ÿ”ป" + map[":smile:"] = "๐Ÿ˜„" + map[":smile_cat:"] = "๐Ÿ˜ธ" + map[":smiley:"] = "๐Ÿ˜ƒ" + map[":smiley_cat:"] = "๐Ÿ˜บ" + map[":smiling_imp:"] = "๐Ÿ˜ˆ" + map[":smirk:"] = "๐Ÿ˜" + map[":smirk_cat:"] = "๐Ÿ˜ผ" + map[":smoking:"] = "๐Ÿšฌ" + map[":snail:"] = "๐ŸŒ" + map[":snake:"] = "๐Ÿ" + map[":snowboarder:"] = "๐Ÿ‚" + map[":snowflake:"] = "โ„๏ธ" + map[":snowman:"] = "โ›„" + map[":sob:"] = "๐Ÿ˜ญ" + map[":soccer:"] = "โšฝ" + map[":soon:"] = "๐Ÿ”œ" + map[":sos:"] = "๐Ÿ†˜" + map[":sound:"] = "๐Ÿ”‰" + map[":space_invader:"] = "๐Ÿ‘พ" + map[":spades:"] = "โ™ ๏ธ" + map[":spaghetti:"] = "๐Ÿ" + map[":sparkler:"] = "๐ŸŽ‡" + map[":sparkles:"] = "โœจ" + map[":sparkling_heart:"] = "๐Ÿ’–" + map[":speak_no_evil:"] = "๐Ÿ™Š" + map[":speaker:"] = "๐Ÿ”ˆ" + map[":speech_balloon:"] = "๐Ÿ’ฌ" + map[":speedboat:"] = "๐Ÿšค" + map[":star2:"] = "๐ŸŒŸ" + map[":star:"] = "โญ" + map[":stars:"] = "๐ŸŒ " + map[":station:"] = "๐Ÿš‰" + map[":statue_of_liberty:"] = "๐Ÿ—ฝ" + map[":steam_locomotive:"] = "๐Ÿš‚" + map[":stew:"] = "๐Ÿฒ" + map[":straight_ruler:"] = "๐Ÿ“" + map[":strawberry:"] = "๐Ÿ“" + map[":stuck_out_tongue:"] = "๐Ÿ˜›" + map[":stuck_out_tongue_closed_eyes:"] = "๐Ÿ˜" + map[":stuck_out_tongue_winking_eye:"] = "๐Ÿ˜œ" + map[":sun_with_face:"] = "๐ŸŒž" + map[":sunflower:"] = "๐ŸŒป" + map[":sunglasses:"] = "๐Ÿ˜Ž" + map[":sunny:"] = "โ˜€๏ธ" + map[":sunrise:"] = "๐ŸŒ…" + map[":sunrise_over_mountains:"] = "๐ŸŒ„" + map[":surfer:"] = "๐Ÿ„" + map[":sushi:"] = "๐Ÿฃ" + map[":suspension_railway:"] = "๐ŸšŸ" + map[":sweat:"] = "๐Ÿ˜“" + map[":sweat_drops:"] = "๐Ÿ’ฆ" + map[":sweat_smile:"] = "๐Ÿ˜…" + map[":sweet_potato:"] = "๐Ÿ " + map[":swimmer:"] = "๐ŸŠ" + map[":symbols:"] = "๐Ÿ”ฃ" + map[":syringe:"] = "๐Ÿ’‰" + map[":tada:"] = "๐ŸŽ‰" + map[":tanabata_tree:"] = "๐ŸŽ‹" + map[":tangerine:"] = "๐ŸŠ" + map[":taurus:"] = "โ™‰" + map[":taxi:"] = "๐Ÿš•" + map[":tea:"] = "๐Ÿต" + map[":telephone:"] = "โ˜Ž๏ธ" + map[":telephone_receiver:"] = "๐Ÿ“ž" + map[":telescope:"] = "๐Ÿ”ญ" + map[":tennis:"] = "๐ŸŽพ" + map[":tent:"] = "โ›บ" + map[":thought_balloon:"] = "๐Ÿ’ญ" + map[":three:"] = "3๏ธโƒฃ" + map[":thumbsdown:"] = "๐Ÿ‘Ž" + map[":thumbsup:"] = "๐Ÿ‘" + map[":ticket:"] = "๐ŸŽซ" + map[":tiger2:"] = "๐Ÿ…" + map[":tiger:"] = "๐Ÿฏ" + map[":tired_face:"] = "๐Ÿ˜ซ" + map[":tm:"] = "โ„ข๏ธ" + map[":toilet:"] = "๐Ÿšฝ" + map[":tokyo_tower:"] = "๐Ÿ—ผ" + map[":tomato:"] = "๐Ÿ…" + map[":tongue:"] = "๐Ÿ‘…" + map[":top:"] = "๐Ÿ”" + map[":tophat:"] = "๐ŸŽฉ" + map[":tractor:"] = "๐Ÿšœ" + map[":traffic_light:"] = "๐Ÿšฅ" + map[":train2:"] = "๐Ÿš†" + map[":train:"] = "๐Ÿš‹" + map[":tram:"] = "๐ŸšŠ" + map[":triangular_flag_on_post:"] = "๐Ÿšฉ" + map[":triangular_ruler:"] = "๐Ÿ“" + map[":trident:"] = "๐Ÿ”ฑ" + map[":triumph:"] = "๐Ÿ˜ค" + map[":trolleybus:"] = "๐ŸšŽ" + map[":trophy:"] = "๐Ÿ†" + map[":tropical_drink:"] = "๐Ÿน" + map[":tropical_fish:"] = "๐Ÿ " + map[":truck:"] = "๐Ÿšš" + map[":trumpet:"] = "๐ŸŽบ" + map[":tulip:"] = "๐ŸŒท" + map[":turtle:"] = "๐Ÿข" + map[":tv:"] = "๐Ÿ“บ" + map[":twisted_rightwards_arrows:"] = "๐Ÿ”€" + map[":two:"] = "2๏ธโƒฃ" + map[":two_men_holding_hands:"] = "๐Ÿ‘ฌ" + map[":two_women_holding_hands:"] = "๐Ÿ‘ญ" + map[":u5272:"] = "๐Ÿˆน" + map[":u5408:"] = "๐Ÿˆด" + map[":u55b6:"] = "๐Ÿˆบ" + map[":u6307:"] = "๐Ÿˆฏ" + map[":u6708:"] = "๐Ÿˆท๏ธ" + map[":u6709:"] = "๐Ÿˆถ" + map[":u6e80:"] = "๐Ÿˆต" + map[":u7121:"] = "๐Ÿˆš" + map[":u7533:"] = "๐Ÿˆธ" + map[":u7981:"] = "๐Ÿˆฒ" + map[":u7a7a:"] = "๐Ÿˆณ" + map[":umbrella:"] = "โ˜”" + map[":unamused:"] = "๐Ÿ˜’" + map[":underage:"] = "๐Ÿ”ž" + map[":unlock:"] = "๐Ÿ”“" + map[":up:"] = "๐Ÿ†™" + map[":us:"] = "๐Ÿ‡บ๐Ÿ‡ธ" + map[":v:"] = "โœŒ๏ธ" + map[":vertical_traffic_light:"] = "๐Ÿšฆ" + map[":vhs:"] = "๐Ÿ“ผ" + map[":vibration_mode:"] = "๐Ÿ“ณ" + map[":video_camera:"] = "๐Ÿ“น" + map[":video_game:"] = "๐ŸŽฎ" + map[":violin:"] = "๐ŸŽป" + map[":virgo:"] = "โ™" + map[":volcano:"] = "๐ŸŒ‹" + map[":vs:"] = "๐Ÿ†š" + map[":walking:"] = "๐Ÿšถ" + map[":waning_crescent_moon:"] = "๐ŸŒ˜" + map[":waning_gibbous_moon:"] = "๐ŸŒ–" + map[":warning:"] = "โš ๏ธ" + map[":watch:"] = "โŒš" + map[":water_buffalo:"] = "๐Ÿƒ" + map[":watermelon:"] = "๐Ÿ‰" + map[":wave:"] = "๐Ÿ‘‹" + map[":wavy_dash:"] = "ใ€ฐ๏ธ" + map[":waxing_crescent_moon:"] = "๐ŸŒ’" + map[":waxing_gibbous_moon:"] = "๐ŸŒ”" + map[":wc:"] = "๐Ÿšพ" + map[":weary:"] = "๐Ÿ˜ฉ" + map[":wedding:"] = "๐Ÿ’’" + map[":whale2:"] = "๐Ÿ‹" + map[":whale:"] = "๐Ÿณ" + map[":wheelchair:"] = "โ™ฟ" + map[":white_check_mark:"] = "โœ…" + map[":white_circle:"] = "โšช" + map[":white_flower:"] = "๐Ÿ’ฎ" + map[":white_square_button:"] = "๐Ÿ”ณ" + map[":wind_chime:"] = "๐ŸŽ" + map[":wine_glass:"] = "๐Ÿท" + map[":wink:"] = "๐Ÿ˜‰" + map[":wolf:"] = "๐Ÿบ" + map[":woman:"] = "๐Ÿ‘ฉ" + map[":womans_clothes:"] = "๐Ÿ‘š" + map[":womans_hat:"] = "๐Ÿ‘’" + map[":womens:"] = "๐Ÿšบ" + map[":worried:"] = "๐Ÿ˜Ÿ" + map[":wrench:"] = "๐Ÿ”ง" + map[":x:"] = "โŒ" + map[":yellow_heart:"] = "๐Ÿ’›" + map[":yen:"] = "๐Ÿ’ด" + map[":yum:"] = "๐Ÿ˜‹" + map[":zap:"] = "โšก" + map[":zero:"] = "0๏ธโƒฃ" + map[":zzz:"] = "๐Ÿ’ค" +} +{ + if ($0 ~ /
/) in_pre = 1
+    if (!in_pre) {
+        code_count = 0
+        line = $0
+        out = ""
+        while (match(line, /[^<]*<\/code>/)) {
+            code_count++
+            code_store[code_count] = substr(line, RSTART, RLENGTH)
+            out = out substr(line, 1, RSTART - 1) "\034EC" code_count "\034"
+            line = substr(line, RSTART + RLENGTH)
+        }
+        out = out line
+
+        for (sc in map) {
+            if (index(out, sc)) {
+                gsub(sc, map[sc], out)
+            }
+        }
+
+        for (i = 1; i <= code_count; i++) {
+            gsub("\034EC" i "\034", code_store[i], out)
+        }
+        $0 = out
+    }
+    if ($0 ~ /<\/pre>/) in_pre = 0
+    print
+}
diff --git a/awk/footnotes.awk b/awk/footnotes.awk
new file mode 100644
index 0000000..79bd712
--- /dev/null
+++ b/awk/footnotes.awk
@@ -0,0 +1,51 @@
+BEGIN { fn_count = 0 }
+
+# Match [^id]: text
+/^\[\^[a-zA-Z0-9_-]+\]:/ {
+    id_start = index($0, "[^") + 2
+    id_end = index($0, "]:")
+    id = substr($0, id_start, id_end - id_start)
+    text = substr($0, id_end + 2)
+    # Trim leading space
+    sub(/^[ \t]+/, "", text)
+    
+    fn_ids[++fn_count] = id
+    fn_texts[id] = text
+    next
+}
+
+{
+    lines[++line_count] = $0
+}
+
+END {
+    for (i = 1; i <= line_count; i++) {
+        line = lines[i]
+        
+        for (j = 1; j <= fn_count; j++) {
+            id = fn_ids[j]
+            marker = "[^" id "]"
+            repl = "" id ""
+            
+            while ((pos = index(line, marker)) > 0) {
+                line = substr(line, 1, pos - 1) repl substr(line, pos + length(marker))
+            }
+        }
+        print line
+    }
+    
+    if (fn_count > 0) {
+        print "
" + print "
" + print "
    " + for (j = 1; j <= fn_count; j++) { + id = fn_ids[j] + text = fn_texts[id] + print "
  1. " + print "

    " text "

    " + print "
  2. " + } + print "
" + print "
" + } +} diff --git a/awk/markdown_inline.awk b/awk/markdown_inline.awk index 66e7ee7..9b05a7a 100644 --- a/awk/markdown_inline.awk +++ b/awk/markdown_inline.awk @@ -230,5 +230,7 @@ function restore_html_tags(s, i, val) { } } + gsub(/" in_p = 0 diff --git a/awk/toc.awk b/awk/toc.awk new file mode 100644 index 0000000..c35e2e1 --- /dev/null +++ b/awk/toc.awk @@ -0,0 +1,50 @@ +BEGIN { + toc_str = "
    \n" + has_toc = 0 +} +{ + lines[++n] = $0 + if ($0 ~ /
    /) in_pre = 1
    +    if (!in_pre && $0 ~ /\{\{TOC\}\}/) {
    +        has_toc = 1
    +        toc_lines[n] = 1
    +    }
    +    if ($0 ~ /<\/pre>/) in_pre = 0
    +    if (match($0, /]*>/)) {
    +        tag_len = RLENGTH
    +        title_start = RSTART + tag_len
    +        title_str = substr($0, title_start)
    +        title_end = index(title_str, " 0) {
    +            title = substr(title_str, 1, title_end - 1)
    +            gsub(/<[^>]+>/, "", title)
    +            
    +            # extract id
    +            id_start = match($0, /id="[^"]*"/)
    +            if (id_start > 0) {
    +                id_str = substr($0, id_start + 4)
    +                id_end = index(id_str, "\"")
    +                id = substr(id_str, 1, id_end - 1)
    +                
    +                # what tag? level
    +                level = substr($0, match($0, /" title "\n"
    +                } else if (level == "3") {
    +                    toc_str = toc_str "
  1. " title "
  2. \n" + } + } + } + } +} +END { + toc_str = toc_str "
" + for (i = 1; i <= n; i++) { + if (has_toc && toc_lines[i] && lines[i] ~ /^[[:space:]]*\{\{TOC\}\}[[:space:]]*$/) { + toc_lines[i] = 0 # Mark as processed if we want, but not strictly needed + sub(/\{\{TOC\}\}/, toc_str, lines[i]) + } + print lines[i] + } +} diff --git a/kewt.sh b/kewt.sh index 6928c6c..3633ab1 100755 --- a/kewt.sh +++ b/kewt.sh @@ -26,6 +26,8 @@ Options: --version Show version information. --from Source directory (default: site) --to Output directory (default: out) + --watch, -w Watch for file changes and rebuild automatically. + --serve, -s [port] Start a local HTTP server after building (default port: 8000). EOF } @@ -33,7 +35,8 @@ script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd) awk_dir="$script_dir/awk" KEWT_TMPDIR=$(mktemp -d "/tmp/kewt_run.XXXXXX") -trap 'rm -rf "$KEWT_TMPDIR"' EXIT HUP INT TERM +trap 'rm -rf "$KEWT_TMPDIR"' EXIT +trap 'exit 0' HUP INT TERM DEFAULT_CONF='title = "kewt" style = "kewt" @@ -59,6 +62,7 @@ base_url = "" generate_feed = false feed_file = "rss.xml" posts_dir = "" +posts_per_page = 12 custom_admonitions = ""' DEFAULT_TMPL=' @@ -73,8 +77,10 @@ DEFAULT_TMPL=' +

{{HEADER_BRAND}}

+
@@ -201,8 +207,6 @@ update_site() { exit 0 } - - src="" out="" new_mode="false" @@ -210,6 +214,8 @@ new_title="" post_mode="false" post_title="" positional_count=0 +watch_mode="false" +serve_mode="false" while [ $# -gt 0 ]; do case "$1" in @@ -261,6 +267,16 @@ while [ $# -gt 0 ]; do out="$2" shift ;; + --watch|-w) + watch_mode="true" + ;; + --serve|-s) + serve_mode="true" + if [ $# -ge 2 ] && echo "$2" | grep -qE '^[0-9]+$'; then + serve_port="$2" + shift + fi + ;; --*) die "Unknown option: $1" ;; @@ -427,6 +443,7 @@ base_url="" generate_feed="false" feed_file="rss.xml" posts_dir="" +posts_per_page="12" custom_admonitions="" load_config() { @@ -479,6 +496,7 @@ load_config() { generate_feed) generate_feed="$val" ;; feed_file) feed_file="${val#/}" ;; posts_dir) posts_dir="${val#/}" ;; + posts_per_page) posts_per_page="$val" ;; custom_admonitions) custom_admonitions="$val" ;; esac done < "$1" @@ -521,11 +539,13 @@ parse_frontmatter() { fm_title="" fm_date="" fm_draft="" + fm_description="" while IFS='=' read -r _fk _fv; do case "$_fk" in title) fm_title="$_fv" ;; date) fm_date="$_fv" ;; draft) fm_draft="$_fv" ;; + description) fm_description="$_fv" ;; esac done < "$_fm_out" rm -f "$_fm_out" @@ -721,6 +741,22 @@ render_markdown() { fi fi + head_extra_og="" + if [ -n "$fm_description" ]; then + head_extra_og="$head_extra_og + " + fi + og_url="${base_url%/}${current_url}" + head_extra_og="$head_extra_og + " + + if [ -n "$head_extra" ]; then + head_extra="$head_extra + $head_extra_og" + else + head_extra="$head_extra_og" + fi + ENABLE_HEADER_LINKS="$enable_header_links" CUSTOM_ADMONITIONS="$custom_admonitions" MARKDOWN_SITE_ROOT="$src" MARKDOWN_FALLBACK_FILE="$script_dir/styles/$style.css" sh "$script_dir/markdown.sh" "$content_file" | AWK_CURRENT_URL="$current_url" AWK_TITLE="$page_title" AWK_NAV="$nav" AWK_FOOTER="$footer" AWK_STYLE_PATH="${style_path}${asset_version}" AWK_HEADER_BRAND="$header_brand" AWK_HEAD_EXTRA="$head_extra" awk -f "$awk_dir/render_template.awk" "$local_template" } @@ -736,6 +772,7 @@ needs_rebuild() { return 1 } +build_site() { echo "Building site from '$src' to '$out'..." eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while read -r dir; do @@ -883,29 +920,94 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while fi done - if [ "$has_custom_index" = "true" ]; then - awk ' - /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ { - while((getline line < "'"$temp_list"'") > 0) print line - close("'"$temp_list"'") - next - } - { print } - ' "$dir/index.md" > "$temp_index" - else - cat "$temp_list" >> "$temp_index" - fi - is_home="false"; [ "$dir" = "$src" ] && is_home="true" target_url="/$rel_dir/index.html" [ "$rel_dir" = "." ] && target_url="/index.html" - do_rebuild="false" - needs_rebuild "$dir" "$out_dir/index.html" && do_rebuild="true" - [ "$has_custom_index" = "true" ] && needs_rebuild "$dir/index.md" "$out_dir/index.html" && do_rebuild="true" + num_items=$(wc -l < "$temp_list") + if [ "$is_posts_dir" = "true" ] && [ -n "$posts_per_page" ] && [ "$posts_per_page" -gt 0 ] && [ "$num_items" -gt "$posts_per_page" ]; then + num_pages=$(( (num_items + posts_per_page - 1) / posts_per_page )) + for p in $(seq 1 $num_pages); do + chunk_list="$KEWT_TMPDIR/chunk.md" + start_line=$(( (p - 1) * posts_per_page + 1 )) + tail -n +$start_line "$temp_list" | head -n "$posts_per_page" > "$chunk_list" - if [ "$do_rebuild" = "true" ]; then - render_markdown "$temp_index" "$is_home" "$target_url" > "$out_dir/index.html" + base_url_dir="$(dirname "$target_url")" + [ "$base_url_dir" = "/" ] && base_url_dir="" + + nav_html="
" + if [ "$p" -gt 1 ]; then + if [ "$p" -eq 2 ]; then + nav_html="$nav_html « Prev " + else + nav_html="$nav_html « Prev " + fi + fi + nav_html="$nav_html Page $p of $num_pages " + if [ "$p" -lt "$num_pages" ]; then + nav_html="$nav_html Next » " + fi + nav_html="$nav_html
" + + echo "" >> "$chunk_list" + echo "$nav_html" >> "$chunk_list" + + temp_index_p="$KEWT_TMPDIR/index_p$p.md" + if [ "$has_custom_index" = "false" ]; then + display_dir="${rel_dir#.}" + [ -z "$display_dir" ] && display_dir="/" + echo "# Index of $display_dir" > "$temp_index_p" + echo "" >> "$temp_index_p" + else + : > "$temp_index_p" + fi + + if [ "$has_custom_index" = "true" ]; then + awk ' + /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ { + while((getline line < "'"$chunk_list"'") > 0) print line + close("'"$chunk_list"'") + next + } + { print } + ' "$dir/index.md" >> "$temp_index_p" + else + cat "$chunk_list" >> "$temp_index_p" + fi + + if [ "$p" -eq 1 ]; then + out_file="$out_dir/index.html" + target_url_p="$target_url" + else + out_file="$out_dir/page/$p/index.html" + target_url_p="$base_url_dir/page/$p/index.html" + mkdir -p "$(dirname "$out_file")" + fi + + render_markdown "$temp_index_p" "$is_home" "$target_url_p" > "$out_file" + rm -f "$temp_index_p" "$chunk_list" + done + else + if [ "$has_custom_index" = "true" ]; then + awk ' + /^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ { + while((getline line < "'"$temp_list"'") > 0) print line + close("'"$temp_list"'") + next + } + { print } + ' "$dir/index.md" > "$temp_index" + else + cat "$temp_list" >> "$temp_index" + fi + + do_rebuild="false" + needs_rebuild "$dir" "$out_dir/index.html" && do_rebuild="true" + [ "$has_custom_index" = "true" ] && needs_rebuild "$dir/index.md" "$out_dir/index.html" && do_rebuild="true" + + if [ "$do_rebuild" = "true" ]; then + render_markdown "$temp_index" "$is_home" "$target_url" > "$out_dir/index.html" + fi fi rm -f "$temp_index" "$temp_list" fi @@ -1053,18 +1155,22 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then rel_path="${rel_path#/}" post_url="$base_url_feed/${rel_path%.md}.html" - pub_year=$(echo "$post_date" | cut -d- -f1) - pub_month=$(echo "$post_date" | cut -d- -f2) - pub_day=$(echo "$post_date" | cut -d- -f3) - # zero-padded - pub_day=$(printf '%02d' "${pub_day#0}") - case "$pub_month" in - 01) pub_mon="Jan" ;; 02) pub_mon="Feb" ;; 03) pub_mon="Mar" ;; - 04) pub_mon="Apr" ;; 05) pub_mon="May" ;; 06) pub_mon="Jun" ;; - 07) pub_mon="Jul" ;; 08) pub_mon="Aug" ;; 09) pub_mon="Sep" ;; - 10) pub_mon="Oct" ;; 11) pub_mon="Nov" ;; 12) pub_mon="Dec" ;; - esac - pub_date="${pub_day} ${pub_mon} ${pub_year} ${post_time}:00 +0000" + if date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000' >/dev/null 2>&1; then + pub_date=$(date -u -d "$post_date $post_time" '+%a, %d %b %Y %H:%M:%S +0000') + else + pub_year=$(echo "$post_date" | cut -d- -f1) + pub_month=$(echo "$post_date" | cut -d- -f2) + pub_day=$(echo "$post_date" | cut -d- -f3) + # zero-padded + pub_day=$(printf '%02d' "${pub_day#0}") + case "$pub_month" in + 01) pub_mon="Jan" ;; 02) pub_mon="Feb" ;; 03) pub_mon="Mar" ;; + 04) pub_mon="Apr" ;; 05) pub_mon="May" ;; 06) pub_mon="Jun" ;; + 07) pub_mon="Jul" ;; 08) pub_mon="Aug" ;; 09) pub_mon="Sep" ;; + 10) pub_mon="Oct" ;; 11) pub_mon="Nov" ;; 12) pub_mon="Dec" ;; + esac + pub_date="Mon, ${pub_day} ${pub_mon} ${pub_year} ${post_time}:00 +0000" + fi { printf ' \n' @@ -1081,3 +1187,46 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then fi echo "Build complete." +} + +build_site + +if [ "$serve_mode" = "true" ]; then + port="${serve_port:-8000}" + if command -v python3 >/dev/null 2>&1; then + python3 -m http.server "$port" -d "$out" >/dev/null 2>&1 & + server_pid=$! + echo "Serving '$out' on http://localhost:$port (python3)" + elif command -v busybox >/dev/null 2>&1; then + busybox httpd -f -p "$port" -h "$out" >/dev/null 2>&1 & + server_pid=$! + echo "Serving '$out' on http://localhost:$port (busybox)" + else + die "Neither python3 nor busybox httpd is available to serve." + fi + + trap 'kill $server_pid 2>/dev/null; rm -rf "$KEWT_TMPDIR"' EXIT + trap 'kill $server_pid 2>/dev/null; exit 0' HUP INT TERM +fi + +if [ "$watch_mode" = "true" ]; then + echo "Watching for changes in '$src'..." + touch "$KEWT_TMPDIR/watch_mark" + while true; do + sleep 1 + changed="$(find "$src" -type f -newer "$KEWT_TMPDIR/watch_mark" 2>/dev/null | head -n 1)" + [ -z "$changed" ] && [ -f "site.conf" ] && [ "site.conf" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="site.conf" + [ -z "$changed" ] && [ -f "$src/site.conf" ] && [ "$src/site.conf" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="$src/site.conf" + [ -z "$changed" ] && [ -f "$template" ] && [ "$template" -nt "$KEWT_TMPDIR/watch_mark" ] && changed="$template" + [ -z "$changed" ] && [ -d "$script_dir/styles" ] && changed="$(find "$script_dir/styles" -type f -newer "$KEWT_TMPDIR/watch_mark" 2>/dev/null | head -n 1)" + + if [ -n "$changed" ]; then + echo "" + echo "Change detected, rebuilding..." + build_site + touch "$KEWT_TMPDIR/watch_mark" + fi + done +elif [ "$serve_mode" = "true" ]; then + wait "$server_pid" +fi diff --git a/markdown.sh b/markdown.sh index 9dac41e..9848105 100755 --- a/markdown.sh +++ b/markdown.sh @@ -62,13 +62,20 @@ awk -f "$awk_dir/fenced_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_f awk -f "$awk_dir/indented_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -f "$awk_dir/pipe_tables.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -v enable_header_links="$ENABLE_HEADER_LINKS" -f "$awk_dir/headers.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" +awk -f "$awk_dir/definition_lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -f "$awk_dir/lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" +# TOC +awk -f "$awk_dir/toc.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" +# Footnotes +awk -f "$awk_dir/footnotes.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" + # Spacing awk -f "$awk_dir/breaks.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -f "$awk_dir/paragraphs.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" # Inline styles +awk -f "$awk_dir/emoji.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -f "$awk_dir/markdown_inline.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" awk -v input_file="$1" -v site_root="$MARKDOWN_SITE_ROOT" -v fallback_file="$MARKDOWN_FALLBACK_FILE" -f "$awk_dir/markdown_embed.awk" "$temp_file" rm "$temp_file" diff --git a/site/Docs/configuration.md b/site/Docs/configuration.md index d437ac3..ed96703 100644 --- a/site/Docs/configuration.md +++ b/site/Docs/configuration.md @@ -15,11 +15,13 @@ You can set metadata for a page using a `site.conf`-style frontmatter block at t title = "Custom Page Title" date = "2026-03-23 11:32" draft = false +description = "A short page summary" --- ``` - `title` - overrides the page title, post name in index links, and RSS ``. - `date` - overrides the post date and time. Supports `YYYY-MM-DD` and `YYYY-MM-DD HH:MM` (or `HH-MM`). - `draft` - if `true`, the file is excluded from HTML generation. +- `description` - page description, used for Open Graph `og:description` meta tag. ## Directory Index Customisation @@ -34,4 +36,26 @@ This is my blog. The posts are below. The top-most one is the most recent. {{LIST}} ``` -The `{{LIST}}` tag will be replaced with the generated list of links to child pages and files, exactly as in case the custom index didn't exist. \ No newline at end of file +The `{{LIST}}` tag will be replaced with the generated list of links to child pages and files, exactly as in case the custom index didn't exist. + +## Table of Contents + +You can auto-generate a Table of Contents by placing `{{TOC}}` anywhere in your markdown file. It collects all `h2` and `h3` headings and generates an ordered list with anchor links. + +## Footnotes + +Footnotes use the `[^id]` syntax inline and `[^id]: text` for definitions at the bottom of the file. They are rendered as a numbered `<section>` at the end of the page. + +## Definition Lists + +Definition lists use the standard syntax: + +```md +Term +: Definition +``` +This renders as `<dl><dt>Term</dt><dd>Definition</dd></dl>`. Multiple definitions per term are supported. + +## Emoji Shortcodes + +Standard GitHub/MkDocs emoji shortcodes like `:smile:`, `:fire:`, `:rocket:` are automatically replaced with their Unicode emoji equivalents. Shortcodes inside code blocks are left as-is. \ No newline at end of file diff --git a/site/Docs/usage.md b/site/Docs/usage.md index 55dc5b6..5424bb3 100644 --- a/site/Docs/usage.md +++ b/site/Docs/usage.md @@ -9,11 +9,15 @@ kewt --generate-template [path] kewt --update [dir] kewt --from <src> --to <out> kewt [src] [out] +kewt --watch +kewt --serve [port] ``` - `--new [title]` creates a new site directory with a default `site.conf`, `template.html`, and `index.md`. - `--post [title]` creates a new markdown file in the configured `posts_dir` with the current date/time as the filename and default frontmatter. - `--generate-template [path]` writes the default `template.html` to the given path (defaults to `template.html` in the current directory). - `--update [dir]` adds any missing keys to `site.conf` and checks `template.html` against the latest default. +- `--watch` (`-w`) watches for file changes in the source directory and rebuilds automatically. +- `--serve` (`-s`) starts a local HTTP server (python3 or busybox) in the output directory after building. Use with the port number to specify the port. Composable with `--watch`. ## site.conf @@ -42,6 +46,7 @@ base_url = "" generate_feed = false feed_file = "rss.xml" posts_dir = "" +posts_per_page = 12 custom_admonitions = "" ``` - `title` - site title @@ -67,5 +72,6 @@ custom_admonitions = "" - `generate_feed` - enable RSS feed generation (requires `base_url`) - `feed_file` - filename for the generated RSS feed (default: "rss.xml") - `posts_dir` - directory name containing posts (e.g., "posts"). Enables reverse-chronological sorting, title headings in indexes, and automatic backlinks. +- `posts_per_page` - number of posts per page in paginated post indexes (default: 12). Set to 0 to disable pagination. - `enable_header_links` - turns markdown section headings into clickable anchor links (default: true) - `custom_admonitions` - comma separated list of custom admonitions diff --git a/site/index.md b/site/index.md index 6700ac3..c0bab4b 100644 --- a/site/index.md +++ b/site/index.md @@ -14,7 +14,7 @@ It's meant to be a static site generator, like _[kew](https://github.com/uint23/ ## Features - No dependencies -- Frontmatter support (title, date, draft) +- Frontmatter support (title, date, draft, description) - Supports many embed types - Automatic css variable replacement for older browsers - Automatic inlining and embedding of many filetypes with `\![link]` or `\![alt](link)` @@ -31,6 +31,13 @@ It's meant to be a static site generator, like _[kew](https://github.com/uint23/ - Clickable markdown header anchors - Mobile responsive layout - Customisable directory index pages with `{{LIST}}` +- Open Graph meta tags from frontmatter +- Auto-generated Table of Contents via `{{TOC}}` +- Footnotes (`[^id]`) +- Definition lists +- Emoji shortcodes (`:smile:`, `:fire:`, etc.) +- Post pagination +- `--watch` and `--serve` modes for development *** diff --git a/styles/kewt.css b/styles/kewt.css index fadedad..2f0aaad 100644 --- a/styles/kewt.css +++ b/styles/kewt.css @@ -252,8 +252,27 @@ hr { border-top: 1px solid var(--code-border); } +.nav-toggle, .nav-toggle-label { + display: none; +} + @media screen and (max-width: 600px) { + header { + display: flex; + justify-content: space-between; + align-items: center; + } + + .nav-toggle-label { + display: block; + font-size: 30px; + cursor: pointer; + color: var(--fg-heading); + user-select: none; + } + #side-bar { + display: none; position: relative; top: auto; left: auto; @@ -264,6 +283,10 @@ hr { margin: 0 20px 20px 20px; } + .nav-toggle:checked ~ #side-bar { + display: block; + } + article { margin: 0 20px 0 20px; }