From db5d6f469f355a85da2ef2582f08799da9754d88 Mon Sep 17 00:00:00 2001 From: pancakes Date: Sun, 10 Nov 2024 15:49:04 +1000 Subject: [PATCH] [frontend/mfm] Implement flip, font, x2, x3, x4, blur, and rotate fn nodes --- .../Components/MfmText.razor.css | 49 ++++++++ .../Core/Miscellaneous/RenderMfm.cs | 105 +++++++++++++++++- 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/Iceshrimp.Frontend/Components/MfmText.razor.css b/Iceshrimp.Frontend/Components/MfmText.razor.css index a37dcbf8..bce1821b 100644 --- a/Iceshrimp.Frontend/Components/MfmText.razor.css +++ b/Iceshrimp.Frontend/Components/MfmText.razor.css @@ -109,4 +109,53 @@ .code-pre { overflow: auto; } +} + +/* fn nodes */ +::deep { + .fn-flip.h { + display: inline-block; + transform: scaleX(-1); + } +} + +::deep { + .fn-flip.v { + display: inline-block; + transform: scaleY(-1); + } +} + +::deep { + .fn-flip.h.v { + display: inline-block; + transform: scaleX(-1) scaleY(-1); + } +} + +::deep { + .fn-x { + display: inline-block; + scale: attr(data-scale number, 2); + } +} + +::deep { + .fn-blur { + filter: blur(6px); + transition: filter 0.3s; + } +} + +::deep { + .fn-blur:hover { + filter: blur(0); + } +} + +::deep { + .fn-rotate { + display: inline-block; + transform-origin: center center 0; + } } \ No newline at end of file diff --git a/Iceshrimp.Frontend/Core/Miscellaneous/RenderMfm.cs b/Iceshrimp.Frontend/Core/Miscellaneous/RenderMfm.cs index 42ee16d3..7c78d786 100644 --- a/Iceshrimp.Frontend/Core/Miscellaneous/RenderMfm.cs +++ b/Iceshrimp.Frontend/Core/Miscellaneous/RenderMfm.cs @@ -3,6 +3,7 @@ using AngleSharp.Dom; using Iceshrimp.Parsing; using Iceshrimp.Shared.Schemas.Web; using Microsoft.AspNetCore.Components; +using Microsoft.FSharp.Core; namespace Iceshrimp.Frontend.Core.Miscellaneous; @@ -60,7 +61,7 @@ public static class MfmRenderer MfmNodeTypes.MfmBlockNode mfmBlockNode => throw new NotImplementedException($"{mfmBlockNode.GetType()}"), MfmNodeTypes.MfmBoldNode mfmBoldNode => MfmBoldNode(mfmBoldNode, document), MfmNodeTypes.MfmEmojiCodeNode mfmEmojiCodeNode => MfmEmojiCodeNode(mfmEmojiCodeNode, document, emoji, simple), - MfmNodeTypes.MfmFnNode mfmFnNode => throw new NotImplementedException($"{mfmFnNode.GetType()}"), + MfmNodeTypes.MfmFnNode mfmFnNode => MfmFnNode(mfmFnNode, document), MfmNodeTypes.MfmHashtagNode mfmHashtagNode => MfmHashtagNode(mfmHashtagNode, document), MfmNodeTypes.MfmInlineCodeNode mfmInlineCodeNode => MfmInlineCodeNode(mfmInlineCodeNode, document), MfmNodeTypes.MfmItalicNode mfmItalicNode => MfmItalicNode(mfmItalicNode, document), @@ -242,4 +243,106 @@ public static class MfmRenderer return link; } + + private static INode MfmFnNode(MfmNodeTypes.MfmFnNode node, IDocument document) + { + // FSharpOption is a pain to work with in C#, this makes dealing with the args a lot easier + var args = FSharpOption>>.get_IsSome(node.Args) + ? node.Args.Value.ToDictionary(p => p.Key, + p => FSharpOption.get_IsSome(p.Value) ? p.Value.Value : null) + : new Dictionary(); + + return node.Name switch { + "flip" => MfmFnFlip(args, document), + "font" => MfmFnFont(args, document), + "x2" => MfmFnX(node.Name, document), + "x3" => MfmFnX(node.Name, document), + "x4" => MfmFnX(node.Name, document), + "blur" => MfmFnBlur(document), + "jelly" => throw new NotImplementedException($"{node.Name}"), + "tada" => throw new NotImplementedException($"{node.Name}"), + "jump" => throw new NotImplementedException($"{node.Name}"), + "bounce" => throw new NotImplementedException($"{node.Name}"), + "spin" => throw new NotImplementedException($"{node.Name}"), + "shake" => throw new NotImplementedException($"{node.Name}"), + "twitch" => throw new NotImplementedException($"{node.Name}"), + "rainbow" => throw new NotImplementedException($"{node.Name}"), + "sparkle" => throw new NotImplementedException($"{node.Name}"), + "rotate" => MfmFnRotate(args, document), + "fade" => throw new NotImplementedException($"{node.Name}"), + "crop" => throw new NotImplementedException($"{node.Name}"), + "position" => throw new NotImplementedException($"{node.Name}"), + "scale" => throw new NotImplementedException($"{node.Name}"), + "fg" => throw new NotImplementedException($"{node.Name}"), + "bg" => throw new NotImplementedException($"{node.Name}"), + "border" => throw new NotImplementedException($"{node.Name}"), + "ruby" => throw new NotImplementedException($"{node.Name}"), + "unixtime" => throw new NotImplementedException($"{node.Name}"), + _ => throw new NotImplementedException($"{node.Name}") + }; + } + + private static INode MfmFnFlip(Dictionary args, IDocument document) + { + var el = document.CreateElement("span"); + + if (args.ContainsKey("h") && args.ContainsKey("v")) + el.ClassName = "fn-flip h v"; + else if (args.ContainsKey("v")) + el.ClassName = "fn-flip v"; + else + el.ClassName = "fn-flip h"; + + return el; + } + + private static INode MfmFnFont(Dictionary args, IDocument document) + { + var el = document.CreateElement("span"); + + if (args.ContainsKey("serif")) + el.SetAttribute("style", "font-family: serif;"); + else if (args.ContainsKey("monospace")) + el.SetAttribute("style", "font-family: monospace;"); + else if (args.ContainsKey("cursive")) + el.SetAttribute("style", "font-family: cursive;"); + else if (args.ContainsKey("fantasy")) + el.SetAttribute("style", "font-family: fantasy;"); + + return el; + } + + private static INode MfmFnX(string name, IDocument document) + { + var el = document.CreateElement("span"); + + el.ClassName = "fn-x"; + el.SetAttribute("data-scale", name.Replace("x", "")); + + return el; + } + + private static INode MfmFnBlur(IDocument document) + { + var el = document.CreateElement("span"); + + el.ClassName = "fn-blur"; + + return el; + } + + private static INode MfmFnRotate(Dictionary args, IDocument document) + { + var el = document.CreateElement("span"); + + var deg = args.GetValueOrDefault("deg") ?? "90"; + + el.ClassName = "fn-rotate"; + if (args.ContainsKey("x")) + el.SetAttribute("style", $"transform: perspective(120px) rotateX({deg}deg);"); + else + el.SetAttribute("style", $"transform: rotate({deg}deg);"); + + return el; + } } \ No newline at end of file