feat(themes): mini-mockup preview in theme cards

This commit is contained in:
2026-05-05 14:13:19 +02:00
parent af4651b37e
commit 8f9c01d322
2 changed files with 79 additions and 16 deletions
@@ -0,0 +1,70 @@
using System.Numerics;
using Dalamud.Bindings.ImGui;
using HellionChat.Themes;
using HellionChat.Util;
namespace HellionChat.Ui.SettingsTabs;
internal static class ThemeMockup
{
// Zeichnet ein Mini-Chat-Window-Mockup mit den Theme-Werten direkt
// ins WindowDrawList. Keine Texture, keine Allocation pro Frame —
// alles via DrawList.AddRectFilled / AddText.
public static void Draw(Vector2 origin, Vector2 size, Theme theme)
{
var draw = ImGui.GetWindowDrawList();
var c = theme.Colors;
// Window-Bg
draw.AddRectFilled(origin, origin + size, ColourUtil.RgbaToAbgr(c.WindowBg | 0xFFu), theme.Layout.WindowRounding);
// Title-Bar
var titleHeight = 14f;
draw.AddRectFilled(
origin,
new Vector2(origin.X + size.X, origin.Y + titleHeight),
ColourUtil.RgbaToAbgr(c.Identity), theme.Layout.WindowRounding);
// Tab-Bar — 3 Mini-Tabs
var tabY = origin.Y + titleHeight + 4f;
var tabHeight = 12f;
for (var i = 0; i < 3; i++)
{
var tabX = origin.X + 6f + i * 28f;
var color = i == 0 ? c.FrameBg : c.ChildBg;
draw.AddRectFilled(
new Vector2(tabX, tabY),
new Vector2(tabX + 26f, tabY + tabHeight),
ColourUtil.RgbaToAbgr(color), theme.Layout.TabRounding);
if (i == 0) // Active-Pill
{
draw.AddRectFilled(
new Vector2(tabX, tabY + tabHeight - 2f),
new Vector2(tabX + 26f, tabY + tabHeight),
ColourUtil.RgbaToAbgr(c.Primary));
}
}
// Card-Row mit Mock-Sender + Text
var rowY = tabY + tabHeight + 6f;
var rowHeight = 18f;
draw.AddRectFilled(
new Vector2(origin.X + 6f, rowY),
new Vector2(origin.X + size.X - 6f, rowY + rowHeight),
ColourUtil.RgbaToAbgr(c.Surface), 2f);
// Akzent-Button rechts unten
var btnW = 28f;
var btnH = 10f;
var btnX = origin.X + size.X - btnW - 6f;
var btnY = origin.Y + size.Y - btnH - 6f;
draw.AddRectFilled(
new Vector2(btnX, btnY),
new Vector2(btnX + btnW, btnY + btnH),
ColourUtil.RgbaToAbgr(c.Accent), theme.Layout.FrameRounding);
// Border um das gesamte Mockup
draw.AddRect(origin, origin + size, ColourUtil.RgbaToAbgr(c.Border), theme.Layout.WindowRounding);
}
}
+9 -16
View File
@@ -82,7 +82,7 @@ internal sealed class Themes : ISettingsTab
var avail = ImGui.GetContentRegionAvail(); var avail = ImGui.GetContentRegionAvail();
var columns = avail.X >= 700f ? 3 : 2; var columns = avail.X >= 700f ? 3 : 2;
var cardWidth = (avail.X - (columns - 1) * 8f) / columns; var cardWidth = (avail.X - (columns - 1) * 8f) / columns;
var cardHeight = 110f; var cardHeight = 140f; // war 110f — Mockup braucht mehr Platz
var i = 0; var i = 0;
foreach (var theme in themes) foreach (var theme in themes)
{ {
@@ -117,30 +117,23 @@ internal sealed class Themes : ISettingsTab
draw.AddRect(cursorBefore, cursorBefore + new Vector2(w, h), border, 4f, ImDrawFlags.None, 1f); draw.AddRect(cursorBefore, cursorBefore + new Vector2(w, h), border, 4f, ImDrawFlags.None, 1f);
} }
// Akzent-Swatch links oben // Mini-Mockup statt Akzent-Swatch — visualisiert das Theme im Mini-Chat-Window
var swatchPos = cursorBefore + new Vector2(12f, 12f); var mockupOrigin = cursorBefore + new Vector2(12f, 12f);
var swatchSize = new Vector2(20f, 20f); var mockupSize = new Vector2(w - 24f, 60f);
draw.AddRectFilled(swatchPos, swatchPos + swatchSize, ColourUtil.RgbaToAbgr(theme.Colors.Primary), 3f); ThemeMockup.Draw(mockupOrigin, mockupSize, theme);
// Name // Name unter dem Mockup
ImGui.SetCursorScreenPos(cursorBefore + new Vector2(40f, 12f)); ImGui.SetCursorScreenPos(cursorBefore + new Vector2(12f, 78f));
var textColor = ColourUtil.RgbaToAbgr(theme.Colors.TextPrimary); var textColor = ColourUtil.RgbaToAbgr(theme.Colors.TextPrimary);
using (ImRaii.PushColor(ImGuiCol.Text, textColor)) using (ImRaii.PushColor(ImGuiCol.Text, textColor))
ImGui.TextUnformatted(theme.Name); ImGui.TextUnformatted(theme.Name);
// Author // Author dahinter dezent
ImGui.SetCursorScreenPos(cursorBefore + new Vector2(40f, 32f)); ImGui.SetCursorScreenPos(cursorBefore + new Vector2(12f, 96f));
var mutedColor = ColourUtil.RgbaToAbgr(theme.Colors.TextMuted); var mutedColor = ColourUtil.RgbaToAbgr(theme.Colors.TextMuted);
using (ImRaii.PushColor(ImGuiCol.Text, mutedColor)) using (ImRaii.PushColor(ImGuiCol.Text, mutedColor))
ImGui.TextUnformatted(theme.Author); ImGui.TextUnformatted(theme.Author);
// Description (wrapped, falls zu lang)
ImGui.SetCursorScreenPos(cursorBefore + new Vector2(12f, 60f));
ImGui.PushTextWrapPos(cursorBefore.X + w - 12f);
using (ImRaii.PushColor(ImGuiCol.Text, mutedColor))
ImGui.TextUnformatted(theme.Description);
ImGui.PopTextWrapPos();
// Cursor unter die Card setzen // Cursor unter die Card setzen
ImGui.SetCursorScreenPos(cursorBefore + new Vector2(0f, h + 8f)); ImGui.SetCursorScreenPos(cursorBefore + new Vector2(0f, h + 8f));