2022-07-24 22:43:49 +00:00
defmodule MfmParser.Encoder do
alias MfmParser.Parser
alias MfmParser.Node
2022-08-23 11:07:35 +00:00
import Temple
2022-07-24 22:43:49 +00:00
2022-07-25 11:46:11 +00:00
@moduledoc """
An encoder who can turn a tree into HTML .
It only works for the MFM specific tags of the form $ [ name . opts content ] .
Other parts of MFM ( html , Markdown and [ KaTeX ] ( https :/ / katex . org / ) ) are out of scope for this project .
It can directly take input from function ` MfmParser.Parser . parse ` .
## Examples
iex > [
... > % MfmParser.Node.MFM.Twitch {
... > children : [ % MfmParser.Node.Text { props : %{ text : " 🍮 " } } ] ,
... > props : %{ speed : " 5s " }
... > }
... > ]
... > |> MfmParser.Encoder . to_html ( )
2022-08-18 02:36:35 +00:00
" <span class= \\ " mfm \\ " style= \\ " display : inline - block ; animation : 5 s ease 0 s infinite normal none running mfm - twitch ; \\ " >🍮</span> "
2022-07-25 11:46:11 +00:00
iex > MfmParser.Parser . parse ( " $[twitch.speed=5s 🍮] " ) |> MfmParser.Encoder . to_html ( )
2022-08-18 02:36:35 +00:00
" <span class= \\ " mfm \\ " style= \\ " display : inline - block ; animation : 5 s ease 0 s infinite normal none running mfm - twitch ; \\ " >🍮</span> "
2022-07-25 11:46:11 +00:00
"""
2022-07-24 22:43:49 +00:00
def to_html ( tree ) when is_list ( tree ) do
2022-08-23 11:07:35 +00:00
to_html_styles ( tree )
2022-07-24 22:43:49 +00:00
end
def to_html ( input ) when is_binary ( input ) do
Parser . parse ( input ) |> to_html ( )
end
2022-08-23 11:07:35 +00:00
defp to_html_styles ( tree ) do
2022-07-24 22:43:49 +00:00
tree
2022-08-23 11:07:35 +00:00
|> Enum . reduce ( " " , fn node , html ->
html <>
case node do
% Node.Text { } ->
node . props . text
% Node.Newline { } ->
node . props . text
% Node.MFM.Flip { } ->
html_child = to_html_styles ( node . children )
case node . props do
%{ v : true , h : true } ->
temple do
span class : " mfm " , style : " display: inline-block; transform: scale(-1); " do
html_child
end
end
%{ v : true } ->
" <span class= \" mfm \" style= \" display: inline-block; transform: scaleY(-1); \" > #{ html_child } </span> "
_ ->
" <span class= \" mfm \" style= \" display: inline-block; transform: scaleX(-1); \" > #{ html_child } </span> "
end
% Node.MFM.Font { } ->
html_child = to_html_styles ( node . children )
temple do
span class : " mfm " ,
style : " display: inline-block; font-family: #{ node . props . font } ; " do
html_child
end
end
% Node.MFM.X { } ->
html_child = to_html_styles ( node . children )
temple do
span style : " font-size: #{ node . props . size } " do
html_child
end
end
% Node.MFM.Blur { } ->
html_child = to_html_styles ( node . children )
temple do
span ( class : " mfm _mfm_blur_ " , do : html_child )
end
% Node.MFM.Jelly { } ->
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; animation: #{ node . props . speed } linear 0s infinite normal both running mfm-rubberBand; \" > #{ html_child } </span> "
% Node.MFM.Tada { } ->
html_child = to_html_styles ( node . children )
temple do
span class : " mfm " ,
style :
" display: inline-block; font-size: 150%; animation: #{ node . props . speed } linear 0s infinite normal both running mfm-tada; " do
html_child
end
end
% Node.MFM.Jump { } ->
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; animation: #{ node . props . speed } linear 0s infinite normal none running mfm-jump; \" > #{ html_child } </span> "
% Node.MFM.Bounce { } ->
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; animation: #{ node . props . speed } linear 0s infinite normal none running mfm-bounce; transform-origin: center bottom 0px; \" > #{ html_child } </span> "
% Node.MFM.Spin { } ->
html_child = to_html_styles ( node . children )
keyframe_names_map = %{
" x " = > " mfm-spinX " ,
" y " = > " mfm-spinY " ,
" z " = > " mfm-spin "
}
directions_map = %{
" left " = > " reverse "
}
" <span class= \" mfm \" style= \" display: inline-block; animation: #{ node . props . speed } linear 0s infinite #{ Map . get ( directions_map , node . props . direction , node . props . direction ) } none running #{ Map . get ( keyframe_names_map , node . props . axis , " " ) } ; \" > #{ html_child } </span> "
% Node.MFM.Shake { } ->
html_child = to_html_styles ( node . children )
temple do
span class : " mfm " ,
style :
" display: inline-block; animation: #{ node . props . speed } ease 0s infinite normal none running mfm-shake; " do
html_child
end
end
% Node.MFM.Twitch { } ->
html_child = to_html_styles ( node . children )
temple do
span class : " mfm " ,
style :
" display: inline-block; animation: #{ node . props . speed } ease 0s infinite normal none running mfm-twitch; " do
html_child
end
end
% Node.MFM.Rainbow { } ->
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; animation: #{ node . props . speed } linear 0s infinite normal none running mfm-rainbow; \" > #{ html_child } </span> "
% Node.MFM.Sparkle { } ->
# TODO: This is not how Misskey does it and should be changed to make it work like Misskey.
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; animation: 1s linear 0s infinite normal none running mfm-sparkle; \" > #{ html_child } </span> "
% Node.MFM.Rotate { } ->
html_child = to_html_styles ( node . children )
" <span class= \" mfm \" style= \" display: inline-block; transform: rotate(90deg); transform-origin: center center 0px; \" > #{ html_child } </span> "
% Node.MFM.Undefined { } ->
html_child = to_html_styles ( node . children )
" <span> #{ html_child } </span> "
_ ->
html
end
2022-07-24 22:43:49 +00:00
end )
end
end