mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fa7227b94 | |||
| 241068b487 | |||
| 88eea07fec |
@@ -3,15 +3,14 @@
|
|||||||
- Look at the source for 3 template languages that support mustache syntax,
|
- Look at the source for 3 template languages that support mustache syntax,
|
||||||
and see how they implement the tempaltes, then pick the best one. One of them
|
and see how they implement the tempaltes, then pick the best one. One of them
|
||||||
should be Hugo / go.
|
should be Hugo / go.
|
||||||
- [ ] robots.txt?
|
|
||||||
- [ ] Evaluate Tufte CSS — borrow sidenote CSS or replace TailwindCSS entirely
|
- [ ] Evaluate Tufte CSS — borrow sidenote CSS or replace TailwindCSS entirely
|
||||||
- Option B: Steal Tufte's sidenote/margin-note CSS (adapt for dark theme), keep TailwindCSS
|
- Option B: Steal Tufte's sidenote/margin-note CSS (adapt for dark theme), keep TailwindCSS
|
||||||
- Option C: Full Tufte CSS — drop TailwindCSS, no build step, semantic HTML, customize for dark theme + Roboto
|
- Option C: Full Tufte CSS — drop TailwindCSS, no build step, semantic HTML, customize for dark theme + Roboto
|
||||||
- Our sidenote HTML pattern already matches Tufte's exactly
|
- Our sidenote HTML pattern already matches Tufte's exactly
|
||||||
- [ ] GitHub alerts (`> [!CAUTION]` → styled blockquote) — 2 posts
|
|
||||||
- [ ] Block attributes on code fences (`{ #ex-1 }`) — hello-world.md
|
- [ ] Block attributes on code fences (`{ #ex-1 }`) — hello-world.md
|
||||||
- [ ] Emoji shortcodes (`:shrug:` etc.) — 2 instances
|
- [x] Emoji shortcodes (`:shrug:` etc.) — 2 instances
|
||||||
|
- [ ] Backslash in shrug not visible.
|
||||||
- [ ] include-code shortcode (`{{< include-code ... >}}`) — i-ported-fd-to-odin
|
- [ ] include-code shortcode (`{{< include-code ... >}}`) — i-ported-fd-to-odin
|
||||||
- [ ] Nix build integration — main flake runs thor + tailwindcss instead of Hugo
|
- [x] Nix build integration — main flake runs thor + tailwindcss instead of Hugo
|
||||||
- [ ] Copy-to-clipboard button on code blocks (was in Hugo's custom-head.html)
|
- [ ] Copy-to-clipboard button on code blocks (was in Hugo's custom-head.html)
|
||||||
- [ ] OpenGraph meta tags
|
- [ ] OpenGraph meta tags
|
||||||
|
|||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
#+feature dynamic-literals
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
ALERT_STYLES: map[string]string = {
|
||||||
|
"note" = "border-l-blue-500 bg-blue-950/30 text-slate-300",
|
||||||
|
"tip" = "border-l-green-500 bg-green-950/30 text-slate-300",
|
||||||
|
"important" = "border-l-purple-500 bg-purple-950/30 text-slate-300",
|
||||||
|
"warning" = "border-l-yellow-500 bg-yellow-950/30 text-slate-300",
|
||||||
|
"caution" = "border-l-red-500 bg-red-950/30 text-slate-300",
|
||||||
|
}
|
||||||
|
|
||||||
|
ALERT_EMOJIS: map[string]string = {
|
||||||
|
"note" = "\xe2\x84\xb9\xef\xb8\x8f",
|
||||||
|
"tip" = "\xf0\x9f\x92\xa1",
|
||||||
|
"important" = "\xe2\x9d\x97",
|
||||||
|
"warning" = "\xe2\x9a\xa0\xef\xb8\x8f",
|
||||||
|
"caution" = "\xe2\x9d\x97",
|
||||||
|
}
|
||||||
|
|
||||||
|
inject_alerts :: proc(html: string) -> string {
|
||||||
|
parts: [dynamic]string
|
||||||
|
defer delete(parts)
|
||||||
|
|
||||||
|
remaining := html
|
||||||
|
|
||||||
|
for {
|
||||||
|
bq_start := strings.index(remaining, "<blockquote>")
|
||||||
|
if bq_start < 0 {
|
||||||
|
append(&parts, remaining)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
bq_close := strings.index(remaining, "</blockquote>")
|
||||||
|
if bq_close < 0 {
|
||||||
|
append(&parts, remaining)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
bq_end := bq_close + len("</blockquote>")
|
||||||
|
bq := remaining[bq_start:bq_end]
|
||||||
|
|
||||||
|
// Append text before this blockquote
|
||||||
|
append(&parts, remaining[:bq_start])
|
||||||
|
|
||||||
|
// Transform if it's an alert, otherwise keep as-is
|
||||||
|
append(&parts, transform_alert(bq))
|
||||||
|
|
||||||
|
remaining = remaining[bq_end:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.join(parts[:], "")
|
||||||
|
}
|
||||||
|
|
||||||
|
transform_alert :: proc(bq: string) -> string {
|
||||||
|
// Skip <blockquote> tag and whitespace
|
||||||
|
pos := len("<blockquote>")
|
||||||
|
for pos < len(bq) && (bq[pos] == '\n' || bq[pos] == '\r' || bq[pos] == ' ' || bq[pos] == '\t') {
|
||||||
|
pos += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for <p>[!
|
||||||
|
if pos + 4 >= len(bq) || bq[pos] != '<' || bq[pos + 1] != 'p' || bq[pos + 2] != '>' ||
|
||||||
|
bq[pos + 3] != '[' || bq[pos + 4] != '!' {
|
||||||
|
return bq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract alert type until ]
|
||||||
|
close := strings.index(bq[pos + 5:], "]")
|
||||||
|
if close < 0 {
|
||||||
|
return bq
|
||||||
|
}
|
||||||
|
|
||||||
|
type_raw := bq[pos + 5 : pos + 5 + close]
|
||||||
|
type_lower := strings.to_lower(type_raw)
|
||||||
|
|
||||||
|
style, has_style := ALERT_STYLES[type_lower]
|
||||||
|
emoji, has_emoji := ALERT_EMOJIS[type_lower]
|
||||||
|
if !has_style || !has_emoji {
|
||||||
|
return bq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position after ]
|
||||||
|
after_type := pos + 5 + close + 1
|
||||||
|
|
||||||
|
// Skip optional + or -
|
||||||
|
content_start := after_type
|
||||||
|
if content_start < len(bq) && (bq[content_start] == '+' || bq[content_start] == '-') {
|
||||||
|
content_start += 1
|
||||||
|
}
|
||||||
|
// Skip space after marker
|
||||||
|
if content_start < len(bq) && bq[content_start] == ' ' {
|
||||||
|
content_start += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild: styled blockquote + bold title paragraph + rest
|
||||||
|
rest := bq[content_start:]
|
||||||
|
|
||||||
|
return fmt.aprintf(
|
||||||
|
`<blockquote class="alert %s rounded-r py-2">
|
||||||
|
<p class="font-bold mb-1">%s %s`,
|
||||||
|
style,
|
||||||
|
emoji,
|
||||||
|
rest,
|
||||||
|
)
|
||||||
|
}
|
||||||
+3
-2
@@ -173,9 +173,10 @@ load_page :: proc(
|
|||||||
if strings.has_suffix(file_path, ".html") {
|
if strings.has_suffix(file_path, ".html") {
|
||||||
page.body_html = strings.clone(body)
|
page.body_html = strings.clone(body)
|
||||||
} else {
|
} else {
|
||||||
clean_body, defs := strip_definitions(body)
|
expanded := expand_emoji(body)
|
||||||
|
clean_body, defs := strip_definitions(expanded)
|
||||||
html := cm.markdown_to_html_from_string(clean_body, {.Unsafe})
|
html := cm.markdown_to_html_from_string(clean_body, {.Unsafe})
|
||||||
page.body_html = inject_sidenotes(html, defs)
|
page.body_html = inject_alerts(inject_sidenotes(html, defs))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch page_type {
|
switch page_type {
|
||||||
|
|||||||
+438
@@ -0,0 +1,438 @@
|
|||||||
|
#+feature dynamic-literals
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
EMOJIS: map[string]string = {
|
||||||
|
// People
|
||||||
|
"smile" = "\xf0\x9f\x98\x84",
|
||||||
|
"laughing" = "\xf0\x9f\x98\x86",
|
||||||
|
"blush" = "\xf0\x9f\x98\x8a",
|
||||||
|
"smiley" = "\xf0\x9f\x98\x83",
|
||||||
|
"wink" = "\xf0\x9f\x98\x89",
|
||||||
|
"joy" = "\xf0\x9f\xa4\xa3",
|
||||||
|
"rofl" = "\xf0\x9f\xa4\xa3",
|
||||||
|
"relaxed" = "\xe2\x98\xba\xef\xb8\x8f",
|
||||||
|
"thinking" = "\xf0\x9f\xa4\x94",
|
||||||
|
"neutral_face" = "\xf0\x9f\x98\x90",
|
||||||
|
"expressionless" = "\xf0\x9f\x98\x91",
|
||||||
|
"no_mouth" = "\xf0\x9f\x98\xb6",
|
||||||
|
"rolling_eyes" = "\xf0\x9f\x99\x84",
|
||||||
|
"smirk" = "\xf0\x9f\x98\x8f",
|
||||||
|
"persevere" = "\xf0\x9f\x98\xa3",
|
||||||
|
"disappointed_relieved" = "\xf0\x9f\x98\xa5",
|
||||||
|
"open_mouth" = "\xf0\x9f\x98\xae",
|
||||||
|
"zipper_mouth_face" = "\xf0\x9f\xa4\x90",
|
||||||
|
"hushed" = "\xf0\x9f\x98\xaf",
|
||||||
|
"sleepy" = "\xf0\x9f\x98\xaa",
|
||||||
|
"tired_face" = "\xf0\x9f\x98\xab",
|
||||||
|
"sleeping" = "\xf0\x9f\x98\xb4",
|
||||||
|
"relieved" = "\xf0\x9f\x98\x8c",
|
||||||
|
"stuck_out_tongue" = "\xf0\x9f\x98\x9b",
|
||||||
|
"stuck_out_tongue_winking_eye" = "\xf0\x9f\x98\x9c",
|
||||||
|
"stuck_out_tongue_closed_eyes" = "\xf0\x9f\x98\x9d",
|
||||||
|
"drooling_face" = "\xf0\x9f\xa4\xa4",
|
||||||
|
"unamused" = "\xf0\x9f\x98\x92",
|
||||||
|
"sweat" = "\xf0\x9f\x98\x85",
|
||||||
|
"pensive" = "\xf0\x9f\x98\x94",
|
||||||
|
"confused" = "\xf0\x9f\x98\x95",
|
||||||
|
"upside_down_face" = "\xf0\x9f\x99\x83",
|
||||||
|
"money_mouth_face" = "\xf0\x9f\xa4\x91",
|
||||||
|
"astonished" = "\xf0\x9f\x98\xb2",
|
||||||
|
"white_frowning_face" = "\xe2\x98\xb9\xef\xb8\x8f",
|
||||||
|
"slightly_sad_face" = "\xe2\x98\xb9\xef\xb8\x8f",
|
||||||
|
"confounded" = "\xf0\x9f\x98\x96",
|
||||||
|
"disappointed" = "\xf0\x9f\x98\x9e",
|
||||||
|
"worried" = "\xf0\x9f\x98\x9f",
|
||||||
|
"triumph" = "\xf0\x9f\x98\xa4",
|
||||||
|
"cry" = "\xf0\x9f\x98\xa2",
|
||||||
|
"sob" = "\xf0\x9f\x98\xad",
|
||||||
|
"frowning" = "\xf0\x9f\x98\xa6",
|
||||||
|
"frowning_face" = "\xf0\x9f\x99\x81",
|
||||||
|
"anguished" = "\xf0\x9f\x98\xa7",
|
||||||
|
"fearful" = "\xf0\x9f\x98\xa8",
|
||||||
|
"weary" = "\xf0\x9f\x98\xa9",
|
||||||
|
"grimacing" = "\xf0\x9f\x98\xac",
|
||||||
|
"cold_sweat" = "\xf0\x9f\x98\xb0",
|
||||||
|
"scream" = "\xf0\x9f\x98\xb1",
|
||||||
|
"flushed" = "\xf0\x9f\x98\xb3",
|
||||||
|
"dizzy_face" = "\xf0\x9f\x98\xb5",
|
||||||
|
"rage" = "\xf0\x9f\x98\xa1",
|
||||||
|
"angry" = "\xf0\x9f\x98\xa0",
|
||||||
|
"innocent" = "\xf0\x9f\x98\x87",
|
||||||
|
"cowboy_hat_face" = "\xf0\x9f\xa4\xa0",
|
||||||
|
"clown_face" = "\xf0\x9f\xa4\xa1",
|
||||||
|
"mask" = "\xf0\x9f\x98\xb7",
|
||||||
|
"thermometer_face" = "\xf0\x9f\xa4\x92",
|
||||||
|
"head_bandage" = "\xf0\x9f\xa4\x95",
|
||||||
|
"nauseated_face" = "\xf0\x9f\xa4\xa2",
|
||||||
|
"sneezing_face" = "\xf0\x9f\xa4\xa7",
|
||||||
|
"smiling_imp" = "\xf0\x9f\x98\x88",
|
||||||
|
"imp" = "\xf0\x9f\x91\xbf",
|
||||||
|
"shrug" = "\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf",
|
||||||
|
"facepalm" = "\xf0\x9f\xa4\xa6",
|
||||||
|
"facepunch" = "\xf0\x9f\x91\x8a",
|
||||||
|
"wave" = "\xf0\x9f\x91\x8b",
|
||||||
|
"ok_hand" = "\xf0\x9f\x91\x8c",
|
||||||
|
"thumbsup" = "\xf0\x9f\x91\x8d",
|
||||||
|
"thumbsdown" = "\xf0\x9f\x91\x8e",
|
||||||
|
"clap" = "\xf0\x9f\x91\x8f",
|
||||||
|
"pray" = "\xf0\x9f\x99\x8f",
|
||||||
|
"point_up" = "\xe2\x98\x9d\xef\xb8\x8f",
|
||||||
|
"point_down" = "\xf0\x9f\x91\x87",
|
||||||
|
"point_left" = "\xf0\x9f\x91\x88",
|
||||||
|
"point_right" = "\xf0\x9f\x89\x89",
|
||||||
|
"v" = "\xe2\x9c\x8c\xef\xb8\x8f",
|
||||||
|
"raised_hands" = "\xf0\x9f\x99\x8c",
|
||||||
|
"muscle" = "\xf0\x9f\x92\xaa",
|
||||||
|
"fist" = "\xe2\x9c\x8a",
|
||||||
|
"hand" = "\xe2\x9c\x8b",
|
||||||
|
|
||||||
|
// Hearts & symbols
|
||||||
|
"heart" = "\xe2\x9d\xa4\xef\xb8\x8f",
|
||||||
|
"orange_heart" = "\xf0\x9f\xa7\xa1",
|
||||||
|
"yellow_heart" = "\xf0\x9f\x92\x9b",
|
||||||
|
"green_heart" = "\xf0\x9f\x92\x9a",
|
||||||
|
"blue_heart" = "\xf0\x9f\x92\x99",
|
||||||
|
"purple_heart" = "\xf0\x9f\x92\x9c",
|
||||||
|
"broken_heart" = "\xf0\x9f\x92\x94",
|
||||||
|
"sparkling_heart" = "\xf0\x9f\x92\x96",
|
||||||
|
"100" = "\xf0\x9f\x92\xaf",
|
||||||
|
"anger" = "\xf0\x9f\x92\xa2",
|
||||||
|
"checkered_flag" = "\xf0\x9f\x8f\x81",
|
||||||
|
"crossed_flags" = "\xf0\x9f\x9a\xa9",
|
||||||
|
"rocket" = "\xf0\x9f\x9a\x80",
|
||||||
|
"star" = "\xe2\xad\x90",
|
||||||
|
"star2" = "\xf0\x9f\x8c\x9f",
|
||||||
|
"sparkles" = "\xe2\x9c\xa8",
|
||||||
|
"boom" = "\xf0\x9f\x92\xa5",
|
||||||
|
"exclamation" = "\xe2\x9d\x97",
|
||||||
|
"question" = "\xe2\x9d\x93",
|
||||||
|
"grey_exclamation" = "\xe2\x9d\x95",
|
||||||
|
"grey_question" = "\xe2\x9d\x94",
|
||||||
|
"zzz" = "\xf0\x9f\x92\xa4",
|
||||||
|
"warning" = "\xe2\x9a\xa0\xef\xb8\x8f",
|
||||||
|
"no_entry_sign" = "\xf0\x9f\x9a\xab",
|
||||||
|
"no_entry" = "\xe2\x9b\x94",
|
||||||
|
"white_check_mark" = "\xe2\x9c\x85",
|
||||||
|
"negative_squared_cross_mark" = "\xe2\x9d\x8e",
|
||||||
|
"x" = "\xe2\x9d\x8c",
|
||||||
|
"o" = "\xe2\xad\x95",
|
||||||
|
"heavy_plus_sign" = "\xe2\x9e\x95",
|
||||||
|
"heavy_minus_sign" = "\xe2\x9e\x96",
|
||||||
|
"heavy_division_sign" = "\xe2\x9e\x97",
|
||||||
|
"copyright" = "\xc2\xa9\xef\xb8\x8f",
|
||||||
|
"registered" = "\xc2\xae\xef\xb8\x8f",
|
||||||
|
"tm" = "\xe2\x84\xa2\xef\xb8\x8f",
|
||||||
|
|
||||||
|
// Nature & weather
|
||||||
|
"fire" = "\xf0\x9f\x94\xa5",
|
||||||
|
"zap" = "\xe2\x9a\xa1",
|
||||||
|
"sunny" = "\xe2\x98\x80\xef\xb8\x8f",
|
||||||
|
"cloud" = "\xe2\x98\x81\xef\xb8\x8f",
|
||||||
|
"rainbow" = "\xf0\x9f\x8c\x88",
|
||||||
|
"snowflake" = "\xe2\x9d\x84\xef\xb8\x8f",
|
||||||
|
"dash" = "\xf0\x9f\x92\xa8",
|
||||||
|
"tornado" = "\xf0\x9f\x8c\xaa\xef\xb8\x8f",
|
||||||
|
"deciduous_tree" = "\xf0\x9f\x8c\xb3",
|
||||||
|
"evergreen_tree" = "\xf0\x9f\x8c\xb2",
|
||||||
|
"palm_tree" = "\xf0\x9f\x8c\xb4",
|
||||||
|
"cactus" = "\xf0\x9f\x8c\xb5",
|
||||||
|
"tulip" = "\xf0\x9f\x8c\xb7",
|
||||||
|
"rose" = "\xf0\x9f\x8c\xb9",
|
||||||
|
"sunflower" = "\xf0\x9f\x8c\xbb",
|
||||||
|
"hibiscus" = "\xf0\x9f\x8c\xba",
|
||||||
|
"earth_africa" = "\xf0\x9f\x8c\x8d",
|
||||||
|
"earth_americas" = "\xf0\x9f\x8c\x8e",
|
||||||
|
"earth_asia" = "\xf0\x9f\x8c\x8f",
|
||||||
|
"new_moon" = "\xf0\x9f\x8c\x9a",
|
||||||
|
"full_moon" = "\xf0\x9f\x8c\x95",
|
||||||
|
|
||||||
|
// Food & drink
|
||||||
|
"coffee" = "\xe2\x98\x95",
|
||||||
|
"tea" = "\xf0\x9f\x8d\xb5",
|
||||||
|
"beer" = "\xf0\x9f\x8d\xba",
|
||||||
|
"beers" = "\xf0\x9f\x8d\xbb",
|
||||||
|
"wine_glass" = "\xf0\x9f\x8d\xb7",
|
||||||
|
"tropical_drink" = "\xf0\x9f\x8d\xb9",
|
||||||
|
"apple" = "\xf0\x9f\x8d\x8e",
|
||||||
|
"green_apple" = "\xf0\x9f\x8d\x8f",
|
||||||
|
"orange" = "\xf0\x9f\x8d\x8a",
|
||||||
|
"lemon" = "\xf0\x9f\x8d\x8b",
|
||||||
|
"banana" = "\xf0\x9f\x8d\x8c",
|
||||||
|
"watermelon" = "\xf0\x9f\x8d\x89",
|
||||||
|
"grapes" = "\xf0\x9f\x8d\x87",
|
||||||
|
"strawberry" = "\xf0\x9f\x8d\x93",
|
||||||
|
"melon" = "\xf0\x9f\x8d\x88",
|
||||||
|
"cherries" = "\xf0\x9f\x8d\x92",
|
||||||
|
"peach" = "\xf0\x9f\x8d\x91",
|
||||||
|
"pineapple" = "\xf0\x9f\x8d\x8d",
|
||||||
|
"pizza" = "\xf0\x9f\x8d\x95",
|
||||||
|
"hamburger" = "\xf0\x9f\x8d\x94",
|
||||||
|
"hotdog" = "\xf0\x9f\x8c\xad",
|
||||||
|
"taco" = "\xf0\x9f\x8c\xae",
|
||||||
|
"burrito" = "\xf0\x9f\x8c\xaf",
|
||||||
|
"cake" = "\xf0\x9f\x8d\xb0",
|
||||||
|
"cookie" = "\xf0\x9f\x8d\xaa",
|
||||||
|
"chocolate_bar" = "\xf0\x9f\x8d\xab",
|
||||||
|
"candy" = "\xf0\x9f\x8d\xac",
|
||||||
|
"popcorn" = "\xf0\x9f\x8d\xbf",
|
||||||
|
|
||||||
|
// Animals
|
||||||
|
"dog" = "\xf0\x9f\x90\xb6",
|
||||||
|
"cat" = "\xf0\x9f\x90\xb1",
|
||||||
|
"mouse" = "\xf0\x9f\x90\xad",
|
||||||
|
"hamster" = "\xf0\x9f\x90\xb9",
|
||||||
|
"rabbit" = "\xf0\x9f\x90\xb0",
|
||||||
|
"bear" = "\xf0\x9f\x90\xbb",
|
||||||
|
"panda_face" = "\xf0\x9f\x90\xbc",
|
||||||
|
"koala" = "\xf0\x9f\x90\xa8",
|
||||||
|
"tiger" = "\xf0\x9f\x90\xaf",
|
||||||
|
"lion_face" = "\xf0\x9f\xa6\x81",
|
||||||
|
"cow" = "\xf0\x9f\x90\xae",
|
||||||
|
"pig" = "\xf0\x9f\x90\xb7",
|
||||||
|
"frog" = "\xf0\x9f\x90\xb8",
|
||||||
|
"monkey_face" = "\xf0\x9f\x90\xb5",
|
||||||
|
"see_no_evil" = "\xf0\x9f\x99\x88",
|
||||||
|
"hear_no_evil" = "\xf0\x9f\x99\x89",
|
||||||
|
"speak_no_evil" = "\xf0\x9f\x99\x8a",
|
||||||
|
"owl" = "\xf0\x9f\xa6\x89",
|
||||||
|
"bat" = "\xf0\x9f\xa6\x87",
|
||||||
|
"wolf" = "\xf0\x9f\x90\xba",
|
||||||
|
"boar" = "\xf0\x9f\x90\x97",
|
||||||
|
"horse" = "\xf0\x9f\x90\x8e",
|
||||||
|
"unicorn" = "\xf0\x9f\xa6\x84",
|
||||||
|
"honeybee" = "\xf0\x9f\x90\x9d",
|
||||||
|
"bug" = "\xf0\x9f\x90\x9b",
|
||||||
|
"snail" = "\xf0\x9f\x90\x8c",
|
||||||
|
"beetle" = "\xf0\x9f\x90\x9e",
|
||||||
|
"ant" = "\xf0\x9f\x90\x9c",
|
||||||
|
"spider" = "\xf0\x9f\x95\xb7",
|
||||||
|
"scorpion" = "\xf0\x9f\xa6\x82",
|
||||||
|
"turtle" = "\xf0\x9f\x90\xa2",
|
||||||
|
"snake" = "\xf0\x9f\x90\x8d",
|
||||||
|
"octopus" = "\xf0\x9f\x90\x99",
|
||||||
|
"shell" = "\xf0\x9f\x90\x9a",
|
||||||
|
"whale" = "\xf0\x9f\x90\xb3",
|
||||||
|
"dolphin" = "\xf0\x9f\x90\xac",
|
||||||
|
"fish" = "\xf0\x9f\x90\x9f",
|
||||||
|
"tropical_fish" = "\xf0\x9f\x90\xa0",
|
||||||
|
"blowfish" = "\xf0\x9f\x90\xa1",
|
||||||
|
"penguin" = "\xf0\x9f\x90\xa7",
|
||||||
|
"chicken" = "\xf0\x9f\x90\x94",
|
||||||
|
"bird" = "\xf0\x9f\x90\xa6",
|
||||||
|
"eagle" = "\xf0\x9f\xa6\x85",
|
||||||
|
|
||||||
|
// Objects
|
||||||
|
"computer" = "\xf0\x9f\x92\xbb",
|
||||||
|
"iphone" = "\xf0\x9f\x93\xb1",
|
||||||
|
"keyboard" = "\xe2\x8c\xa8\xef\xb8\x8f",
|
||||||
|
"desktop_computer" = "\xf0\x9f\x96\xa5",
|
||||||
|
"printer" = "\xf0\x9f\x96\xa8",
|
||||||
|
"mouse_three_button" = "\xf0\x9f\x96\xb1",
|
||||||
|
"joystick" = "\xf0\x9f\x95\xb9",
|
||||||
|
"stash" = "\xf0\x9f\x92\xbe",
|
||||||
|
"floppy_disk" = "\xf0\x9f\x92\xbe",
|
||||||
|
"cd" = "\xf0\x9f\x92\xbf",
|
||||||
|
"dvd" = "\xf0\x9f\x93\x80",
|
||||||
|
"vhs" = "\xf0\x9f\x93\xbc",
|
||||||
|
"camera" = "\xf0\x9f\x93\xb7",
|
||||||
|
"video_camera" = "\xf0\x9f\x93\xb9",
|
||||||
|
"tv" = "\xf0\x9f\x93\xba",
|
||||||
|
"radio" = "\xf0\x9f\x93\xbb",
|
||||||
|
"pager" = "\xf0\x9f\x93\x9f",
|
||||||
|
"telephone" = "\xe2\x98\x8e\xef\xb8\x8f",
|
||||||
|
"fax" = "\xf0\x9f\x93\xa0",
|
||||||
|
"bulb" = "\xf0\x9f\x92\xa1",
|
||||||
|
"candle" = "\xf0\x9f\x95\xaf",
|
||||||
|
"bathtub" = "\xf0\x9f\x9b\x81",
|
||||||
|
"shower" = "\xf0\x9f\x9a\xbf",
|
||||||
|
"toilet" = "\xf0\x9f\x9a\xbd",
|
||||||
|
"wrench" = "\xf0\x9f\x94\xa7",
|
||||||
|
"hammer" = "\xf0\x9f\x94\xa8",
|
||||||
|
"nut_and_bolt" = "\xf0\x9f\x94\xa9",
|
||||||
|
"gear" = "\xe2\x9a\x99\xef\xb8\x8f",
|
||||||
|
"link" = "\xf0\x9f\x94\x97",
|
||||||
|
"lock" = "\xf0\x9f\x94\x92",
|
||||||
|
"unlock" = "\xf0\x9f\x94\x93",
|
||||||
|
"key" = "\xf0\x9f\x94\x91",
|
||||||
|
"bell" = "\xf0\x9f\x94\x94",
|
||||||
|
"bookmark" = "\xf0\x9f\x94\x96",
|
||||||
|
"pushpin" = "\xf0\x9f\x93\x8c",
|
||||||
|
"paperclip" = "\xf0\x9f\x93\x8e",
|
||||||
|
"memo" = "\xf0\x9f\x93\x9d",
|
||||||
|
"pencil2" = "\xe2\x9c\x8f\xef\xb8\x8f",
|
||||||
|
"black_nib" = "\xe2\x9c\x92\xef\xb8\x8f",
|
||||||
|
"pen" = "\xf0\x9f\x96\x8a",
|
||||||
|
"paintbrush" = "\xf0\x9f\x96\x8c",
|
||||||
|
"crayon" = "\xf0\x9f\x96\x8d",
|
||||||
|
"book" = "\xf0\x9f\x93\x97",
|
||||||
|
"books" = "\xf0\x9f\x93\x9a",
|
||||||
|
"ledger" = "\xf0\x9f\x93\x92",
|
||||||
|
"notebook" = "\xf0\x9f\x93\x93",
|
||||||
|
"scroll" = "\xf0\x9f\x93\x9c",
|
||||||
|
"page_with_curl" = "\xf0\x9f\x93\x84",
|
||||||
|
"newspaper" = "\xf0\x9f\x93\xb0",
|
||||||
|
"chart_with_upwards_trend" = "\xf0\x9f\x93\x88",
|
||||||
|
"chart_with_downwards_trend" = "\xf0\x9f\x93\x89",
|
||||||
|
"bar_chart" = "\xf0\x9f\x93\x8a",
|
||||||
|
"calendar" = "\xf0\x9f\x93\x85",
|
||||||
|
"date" = "\xf0\x9f\x93\x85",
|
||||||
|
"hourglass" = "\xe2\x8f\xb3",
|
||||||
|
"hourglass_flowing_sand" = "\xe2\x8f\xb3",
|
||||||
|
"clock" = "\xf0\x9f\x95\x90",
|
||||||
|
"alarm_clock" = "\xe2\x8f\xb0",
|
||||||
|
"stopwatch" = "\xe2\x8f\xb1",
|
||||||
|
"watch" = "\xe2\x8c\x9a",
|
||||||
|
"moneybag" = "\xf0\x9f\x92\xb0",
|
||||||
|
"yen" = "\xf0\x9f\x92\xb4",
|
||||||
|
"dollar" = "\xf0\x9f\x92\xb5",
|
||||||
|
"euro" = "\xf0\x9f\x92\xb6",
|
||||||
|
"pound" = "\xf0\x9f\x92\xb7",
|
||||||
|
"money_with_wings" = "\xf0\x9f\x92\xb8",
|
||||||
|
"credit_card" = "\xf0\x9f\x92\xb3",
|
||||||
|
"gem" = "\xf0\x9f\x92\x8e",
|
||||||
|
"bomb" = "\xf0\x9f\x92\xa3",
|
||||||
|
"gift" = "\xf0\x9f\x8e\x81",
|
||||||
|
"balloon" = "\xf0\x9f\x8e\x88",
|
||||||
|
"tada" = "\xf0\x9f\x8e\x89",
|
||||||
|
"confetti_ball" = "\xf0\x9f\x8e\x8a",
|
||||||
|
"package" = "\xf0\x9f\x93\xa6",
|
||||||
|
"mailbox" = "\xf0\x9f\x93\xab",
|
||||||
|
"inbox_tray" = "\xf0\x9f\x93\xa5",
|
||||||
|
"outbox_tray" = "\xf0\x9f\x93\xa4",
|
||||||
|
"email" = "\xe2\x9c\x89\xef\xb8\x8f",
|
||||||
|
"envelope" = "\xe2\x9c\x89\xef\xb8\x8f",
|
||||||
|
"incoming_envelope" = "\xf0\x9f\x93\xa8",
|
||||||
|
|
||||||
|
// Activities
|
||||||
|
"soccer" = "\xe2\x9a\xbd",
|
||||||
|
"basketball" = "\xf0\x9f\x8f\x80",
|
||||||
|
"football" = "\xf0\x9f\x8f\x88",
|
||||||
|
"baseball" = "\xe2\x9a\xbe",
|
||||||
|
"tennis" = "\xf0\x9f\x8e\xbe",
|
||||||
|
"8ball" = "\xf0\x9f\x8e\xb1",
|
||||||
|
"bowling" = "\xf0\x9f\x8e\xb3",
|
||||||
|
"video_game" = "\xf0\x9f\x8e\xae",
|
||||||
|
"dart" = "\xf0\x9f\x8e\xaf",
|
||||||
|
"game_die" = "\xf0\x9f\x8e\xb2",
|
||||||
|
"slot_machine" = "\xf0\x9f\x8e\xb0",
|
||||||
|
"cards" = "\xf0\x9f\x83\x8f",
|
||||||
|
"black_joker" = "\xf0\x9f\x83\x9f",
|
||||||
|
"mahjong" = "\xf0\x9f\x80\x84",
|
||||||
|
"musical_note" = "\xf0\x9f\x8e\xb5",
|
||||||
|
"notes" = "\xf0\x9f\x8e\xb6",
|
||||||
|
"saxophone" = "\xf0\x9f\x8e\xb7",
|
||||||
|
"guitar" = "\xf0\x9f\x8e\xb8",
|
||||||
|
"musical_keyboard" = "\xf0\x9f\x8e\xb9",
|
||||||
|
"trumpet" = "\xf0\x9f\x8e\xba",
|
||||||
|
"violin" = "\xf0\x9f\x8e\xbb",
|
||||||
|
"drum" = "\xf0\x9f\xa5\x81",
|
||||||
|
"headphones" = "\xf0\x9f\x8e\xa7",
|
||||||
|
"microphone" = "\xf0\x9f\x8e\xa4",
|
||||||
|
"level_slider" = "\xf0\x9f\x8e\x9a",
|
||||||
|
"control_knobs" = "\xf0\x9f\x8e\x9b",
|
||||||
|
"ticket" = "\xf0\x9f\x8e\xab",
|
||||||
|
"art" = "\xf0\x9f\x8e\xa8",
|
||||||
|
"circus_tent" = "\xf0\x9f\x8e\xaa",
|
||||||
|
"theater_masks" = "\xf0\x9f\x8e\xad",
|
||||||
|
"clapper" = "\xf0\x9f\x8e\xac",
|
||||||
|
|
||||||
|
// Travel
|
||||||
|
"car" = "\xf0\x9f\x9a\x97",
|
||||||
|
"taxi" = "\xf0\x9f\x9a\x95",
|
||||||
|
"bus" = "\xf0\x9f\x9a\x8d",
|
||||||
|
"train" = "\xf0\x9f\x9a\x86",
|
||||||
|
"metro" = "\xf0\x9f\x9a\x87",
|
||||||
|
"light_rail" = "\xf0\x9f\x9a\x88",
|
||||||
|
"tram" = "\xf0\x9f\x9a\x8a",
|
||||||
|
"bike" = "\xf0\x9f\x9a\xb2",
|
||||||
|
"motorcycle" = "\xf0\x9f\x8f\x8d",
|
||||||
|
"airplane" = "\xe2\x9c\x88\xef\xb8\x8f",
|
||||||
|
"helicopter" = "\xf0\x9f\x9a\x81",
|
||||||
|
"boat" = "\xe2\x9b\xb5",
|
||||||
|
"sailboat" = "\xe2\x9b\xb5",
|
||||||
|
"ship" = "\xf0\x9f\x9a\xa2",
|
||||||
|
"fuelpump" = "\xe2\x9b\xbd",
|
||||||
|
"construction" = "\xf0\x9f\x9a\xa7",
|
||||||
|
"house" = "\xf0\x9f\x8f\xa0",
|
||||||
|
"house_with_garden" = "\xf0\x9f\x8f\xa1",
|
||||||
|
"office" = "\xf0\x9f\x8f\xa2",
|
||||||
|
"post_office" = "\xf0\x9f\x8f\xa3",
|
||||||
|
"hospital" = "\xf0\x9f\x8f\xa5",
|
||||||
|
"bank" = "\xf0\x9f\x8f\xa6",
|
||||||
|
"hotel" = "\xf0\x9f\x8f\xa8",
|
||||||
|
"school" = "\xf0\x9f\x8f\xab",
|
||||||
|
"department_store" = "\xf0\x9f\x8f\xac",
|
||||||
|
"church" = "\xe2\x9b\xaa",
|
||||||
|
"castle" = "\xf0\x9f\x8f\xb0",
|
||||||
|
"factory" = "\xf0\x9f\x8f\xad",
|
||||||
|
"tokyo_tower" = "\xf0\x9f\x97\xbc",
|
||||||
|
"statue_of_liberty" = "\xf0\x9f\x97\xbd",
|
||||||
|
"fountain" = "\xe2\x9b\xb2",
|
||||||
|
"tent" = "\xe2\x9b\xba",
|
||||||
|
"mountain" = "\xf0\x9f\x8f\x94",
|
||||||
|
"snow_capped_mountain" = "\xf0\x9f\x8f\x94",
|
||||||
|
"beach" = "\xf0\x9f\x8f\x96",
|
||||||
|
"camping" = "\xf0\x9f\x8f\x95",
|
||||||
|
"world_map" = "\xf0\x9f\x97\xba",
|
||||||
|
"japan" = "\xf0\x9f\x97\xbe",
|
||||||
|
};
|
||||||
|
|
||||||
|
expand_emoji :: proc(text: string) -> string {
|
||||||
|
if len(EMOJIS) == 0 {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
parts: [dynamic]string
|
||||||
|
defer delete(parts)
|
||||||
|
|
||||||
|
remaining := text
|
||||||
|
|
||||||
|
for {
|
||||||
|
colon := strings.index(remaining, ":")
|
||||||
|
if colon < 0 {
|
||||||
|
append(&parts, remaining)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the closing colon
|
||||||
|
after := remaining[colon + 1:]
|
||||||
|
end := strings.index(after, ":")
|
||||||
|
if end < 0 {
|
||||||
|
append(&parts, remaining)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
shortcode := remaining[colon + 1 : colon + 1 + end]
|
||||||
|
|
||||||
|
// Validate: shortcode must be all lowercase letters, digits, or underscores
|
||||||
|
// and must not contain whitespace
|
||||||
|
valid := true
|
||||||
|
for c in shortcode {
|
||||||
|
if !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9') && c != '_' && c != '+' && c != '-' {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid || len(shortcode) == 0 {
|
||||||
|
append(&parts, remaining[:colon + 1])
|
||||||
|
remaining = remaining[colon + 1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji, found := EMOJIS[shortcode]
|
||||||
|
if !found {
|
||||||
|
append(&parts, remaining[:colon + 1])
|
||||||
|
remaining = remaining[colon + 1:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace :shortcode: with emoji
|
||||||
|
append(&parts, remaining[:colon])
|
||||||
|
append(&parts, emoji)
|
||||||
|
remaining = remaining[colon + 1 + end + 1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.join(parts[:], "")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user