EmojiPicker.pm 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. package Trog::Component::EmojiPicker;
  2. use v5.36;
  3. use re '/aa';
  4. use JSON::MaybeXS;
  5. use Trog::Renderer;
  6. =head1 Trog::Component::EmojiPicker
  7. The emoji picker component.
  8. =head1 Termination Conditions
  9. Dies if the emoji list isn't on disk, as there's no sensible picker to show
  10. without it. It's a frontend dependency, so C<make prereq-frontend> is what
  11. puts it there.
  12. =head1 FUNCTIONS
  13. =head2 render() = STRING
  14. Render the picker as an HTML component.
  15. The emoji list ships as a flat array, which is no use to a picker with tabs, so
  16. it gets bucketed by category on the first call and memoized thereafter -- the
  17. list can't change without a redeploy.
  18. Returns the rendered body, rather than a PSGI triplet, as components are meant
  19. to be composed into a page by their caller.
  20. =cut
  21. sub render () {
  22. state %categorized;
  23. if ( !%categorized ) {
  24. my $file = 'www/scripts/list.min.json';
  25. # One operation rather than a test and then a read, which also catches
  26. # the unreadable case the test missed. Checked with defined() rather
  27. # than truthiness so that an empty file falls through to the JSON
  28. # parser, which will say what is actually wrong with it.
  29. my $raw = eval { File::Slurper::read_binary($file) };
  30. die "Could not read $file ($@) -- run make prereq-frontend first" unless defined $raw;
  31. my $emojis = JSON::MaybeXS::decode_json($raw);
  32. foreach my $emoji ( @{ $emojis->{emojis} } ) {
  33. $categorized{ $emoji->{category} } //= [];
  34. push( @{ $categorized{ $emoji->{category} } }, $emoji->{emoji} );
  35. }
  36. }
  37. return Trog::Renderer->render(
  38. contenttype => 'text/html',
  39. component => 1,
  40. template => 'emojis.tx',
  41. data => {
  42. categories => \%categorized,
  43. },
  44. );
  45. }
  46. 1;