Skip to content

Commit bc1d8e3

Browse files
committed
Add Width to nodes, add Width and Color to cards
1 parent 3d23a52 commit bc1d8e3

File tree

20 files changed

+531
-41
lines changed

20 files changed

+531
-41
lines changed

src/HeyBox.Net.Core/Entities/Messages/Cards/Card.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,23 @@ public class Card : ICard, IEquatable<Card>, IEquatable<ICard>
1313
/// <inheritdoc />
1414
public CardType Type => CardType.Card;
1515

16-
internal Card(ImmutableArray<IModule> modules)
16+
internal Card(CssColor? color, CardSize size, ImmutableArray<IModule> modules)
1717
{
18+
Color = color;
19+
Size = size;
1820
Modules = modules;
1921
}
2022

23+
/// <summary>
24+
/// 获取卡片侧边的颜色。
25+
/// </summary>
26+
public CssColor? Color { get; }
27+
28+
/// <summary>
29+
/// 获取卡片的大小。
30+
/// </summary>
31+
public CardSize Size { get; }
32+
2133
/// <summary>
2234
/// 获取卡片的模块。
2335
/// </summary>

src/HeyBox.Net.Core/Entities/Messages/Cards/CardBuilder.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,56 @@ public class CardBuilder : ICardBuilder, IEquatable<CardBuilder>, IEquatable<ICa
1818
/// <summary>
1919
/// 初始化一个 <see cref="CardBuilder"/> 类的新实例。
2020
/// </summary>
21+
/// <param name="color"> 卡片侧边的颜色。 </param>
22+
/// <param name="size"> 卡片的大小。 </param>
2123
/// <param name="modules"> 卡片的模块。 </param>
22-
public CardBuilder(IList<IModuleBuilder>? modules = null)
24+
public CardBuilder(CssColor? color = null, CardSize size = CardSize.Medium, IList<IModuleBuilder>? modules = null)
2325
{
26+
Color = color;
27+
Size = size;
2428
Modules = modules ?? [];
2529
}
2630

31+
/// <summary>
32+
/// 获取或设置卡片左侧边的 CSS 颜色。
33+
/// </summary>
34+
/// <remarks>
35+
/// 未设置时等效于 <see cref="HeyBox.CssColor.Default"/>。
36+
/// </remarks>
37+
public CssColor? Color { get; set; }
38+
39+
/// <summary>
40+
/// 获取或设置卡片的大小。
41+
/// </summary>
42+
public CardSize Size { get; set; }
43+
2744
/// <summary>
2845
/// 获取或设置卡片的模块。
2946
/// </summary>
3047
public IList<IModuleBuilder> Modules { get; set; }
3148

49+
/// <summary>
50+
/// 设置卡片侧边的颜色。
51+
/// </summary>
52+
/// <param name="color"> 卡片侧边的颜色。 </param>
53+
/// <returns> 当前构建器。 </returns>
54+
public CardBuilder WithColor(CssColor? color)
55+
{
56+
Color = color;
57+
return this;
58+
}
59+
60+
/// <summary>
61+
/// 设置卡片的大小。
62+
/// </summary>
63+
/// <param name="size"> 卡片的大小。 </param>
64+
/// <returns> 当前构建器。 </returns>
65+
public CardBuilder WithSize(CardSize size)
66+
{
67+
Size = size;
68+
return this;
69+
}
70+
3271
/// <summary>
3372
/// 添加一个模块到卡片。
3473
/// </summary>
@@ -75,7 +114,7 @@ public Card Build()
75114
throw new ArgumentException("The modules of the card cannot be empty.", nameof(Modules));
76115
if (Modules.Count > MaxModuleCount)
77116
throw new ArgumentException($"The modules of the card cannot exceed {MaxModuleCount}.", nameof(Modules));
78-
return new Card([..Modules.Select(m => m.Build())]);
117+
return new Card(Color, Size, [..Modules.Select(m => m.Build())]);
79118
}
80119

