Repository navigation
Expand file tree
/
Copy pathCellComponent.razor
More file actions
151 lines (133 loc) · 6.26 KB
/
Copy pathCellComponent.razor
File metadata and controls
151 lines (133 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
@namespace ChainReaction.Components
@using ChainReaction.Model
<div class="game-cell shrink-0 select-none @(cell.IsCritical ? "cell-critical" : "")"
style="@GetCellStyle()"
@onclick="OnClick"
@onmouseenter="OnEnter"
@onmouseleave="OnExit"
title="@GetCellTooltip()">
@if (cell.CurrentCount > 0)
{
var size = Config.CellHeight;
var orbRadius = size < 38 ? 12 : (size < 50 ? 16 : 20);
var gradId = $"orb-grad-{cell.X}-{cell.Y}";
var shadowId = $"orb-shadow-{cell.X}-{cell.Y}";
var criticalClass = cell.IsCritical ? "orb-critical-spin" : "";
<svg width="100%" height="100%" viewBox="0 0 200 200" class="overflow-visible pointer-events-none">
<defs>
<!-- 3D Spherical Radial Gradient -->
<radialGradient id="@gradId" cx="35%" cy="35%" r="65%">
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.9" />
<stop offset="35%" stop-color="@cell.Color" />
<stop offset="80%" stop-color="@GetDarkerColor(cell.Color, 0.75)" />
<stop offset="100%" stop-color="@GetDarkerColor(cell.Color, 0.45)" />
</radialGradient>
<!-- Soft Drop Shadow -->
<filter id="@shadowId" x="-30%" y="-30%" width="160%" height="160%">
<feDropShadow dx="0" dy="3" stdDeviation="5" flood-color="@cell.Color" flood-opacity="0.5" />
</filter>
</defs>
@if (cell.CurrentCount == 1)
{
<!-- Single Centered Orb with Gentle Breathing -->
<g class="orb-breath" style="transform-origin: 100px 100px;">
<circle cx="100" cy="100" r="@(orbRadius * 1.7)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="89" cy="89" r="@(orbRadius * 0.45)" fill="#ffffff" opacity="0.65" />
</g>
}
else if (cell.CurrentCount == 2)
{
<!-- Two Orbs Revolving Smoothly -->
<g class="orb-orbit-2 @criticalClass">
<circle cx="64" cy="100" r="@(orbRadius * 1.4)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="55" cy="91" r="@(orbRadius * 0.38)" fill="#ffffff" opacity="0.65" />
<circle cx="136" cy="100" r="@(orbRadius * 1.4)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="127" cy="91" r="@(orbRadius * 0.38)" fill="#ffffff" opacity="0.65" />
</g>
}
else if (cell.CurrentCount >= 3)
{
<!-- Three Orbs in Revolving Constellation -->
<g class="orb-orbit-3 @criticalClass">
<circle cx="100" cy="64" r="@(orbRadius * 1.3)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="92" cy="56" r="@(orbRadius * 0.35)" fill="#ffffff" opacity="0.65" />
<circle cx="68" cy="126" r="@(orbRadius * 1.3)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="60" cy="118" r="@(orbRadius * 0.35)" fill="#ffffff" opacity="0.65" />
<circle cx="132" cy="126" r="@(orbRadius * 1.3)"
fill="url(#@gradId)"
filter="url(#@shadowId)" />
<circle cx="124" cy="118" r="@(orbRadius * 0.35)" fill="#ffffff" opacity="0.65" />
</g>
}
</svg>
}
else if (isHovered && IsCurrentPlayerValid())
{
<!-- Ghost preview orb on hover -->
<div class="w-1/3 h-1/3 rounded-full opacity-35 animate-pulse pointer-events-none shadow-sm"
style="background: @Config.CurrentUserColor;"></div>
}
<!-- Subtle Capacity Dot Marker in Bottom Corner -->
<div class="absolute bottom-1 right-1 flex gap-0.5 pointer-events-none opacity-25">
@for (int i = 0; i < cell.Capacity; i++)
{
<div class="w-1 h-1 rounded-full @(i < cell.CurrentCount ? "bg-amber-400 opacity-90" : "bg-slate-500")"></div>
}
</div>
</div>
@code {
[Parameter] public Cell cell { get; set; } = new();
[Parameter] public EventCallback OnClick { get; set; }
[Parameter] public string CurrentPlayerName { get; set; } = string.Empty;
private bool isHovered = false;
private void OnEnter() => isHovered = true;
private void OnExit() => isHovered = false;
private bool IsCurrentPlayerValid() =>
string.IsNullOrEmpty(cell.Name) || cell.Name == CurrentPlayerName;
private string GetCellStyle()
{
var h = Config.CellHeight;
var isOwned = !string.IsNullOrEmpty(cell.Name);
var borderStyle = isOwned
? $"border: 2px solid {cell.Color}; color: {cell.Color};"
: "border: 1px solid rgba(51, 65, 85, 0.45); color: rgba(148, 163, 184, 0.4);";
var bgStyle = isOwned
? "background: rgba(15, 23, 42, 0.8);"
: "background: rgba(15, 23, 42, 0.5);";
return $"width:{h}px; height:{h}px; min-width:{h}px; min-height:{h}px; {borderStyle} {bgStyle}";
}
private string GetCellTooltip()
{
return $"{cell.CellTypeName} Cell ({cell.CurrentCount}/{cell.Capacity} orbs)";
}
private string GetDarkerColor(string colorStr, double factor)
{
if (string.IsNullOrEmpty(colorStr)) return "#0f172a";
try
{
if (colorStr.StartsWith("rgb"))
{
var nums = colorStr.Replace("rgb(", "").Replace("rgba(", "").Replace(")", "").Split(',');
if (nums.Length >= 3)
{
int r = Math.Max(0, (int)(int.Parse(nums[0].Trim()) * factor));
int g = Math.Max(0, (int)(int.Parse(nums[1].Trim()) * factor));
int b = Math.Max(0, (int)(int.Parse(nums[2].Trim()) * factor));
return $"rgb({r},{g},{b})";
}
}
}
catch {}
return colorStr;
}
}