feat: implement link embed functionality to enhance message previews with metadata and thumbnails

This commit is contained in:
HueByte
2026-02-19 21:21:51 +01:00
parent 6965ba573e
commit 7167b40013
18 changed files with 740 additions and 15 deletions
+3
View File
@@ -455,6 +455,9 @@ public static partial class ChatColors
public static readonly Attribute SystemAttr = new(new Color(0, 180, 180), Color.Black);
public static readonly Attribute MentionHighlightAttr = new(Color.White, new Color(80, 40, 0));
public static readonly Attribute MentionTextAttr = new(new Color(255, 180, 50), Color.Black);
public static readonly Attribute EmbedBorderAttr = new(new Color(91, 155, 213), Color.Black);
public static readonly Attribute EmbedTitleAttr = new(Color.White, Color.Black);
public static readonly Attribute EmbedDescAttr = new(new Color(160, 160, 160), Color.Black);
/// <summary>
/// Split text around @mentions, giving each @word the MentionTextAttr accent color.
+67
View File
@@ -890,6 +890,10 @@ public sealed class MainWindow : Runnable
var contText = $"{indent}{contentLines[i].TrimEnd('\r')}";
lines.Add(new ChatLine(ChatColors.SplitMentions(contText)));
}
// Render link embed if present
if (message.Embed is not null)
lines.AddRange(FormatEmbed(message.Embed, indent));
break;
}
@@ -938,4 +942,67 @@ public sealed class MainWindow : Runnable
segments.AddRange(ChatColors.SplitMentions(suffix));
return new ChatLine(segments);
}
/// <summary>
/// Format a link embed as indented chat lines with a left border bar.
/// </summary>
private static List<ChatLine> FormatEmbed(EmbedDto embed, string indent)
{
var lines = new List<ChatLine>();
const string border = "\u258f "; // ▏ + space
// Site name
if (!string.IsNullOrWhiteSpace(embed.SiteName))
{
lines.Add(new ChatLine(new List<ChatSegment>
{
new(indent, null),
new(border, ChatColors.EmbedBorderAttr),
new(embed.SiteName, ChatColors.EmbedBorderAttr)
}));
}
// Title
if (!string.IsNullOrWhiteSpace(embed.Title))
{
lines.Add(new ChatLine(new List<ChatSegment>
{
new(indent, null),
new(border, ChatColors.EmbedBorderAttr),
new(embed.Title, ChatColors.EmbedTitleAttr)
}));
}
// Description (truncated)
if (!string.IsNullOrWhiteSpace(embed.Description))
{
var desc = embed.Description.Length > 120
? embed.Description[..117] + "..."
: embed.Description;
lines.Add(new ChatLine(new List<ChatSegment>
{
new(indent, null),
new(border, ChatColors.EmbedBorderAttr),
new(desc, ChatColors.EmbedDescAttr)
}));
}
// ASCII image thumbnail
if (!string.IsNullOrWhiteSpace(embed.ImageAscii))
{
foreach (var artLine in embed.ImageAscii.Split('\n'))
{
var trimmed = artLine.TrimEnd('\r');
if (string.IsNullOrEmpty(trimmed)) continue;
if (ChatLine.HasColorTags(trimmed))
lines.Add(ChatLine.FromColoredText(indent + border + trimmed));
else
lines.Add(new ChatLine(indent + border + trimmed));
}
}
return lines;
}
}