81120
/// <inheritdoc />
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace HeyBox;
2+
3+
/// <summary>
4+
/// 表示卡片的大小。
5+
/// </summary>
6+
public enum CardSize
7+
{
8+
/// <summary>
9+
/// 卡片的尺寸较小。
10+
/// </summary>
11+
Small,
12+
13+
/// <summary>
14+
/// 卡片的尺寸适中。
15+
/// </summary>
16+
Medium
17+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
using System.Globalization;
2+
3+
namespace HeyBox;
4+
5+
/// <summary>
6+
/// 表示一个 CSS 颜色值,参见
7+
/// <see href="https://developer.mozilla.org/docs/Web/CSS/color_value">&lt;color&gt; - CSS: Cascading Style Sheets | MDN</see>。
8+
/// </summary>
9+
public readonly struct CssColor : IEquatable<CssColor>
10+
{
11+
/// <summary>
12+
/// 获取颜色的字符串值。
13+
/// </summary>
14+
public string Value { get; } = string.Empty;
15+
16+
/// <summary>
17+
/// 获取一个表示默认颜色的 <see cref="CssColor"/> 实例。
18+
/// </summary>
19+
/// <remarks>
20+
/// 黑盒语音客户端将使用等同于 <c>CssColor.FromVariable("--brank-fill")</c> 的值。
21+
/// </remarks>
22+
public static CssColor Default { get; } = new(string.Empty);
23+
24+
/// <summary>
25+
/// 获取一个表示透明颜色的 <see cref="CssColor"/> 实例。
26+
/// </summary>
27+
public static CssColor Transparent { get; } = new("transparent");
28+
29+
/// <summary>
30+
/// 使用指定的颜色字符串值初始化 <see cref="CssColor"/> 结构。
31+
/// </summary>
32+
/// <param name="value">颜色的字符串值。</param>
33+
private CssColor(string value)
34+
{
35+
Value = value;
36+
}
37+
38+
/// <summary>
39+
/// 通过颜色值创建 <see cref="CssColor"/> 实例。
40+
/// </summary>
41+
/// <param name="value"> CSS 颜色值字符串。</param>
42+
/// <returns> 对应的 <see cref="CssColor"/> 实例。</returns>
43+
public static CssColor FromValue(string value) => new(value);
44+
45+
/// <summary>
46+
/// 通过颜色名称创建 <see cref="CssColor"/> 实例。
47+
/// </summary>
48+
/// <param name="name">CSS 颜色名称。</param>
49+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
50+
/// <exception cref="ArgumentException">当 <paramref name="name"/> 为空或无效时抛出。</exception>
51+
public static CssColor FromName(string name)
52+
{
53+
if (string.IsNullOrWhiteSpace(name))
54+
throw new ArgumentException("Color name cannot be null or empty.", nameof(name));
55+
return new CssColor(name);
56+
}
57+
58+
/// <summary>
59+
/// 通过十六进制颜色值创建 <see cref="CssColor"/> 实例。
60+
/// </summary>
61+
/// <param name="hex">十六进制颜色值(如 <c>#FFF</c> 或 <c>#FFFFFF</c>)。</param>
62+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
63+
/// <exception cref="ArgumentException">当 <paramref name="hex"/> 格式无效时抛出。</exception>
64+
public static CssColor FromHex(string hex)
65+
{
66+
if (string.IsNullOrWhiteSpace(hex) ||
67+
hex.Length is not (4 or 7) ||
68+
!hex.StartsWith('#'))
69+
throw new ArgumentException("Invalid hex color format.", nameof(hex));
70+
return new CssColor(hex);
71+
}
72+
73+
/// <summary>
74+
/// 通过 RGB 值创建 <see cref="CssColor"/> 实例。
75+
/// </summary>
76+
/// <param name="r">红色分量(0-255)。</param>
77+
/// <param name="g">绿色分量(0-255)。</param>
78+
/// <param name="b">蓝色分量(0-255)。</param>
79+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
80+
public static CssColor FromRgb(byte r, byte g, byte b) => new($"rgb({r}, {g}, {b})");
81+
82+
/// <summary>
83+
/// 通过 RGBA 值创建 <see cref="CssColor"/> 实例。
84+
/// </summary>
85+
/// <param name="r">红色分量(0-255)。</param>
86+
/// <param name="g">绿色分量(0-255)。</param>
87+
/// <param name="b">蓝色分量(0-255)。</param>
88+
/// <param name="a">透明度(0-1)。</param>
89+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
90+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="a"/> 不在 0 到 1 范围内时抛出。</exception>
91+
public static CssColor FromRgba(byte r, byte g, byte b, float a)
92+
{
93+
if (a is < 0 or > 1)
94+
throw new ArgumentOutOfRangeException(nameof(a), "Alpha must be between 0 and 1.");
95+
return new CssColor($"rgba({r}, {g}, {b}, {a.ToString(CultureInfo.InvariantCulture)})");
96+
}
97+
98+
/// <summary>
99+
/// 通过 HSL 值创建 <see cref="CssColor"/> 实例。
100+
/// </summary>
101+
/// <param name="h">色调(0-360)。</param>
102+
/// <param name="s">饱和度(0-100)。</param>
103+
/// <param name="l">亮度(0-100)。</param>
104+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
105+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="h"/>、<paramref name="s"/> 或 <paramref name="l"/> 不在有效范围内时抛出。</exception>
106+
public static CssColor FromHsl(float h, float s, float l)
107+
{
108+
if (h is < 0 or >= 360)
109+
throw new ArgumentOutOfRangeException(nameof(h), "Hue must be between 0 and 360.");
110+
if (s is < 0 or > 100)
111+
throw new ArgumentOutOfRangeException(nameof(s), "Saturation must be between 0 and 100.");
112+
if (l is < 0 or > 100)
113+
throw new ArgumentOutOfRangeException(nameof(l), "Lightness must be between 0 and 100.");
114+
return new CssColor($"hsl({h.ToString(CultureInfo.InvariantCulture)}, {s.ToString(CultureInfo.InvariantCulture)}%, {l.ToString(CultureInfo.InvariantCulture)}%)");
115+
}
116+
117+
/// <summary>
118+
/// 通过 HSLA 值创建 <see cref="CssColor"/> 实例。
119+
/// </summary>
120+
/// <param name="h">色调(0-360)。</param>
121+
/// <param name="s">饱和度(0-100)。</param>
122+
/// <param name="l">亮度(0-100)。</param>
123+
/// <param name="a">透明度(0-1)。</param>
124+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
125+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="h"/>、<paramref name="s"/>、<paramref name="l"/> 或 <paramref name="a"/> 不在有效范围内时抛出。</exception>
126+
public static CssColor FromHsla(float h, float s, float l, float a)
127+
{
128+
if (h is < 0 or >= 360)
129+
throw new ArgumentOutOfRangeException(nameof(h), "Hue must be between 0 and 360.");
130+
if (s is < 0 or > 100)
131+
throw new ArgumentOutOfRangeException(nameof(s), "Saturation must be between 0 and 100.");
132+
if (l is < 0 or > 100)
133+
throw new ArgumentOutOfRangeException(nameof(l), "Lightness must be between 0 and 100.");
134+
if (a is < 0 or > 1)
135+
throw new ArgumentOutOfRangeException(nameof(a), "Alpha must be between 0 and 1.");
136+
return new CssColor($"hsla({h.ToString(CultureInfo.InvariantCulture)}, {s.ToString(CultureInfo.InvariantCulture)}%, {l.ToString(CultureInfo.InvariantCulture)}%, {a.ToString(CultureInfo.InvariantCulture)})");
137+
}
138+
139+
/// <summary>
140+
/// 通过 CSS 变量名创建 <see cref="CssColor"/> 实例。
141+
/// </summary>
142+
/// <param name="variableName">CSS 变量名(不包含 <c>var()</c> 前缀,例如 <c>--brand-fill</c>)。</param>
143+
/// <returns>对应的 <see cref="CssColor"/> 实例。</returns>
144+
/// <exception cref="ArgumentException">当 <paramref name="variableName"/> 为空或无效时抛出。</exception>
145+
public static CssColor FromVariable(string variableName)
146+
{
147+
if (string.IsNullOrWhiteSpace(variableName))
148+
throw new ArgumentException("CSS variable name cannot be null or empty.", nameof(variableName));
149+
return new CssColor($"var(--{variableName.TrimStart('-')})");
150+
}
151+
152+
/// <inheritdoc cref="HeyBox.CssColor.Value" />
153+
public override string ToString() => Value;
154+
155+
/// <inheritdoc />
156+
public override bool Equals(object? obj) => obj is CssColor other && Equals(other);
157+
158+
/// <inheritdoc />
159+
public bool Equals(CssColor other) => Value == other.Value;
160+
161+
/// <inheritdoc />
162+
public override int GetHashCode() => Value.GetHashCode();
163+
164+
/// <summary>
165+
/// 确定两个 <see cref="CssColor"/> 实例是否相等。
166+
/// </summary>
167+
/// <param name="left">左侧的 <see cref="CssColor"/> 实例。</param>
168+
/// <param name="right">右侧的 <see cref="CssColor"/> 实例。</param>
169+
/// <returns>如果相等,则为 true;否则为 false。</returns>
170+
public static bool operator ==(CssColor left, CssColor right) => left.Equals(right);
171+
172+
/// <summary>
173+
/// 确定两个 <see cref="CssColor"/> 实例是否不相等。
174+
/// </summary>
175+
/// <param name="left">左侧的 <see cref="CssColor"/> 实例。</param>
176+
/// <param name="right">右侧的 <see cref="CssColor"/> 实例。</param>
177+
/// <returns>如果不相等,则为 true;否则为 false。</returns>
178+
public static bool operator !=(CssColor left, CssColor right) => !(left == right);
179+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
namespace HeyBox;
2+
3+
/// <summary>
4+
/// 表示一个 CSS 宽度的结构体。
5+
/// </summary>
6+
public readonly struct NodeWidth : IEquatable<NodeWidth>
7+
{
8+
/// <summary>
9+
/// 获取宽度的字符串值。
10+
/// </summary>
11+
public string Value { get; } = string.Empty;
12+
13+
/// <summary>
14+
/// 获取一个表示默认宽度的 <see cref="NodeWidth"/> 实例。
15+
/// </summary>
16+
public static NodeWidth Default { get; } = new(string.Empty);
17+
18+
/// <summary>
19+
/// 使用指定的宽度字符串值初始化 <see cref="NodeWidth"/> 结构。
20+
/// </summary>
21+
/// <param name="value">宽度的字符串值。</param>
22+
private NodeWidth(string value)
23+
{
24+
Value = value;
25+
}
26+
27+
/// <summary>
28+
/// 通过宽度值创建 <see cref="NodeWidth"/> 实例。
29+
/// </summary>
30+
/// <param name="value"> 宽度值字符串。</param>
31+
/// <returns> 对应的 <see cref="NodeWidth"/> 实例。</returns>
32+
public static NodeWidth FromValue(string value) => new(value);
33+
34+
/// <summary>
35+
/// 通过像素值创建 <see cref="NodeWidth"/> 实例。
36+
/// </summary>
37+
/// <param name="pixels"> 像素值,必须为非负整数。</param>
38+
/// <returns> 对应的 <see cref="NodeWidth"/> 实例。</returns>
39+
/// <exception cref="ArgumentOutOfRangeException"> 当 <paramref name="pixels"/> 小于 0 时抛出。</exception>
40+
public static NodeWidth FromPixels(int pixels)
41+
{
42+
if (pixels < 0)
43+
throw new ArgumentOutOfRangeException(nameof(pixels), "Pixel value cannot be negative.");
44+
return new NodeWidth($"{pixels}px");
45+
}
46+
47+
/// <summary>
48+
/// 通过百分比值创建 <see cref="NodeWidth"/> 实例。
49+
/// </summary>
50+
/// <param name="percentage"> 百分比值,必须为非负数。</param>
51+
/// <returns> 对应的 <see cref="NodeWidth"/> 实例。</returns>
52+
/// <exception cref="ArgumentOutOfRangeException"> 当 <paramref name="percentage"/> 小于 0 时抛出。</exception>
53+
public static NodeWidth FromPercentage(double percentage)
54+
{
55+
if (percentage < 0)
56+
throw new ArgumentOutOfRangeException(nameof(percentage), "Percentage value must be between 0 and 100.");
57+
return new NodeWidth($"{percentage}%");
58+
}
59+
60+
/// <inheritdoc cref="HeyBox.NodeWidth.Value" />
61+
public override string ToString() => Value;
62+
63+
/// <inheritdoc />
64+
public override bool Equals(object? obj) => obj is NodeWidth other && Equals(other);
65+
66+
/// <inheritdoc />
67+
public bool Equals(NodeWidth other) => Value == other.Value;
68+
69+
/// <inheritdoc />
70+
public override int GetHashCode() => Value.GetHashCode();
71+
72+
/// <summary>
73+
/// 确定两个 <see cref="NodeWidth"/> 实例是否相等。
74+
/// </summary>
75+
/// <param name="left">左侧的 <see cref="NodeWidth"/> 实例。</param>
76+
/// <param name="right">右侧的 <see cref="NodeWidth"/> 实例。</param>
77+
/// <returns>如果相等,则为 true;否则为 false。</returns>
78+
public static bool operator ==(NodeWidth left, NodeWidth right) => left.Equals(right);
79+
80+
/// <summary>
81+
/// 确定两个 <see cref="NodeWidth"/> 实例是否不相等。
82+
/// </summary>
83+
/// <param name="left">左侧的 <see cref="NodeWidth"/> 实例。</param>
84+
/// <param name="right">右侧的 <see cref="NodeWidth"/> 实例。</param>
85+
/// <returns>如果不相等,则为 true;否则为 false。</returns>
86+
public static bool operator !=(NodeWidth left, NodeWidth right) => !(left == right);
87+
}

0 commit comments

Comments
 (0)