Adding vibe hover effect

This commit is contained in:
2026-07-18 16:23:21 -04:00
parent 74f065e0f5
commit 4ce33bdb36
17 changed files with 550 additions and 308 deletions
+9 -3
View File
@@ -1,4 +1,5 @@
@namespace Shared.Pages
@inject Shared.Services.CardPreviewService PreviewService
@page "/agents"
<PageTitle>Chrono CCG - Agents</PageTitle>
@@ -29,10 +30,15 @@
</GridColumn>
<GridColumn Field="@nameof(CardData.Name)" Title="Card" Width="220px">
<Template>
<div class="agent-name-cell">
<img src="@(((CardData)context).ImagePath)" alt="@(((CardData)context).Name)"
@{
var card = (CardData)context;
}
<div class="agent-name-cell"
@onmouseenter="@(e => PreviewService.Show(card, e.ClientX, e.ClientY))"
@onmouseleave="@(() => PreviewService.Hide())">
<img src="@(card.ImagePath)" alt="@(card.Name)"
class="agent-thumb"/>
<span>@(((CardData)context).Name)</span>
<span>@(card.Name)</span>
</div>
</Template>
</GridColumn>
+3 -2
View File
@@ -1,5 +1,6 @@
@namespace Shared.Pages
@inject CardRenderingService CardRenderer
@inject Shared.Services.CardPreviewService PreviewService
@page "/decks/{Name}"
<PageTitle>Chrono CCG - @(deck?.Name ?? "Deck Details")</PageTitle>
@@ -75,7 +76,7 @@
<section class="deck-section description">
<h2><i class="bi bi-chat-quote-fill"></i> Description</h2>
<div class="deck-description">
@CardRenderer.RenderDescription(deck.Description, SelectCard)
@CardRenderer.RenderDescription(deck.Description, SelectCard, doc => PreviewService.SelectDoc(doc), PreviewService)
</div>
</section>
}
@@ -86,7 +87,7 @@
<CardDetailModal Card="selectedCard"
OnClose="CloseDetail"
OnSelectCard="SelectCard"
DescriptionRenderer="@(desc => CardRenderer.RenderDescription(desc, SelectCard))"/>
DescriptionRenderer="@(desc => CardRenderer.RenderDescription(desc, SelectCard, doc => PreviewService.SelectDoc(doc), PreviewService))"/>
@code {
[Parameter] public string Name { get; set; } = "";
+5 -1
View File
@@ -1,3 +1,5 @@
@inject Shared.Services.CardRenderingService CardRenderer
@inject Shared.Services.CardPreviewService PreviewService
@namespace Shared.Pages
@page "/docs"
@@ -85,7 +87,9 @@
@if (key == "description")
{
<p class="doc-field-desc">@val</p>
<div class="doc-field-desc">
@CardRenderer.RenderDescription(val, _ => {}, doc => PreviewService.SelectDoc(doc), PreviewService)
</div>
}
else
{
+105
View File
@@ -0,0 +1,105 @@
@page "/syndicate-pairings"
@namespace Shared.Pages
<HeadContent>
<meta name="description" content="Explore all syndicate pairings in Chrono CCG."/>
</HeadContent>
<div class="syndicates-container">
<div class="syndicates-header">
<h1>Syndicate Pairings</h1>
<p class="text-secondary">Explore all @pairings.Count combinations of syndicates</p>
</div>
<div class="pairings-grid">
@foreach (var doc in pairings)
{
var s1 = doc.Syndicates?[0] ?? "";
var s2 = doc.Syndicates?[1] ?? "";
<div class="pairing-card" @onclick="() => OpenPairing(doc)">
<div class="pairing-display">
<div class="syndicate-item @s1.ToLowerInvariant()">
<span class="syn-icon"></span>
<span class="syn-name">@s1</span>
</div>
<div class="pairing-separator">
<i class="bi bi-x-lg"></i>
</div>
<div class="syndicate-item @s2.ToLowerInvariant()">
<span class="syn-icon"></span>
<span class="syn-name">@s2</span>
</div>
</div>
<div class="pairing-info">
<span class="pairing-label">Dual-Syndicate Pairing</span>
</div>
</div>
}
</div>
</div>
<Shared.Components.SyndicatePairDialog Doc="selectedDoc" OnClose="ClosePairing" OnNavigate="HandleNavigate"/>
<Shared.Components.CardDetailModal Card="selectedCard" IsVisible="@(selectedCard != null)" OnClose="CloseCard" />
<Shared.Components.DocDetailModal Doc="selectedGenericDoc" OnClose="CloseGenericDoc"/>
@code {
private List<DocData> pairings = [];
private DocData? selectedDoc;
private CardData? selectedCard;
private DocData? selectedGenericDoc;
protected override void OnInitialized()
{
pairings = DocDatabase.Docs
.Where(d => d.Category == "Syndicate Pairings")
.OrderBy(d => d.Title)
.ToList();
}
private void OpenPairing(DocData doc)
{
selectedDoc = doc;
}
private void ClosePairing()
{
selectedDoc = null;
}
private void CloseCard()
{
selectedCard = null;
}
private void CloseGenericDoc()
{
selectedGenericDoc = null;
}
private void HandleNavigate(string name)
{
var card = CardDatabase.Cards.FirstOrDefault(c => string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase));
if (card != null)
{
if (card.Category is "Agent" or "Spell")
{
selectedCard = card;
}
else
{
selectedGenericDoc = new DocData { Title = card.Name, Content = card.Description ?? "", Category = card.Category };
}
StateHasChanged();
return;
}
var doc = DocDatabase.Docs.FirstOrDefault(d => string.Equals(d.Title, name, StringComparison.OrdinalIgnoreCase));
if (doc != null)
{
selectedGenericDoc = doc;
StateHasChanged();
}
}
}
@@ -0,0 +1,130 @@
.syndicates-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.syndicates-header {
margin-bottom: 2rem;
text-align: center;
}
.pairings-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.pairing-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
transition: transform var(--transition), box-shadow var(--transition);
cursor: pointer;
}
.pairing-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow);
border-color: var(--accent);
}
.pairing-display {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
width: 100%;
justify-content: center;
}
.syndicate-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.syn-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 10px currentColor;
}
.syn-name {
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
}
.pairing-separator {
color: var(--text-muted);
font-size: 0.8rem;
opacity: 0.5;
}
.pairing-info {
border-top: 1px solid var(--border);
padding-top: 0.75rem;
width: 100%;
text-align: center;
}
.pairing-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
}
.syn-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 10px currentColor;
display: inline-block; /* Ensure visibility */
}
/* Syndicate Colors */
.singularity {
color: #ffffff;
}
.phasetide {
color: #2196f3;
}
.silence {
color: #9c27b0;
}
.lifeblood {
color: #4caf50;
}
.sungrace {
color: #ff9800;
}
.splintergleam {
color: #f44336;
}
@media (max-width: 600px) {
.pairings-grid {
grid-template-columns: 1fr;
}
.syndicates-container {
padding: 1rem;
}
}
+97
View File
@@ -0,0 +1,97 @@
@page "/syndicates"
@namespace Shared.Pages
<HeadContent>
<meta name="description" content="Explore each syndicate in Chrono CCG."/>
</HeadContent>
<div class="syndicates-container">
<div class="syndicates-header">
<h1>Syndicates</h1>
<p class="text-secondary">Explore the @syndicates.Count core syndicates of Chrono CCG</p>
</div>
<div class="pairings-grid">
@foreach (var doc in syndicates)
{
var s = doc.Title;
<div class="pairing-card" @onclick="() => OpenSyndicate(doc)">
<div class="pairing-display">
<div class="syndicate-item @s.ToLowerInvariant()">
<span class="syn-icon"></span>
<span class="syn-name">@s</span>
</div>
</div>
<div class="pairing-info">
<span class="pairing-label">Syndicate</span>
</div>
</div>
}
</div>
</div>
<Shared.Components.SyndicateDialog Doc="selectedDoc" OnClose="CloseSyndicate" OnNavigate="HandleNavigate"/>
<Shared.Components.CardDetailModal Card="selectedCard" IsVisible="@(selectedCard != null)" OnClose="CloseCard" />
<Shared.Components.DocDetailModal Doc="selectedGenericDoc" OnClose="CloseGenericDoc"/>
@code {
private List<DocData> syndicates = [];
private DocData? selectedDoc;
private CardData? selectedCard;
private DocData? selectedGenericDoc;
protected override void OnInitialized()
{
syndicates = DocDatabase.Docs
.Where(d => d.Category == "Syndicate")
.OrderBy(d => d.Title)
.ToList();
}
private void OpenSyndicate(DocData doc)
{
selectedDoc = doc;
}
private void CloseSyndicate()
{
selectedDoc = null;
}
private void CloseCard()
{
selectedCard = null;
}
private void CloseGenericDoc()
{
selectedGenericDoc = null;
}
private void HandleNavigate(string name)
{
var card = CardDatabase.Cards.FirstOrDefault(c => string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase));
if (card != null)
{
if (card.Category is "Agent" or "Spell")
{
selectedCard = card;
}
else
{
selectedGenericDoc = new DocData { Title = card.Name, Content = card.Description ?? "", Category = card.Category };
}
StateHasChanged();
return;
}
var doc = DocDatabase.Docs.FirstOrDefault(d => string.Equals(d.Title, name, StringComparison.OrdinalIgnoreCase));
if (doc != null)
{
selectedGenericDoc = doc;
StateHasChanged();
}
}
}
+116
View File
@@ -0,0 +1,116 @@
.syndicates-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.syndicates-header {
margin-bottom: 2rem;
text-align: center;
}
.pairings-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
}
.pairing-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
transition: transform var(--transition), box-shadow var(--transition);
cursor: pointer;
}
.pairing-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow);
border-color: var(--accent);
}
.pairing-display {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
width: 100%;
justify-content: center;
}
.syndicate-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.syn-icon {
width: 24px;
height: 24px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 10px currentColor;
display: inline-block;
}
.syn-name {
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
}
.pairing-info {
border-top: 1px solid var(--border);
padding-top: 0.75rem;
width: 100%;
text-align: center;
}
.pairing-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
}
/* Syndicate Colors */
.singularity {
color: #ffffff;
}
.phasetide {
color: #2196f3;
}
.silence {
color: #9c27b0;
}
.lifeblood {
color: #4caf50;
}
.sungrace {
color: #ff9800;
}
.splintergleam {
color: #f44336;
}
@media (max-width: 600px) {
.pairings-grid {
grid-template-columns: 1fr;
}
.syndicates-container {
padding: 1rem;
}
}