fix: paginas de links funcionando

This commit is contained in:
Ricardo Carneiro 2025-06-26 00:25:11 -03:00
parent 2b3d9f308d
commit 603698c9c0
5 changed files with 594 additions and 275 deletions

View File

@ -24,7 +24,8 @@ public class UserPageController : Controller
} }
//[Route("{category}/{slug}")] //[Route("{category}/{slug}")]
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "category", "slug" })] //VOltar a linha abaixo em prod
//[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "category", "slug" })]
public async Task<IActionResult> Display(string category, string slug) public async Task<IActionResult> Display(string category, string slug)
{ {
var userPage = await _userPageService.GetPageAsync(category, slug); var userPage = await _userPageService.GetPageAsync(category, slug);

View File

@ -31,6 +31,7 @@
<meta name="keywords" content="linktree, links, página profissional, perfil, redes sociais, cartão digital" /> <meta name="keywords" content="linktree, links, página profissional, perfil, redes sociais, cartão digital" />
} }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="icon" type="image/x-icon" href="~/favicon.ico" /> <link rel="icon" type="image/x-icon" href="~/favicon.ico" />

View File

@ -1,4 +1,5 @@
@model BCards.Web.Models.PageTheme @model BCards.Web.Models.PageTheme
@{ @{
var theme = Model ?? new BCards.Web.Models.PageTheme var theme = Model ?? new BCards.Web.Models.PageTheme
{ {
@ -8,9 +9,6 @@
BackgroundColor = "#ffffff", BackgroundColor = "#ffffff",
TextColor = "#1f2937" TextColor = "#1f2937"
}; };
// Debug - vamos ver o que está chegando
// Console.WriteLine($"Theme recebido: {Model?.Name ?? "NULL"} - Primary: {Model?.PrimaryColor ?? "NULL"}");
} }
:root { :root {
@ -18,28 +16,27 @@
--secondary-color: @theme.SecondaryColor; --secondary-color: @theme.SecondaryColor;
--background-color: @theme.BackgroundColor; --background-color: @theme.BackgroundColor;
--text-color: @theme.TextColor; --text-color: @theme.TextColor;
--card-bg: rgba(255, 255, 255, 0.95);
--border-color: rgba(0, 0, 0, 0.1);
} }
.user-page { .user-page {
background-color: var(--background-color); background-color: var(--background-color);
color: var(--text-color); color: var(--text-color);
@if (!string.IsNullOrEmpty(theme.BackgroundImage)) min-height: 100vh;
{ padding: 2rem 0;
@:background-image: url('@theme.BackgroundImage');
@:background-size: cover;
@:background-position: center;
@:background-attachment: fixed;
}
} }
.profile-card { .profile-card {
background-color: rgba(255, 255, 255, 0.95); background-color: var(--card-bg);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
border-radius: 20px; border-radius: 20px;
padding: 2rem; padding: 2rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2); border: 1px solid var(--border-color);
max-width: 500px; max-width: 500px;
margin: 0 auto;
} }
.profile-image { .profile-image {
@ -56,15 +53,20 @@
height: 120px; height: 120px;
border-radius: 50%; border-radius: 50%;
border: 4px solid var(--primary-color); border: 4px solid var(--primary-color);
background-color: rgba(255, 255, 255, 0.1); background-color: var(--card-bg);
color: var(--primary-color); color: var(--primary-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
margin: 0 auto;
} }
.profile-name { .profile-name {
color: var(--primary-color); color: var(--primary-color);
font-size: 2rem; font-size: 2rem;
font-weight: 600; font-weight: 600;
margin-bottom: 0.5rem; margin: 1rem 0 0.5rem 0;
} }
.profile-bio { .profile-bio {
@ -74,76 +76,309 @@
font-size: 1.1rem; font-size: 1.1rem;
} }
/* ========== LINKS CONTAINER ========== */
.links-container { .links-container {
margin-bottom: 2rem; margin-bottom: 2rem;
} }
.link-button { /* ========== UNIVERSAL LINK STYLE (TODOS OS LINKS IGUAIS) ========== */
background-color: var(--primary-color); .universal-link {
color: white !important; border: 1px solid var(--border-color);
border: none;
padding: 0.75rem 1.5rem;
border-radius: 12px; border-radius: 12px;
text-decoration: none;
display: block;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
text-align: center;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden; overflow: hidden;
max-width: 100%; background-color: var(--card-bg);
font-size: 0.95rem; transition: all 0.3s ease;
} }
.link-button:hover { .universal-link:hover {
background-color: var(--secondary-color);
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
color: white !important;
text-decoration: none;
} }
.link-button:active { .universal-link-header {
transform: translateY(0); background-color: var(--primary-color);
color: white !important;
padding: 0.75rem 1rem;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
text-decoration: none !important;
transition: background-color 0.3s ease;
position: relative;
font-weight: 500;
}
.universal-link-header:hover {
background-color: var(--secondary-color);
color: white !important;
text-decoration: none !important;
}
.universal-link-content {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
text-align: left;
}
/* Thumbnail para produtos */
.link-thumbnail {
width: 40px;
height: 40px;
border-radius: 6px;
object-fit: cover;
margin-right: 0.75rem;
flex-shrink: 0;
background-color: rgba(255, 255, 255, 0.2);
}
/* Ícone para links normais */
.link-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.75rem;
flex-shrink: 0;
font-size: 1.2rem;
color: white;
}
.link-text-container {
flex: 1;
min-width: 0;
} }
.link-title { .link-title {
font-size: 1.1rem;
margin-bottom: 0.25rem;
font-weight: 600; font-weight: 600;
font-size: 1rem;
color: white;
margin: 0;
line-height: 1.2;
/* Truncate long titles */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
.link-description { .link-subtitle {
font-size: 0.85rem;
color: rgba(255, 255, 255, 0.8);
margin: 0;
line-height: 1.1;
/* Truncate long subtitles */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Seta de expansão */
.expand-arrow {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
border-radius: 6px;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
flex-shrink: 0;
margin-left: 0.5rem;
}
.expand-arrow:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.05);
}
.expand-arrow i {
font-size: 0.9rem; font-size: 0.9rem;
opacity: 0.9; transition: transform 0.3s ease;
} }
.link-icon { .expand-arrow.expanded i {
font-size: 1.2rem; transform: rotate(180deg);
margin-right: 0.5rem;
} }
.profile-footer { /* Conteúdo expandido */
border-top: 1px solid rgba(0, 0, 0, 0.1); .universal-link-details {
padding-top: 1rem; padding: 0;
background-color: var(--card-bg);
border-top: 1px solid var(--border-color);
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out, padding 0.3s ease;
} }
.profile-footer a { .universal-link-details.show {
max-height: 400px;
padding: 1rem;
}
/* Imagem expandida para produtos */
.expanded-image {
width: 100%;
max-width: 200px;
height: auto;
border-radius: 8px;
margin-bottom: 1rem;
display: block;
margin-left: auto;
margin-right: auto;
}
.expanded-description {
color: var(--text-color);
opacity: 0.8;
font-size: 0.9rem;
line-height: 1.5;
margin-bottom: 0.75rem;
}
.expanded-price {
color: #28a745;
font-weight: 700;
font-size: 1.1rem;
margin-bottom: 0.75rem;
text-align: center;
}
.expanded-action {
color: var(--primary-color); color: var(--primary-color);
font-size: 0.85rem;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
}
/* ========== FOOTER ========== */
.profile-footer {
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid var(--border-color);
text-align: center;
}
.footer-promo {
background-color: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.footer-promo:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.footer-promo-header {
display: flex;
align-items: center;
justify-content: space-between;
color: var(--primary-color);
font-weight: 600;
font-size: 0.9rem;
}
.footer-promo-header i {
transition: transform 0.3s ease;
}
.footer-promo-header.expanded i {
transform: rotate(180deg);
}
.footer-promo-content {
margin-top: 0.5rem;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out, margin-top 0.3s ease;
color: var(--text-color);
opacity: 0.8;
font-size: 0.85rem;
line-height: 1.4;
}
.footer-promo-content.show {
max-height: 200px;
margin-top: 0.75rem;
}
.footer-promo-button {
background-color: var(--primary-color);
color: white !important;
border: none;
padding: 0.4rem 0.8rem;
border-radius: 6px;
text-decoration: none !important;
font-size: 0.8rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
margin-top: 0.5rem;
transition: background-color 0.3s ease;
}
.footer-promo-button:hover {
background-color: var(--secondary-color);
color: white !important;
text-decoration: none !important;
}
.footer-credits {
font-size: 0.8rem;
color: var(--text-color);
opacity: 0.6;
}
.footer-credits a {
color: var(--primary-color);
text-decoration: none;
font-weight: 500; font-weight: 500;
} }
.profile-footer a:hover { .footer-credits a:hover {
color: var(--secondary-color); color: var(--secondary-color);
text-decoration: underline;
} }
/* Responsive Design */ /* ========== ANIMATIONS ========== */
@@keyframes slideDown {
from {
max-height: 0;
padding-top: 0;
padding-bottom: 0;
opacity: 0;
}
to {
max-height: 400px;
padding-top: 1rem;
padding-bottom: 1rem;
opacity: 1;
}
}
/* ========== RESPONSIVE DESIGN ========== */
@@media (max-width: 768px) { @@media (max-width: 768px) {
.user-page {
padding: 1rem 0;
}
.profile-card { .profile-card {
padding: 1.5rem; padding: 1.5rem;
margin: 1rem; margin: 0 1rem;
border-radius: 15px; border-radius: 15px;
} }
@ -157,21 +392,31 @@
font-size: 1.75rem; font-size: 1.75rem;
} }
.profile-bio { .universal-link-header {
font-size: 1rem; padding: 0.65rem 0.8rem;
}
.link-button {
padding: 0.65rem 1.25rem;
font-size: 0.9rem;
margin-bottom: 0.6rem;
} }
.link-title { .link-title {
font-size: 0.95rem; font-size: 0.95rem;
} }
.link-description { .link-subtitle {
font-size: 0.8rem;
}
.link-thumbnail,
.link-icon {
width: 36px;
height: 36px;
margin-right: 0.5rem;
}
.expand-arrow {
width: 28px;
height: 28px;
}
.expand-arrow i {
font-size: 0.8rem; font-size: 0.8rem;
} }
} }
@ -179,7 +424,7 @@
@@media (max-width: 480px) { @@media (max-width: 480px) {
.profile-card { .profile-card {
padding: 1rem; padding: 1rem;
margin: 0.5rem; margin: 0 0.5rem;
} }
.profile-image, .profile-image,
@ -192,137 +437,57 @@
font-size: 1.5rem; font-size: 1.5rem;
} }
.link-button { .universal-link-header {
padding: 0.6rem 1rem; padding: 0.6rem 0.8rem;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
}
/* Dark theme adjustments */
@@media (prefers-color-scheme: dark) {
.user-page[data-theme="dark"] .profile-card {
background-color: rgba(17, 24, 39, 0.95);
color: #f9fafb;
}
}
/* Animation for link buttons */
.link-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.link-button:hover::before {
left: 100%;
}
/* Product Link Card Styles */
.product-link-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 15px;
overflow: hidden;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
}
.product-link-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
border-color: var(--primary-color);
}
.product-image {
height: 120px;
width: 100%;
object-fit: cover;
border-radius: 15px 0 0 15px;
}
.product-title {
color: var(--primary-color);
font-weight: 600;
margin-bottom: 0.5rem;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.product-description {
font-size: 0.85rem;
line-height: 1.4;
margin-bottom: 0.5rem;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.product-price {
font-size: 1.1rem;
font-weight: 700;
color: #28a745 !important;
}
.product-link .card-body {
padding: 1rem;
}
/* Responsive adjustments for product cards */
@@media (max-width: 768px) {
.product-image {
height: 100px;
border-radius: 15px 15px 0 0;
} }
.product-link-card .row { .link-title {
flex-direction: column;
}
.product-link-card .col-md-4,
.product-link-card .col-md-8 {
flex: none;
width: 100%;
max-width: 100%;
}
.product-title {
font-size: 1rem;
}
.product-description {
font-size: 0.8rem;
}
.product-price {
font-size: 1rem;
}
}
@@media (max-width: 480px) {
.product-image {
height: 80px;
}
.product-link .card-body {
padding: 0.75rem;
}
.product-title {
font-size: 0.9rem; font-size: 0.9rem;
} }
.product-description { .link-subtitle {
font-size: 0.75rem; font-size: 0.75rem;
-webkit-line-clamp: 1; }
.link-thumbnail,
.link-icon {
width: 32px;
height: 32px;
margin-right: 0.5rem;
}
.expand-arrow {
width: 26px;
height: 26px;
}
.expanded-image {
max-width: 150px;
} }
} }
/* ========== DARK THEME COMPATIBILITY ========== */
.user-page[data-theme="dark"] .profile-card,
.user-page[data-theme="dark"] .universal-link,
.user-page[data-theme="dark"] .footer-promo {
background-color: rgba(31, 41, 55, 0.95);
border-color: rgba(255, 255, 255, 0.1);
}
.user-page[data-theme="dark"] .universal-link-details,
.user-page[data-theme="dark"] .footer-promo-content {
background-color: rgba(31, 41, 55, 0.95);
border-color: rgba(255, 255, 255, 0.1);
}
/* Accessibility */
.universal-link-header:focus,
.expand-arrow:focus {
outline: 2px solid rgba(255, 255, 255, 0.5);
outline-offset: 2px;
}
/* Smooth scroll for mobile */
.universal-link-details {
scroll-behavior: smooth;
}

View File

@ -42,7 +42,9 @@
} }
<link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/userpage.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/userpage.css" asp-append-version="true" />
<link rel="icon" type="image/x-icon" href="~/favicon.ico" /> <link rel="icon" type="image/x-icon" href="~/favicon.ico" />
@await RenderSectionAsync("Styles", required: false) @await RenderSectionAsync("Styles", required: false)

View File

@ -11,7 +11,15 @@
@section Styles { @section Styles {
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style> <style>
@Html.Raw(await Html.PartialAsync("_ThemeStyles", Model.Theme)) @{
var partialOutput = await Html.PartialAsync("_ThemeStyles", Model.Theme);
using (var writer = new System.IO.StringWriter())
{
partialOutput.WriteTo(writer, HtmlEncoder);
@Html.Raw(writer.ToString())
}
}
</style> </style>
} }
@ -27,8 +35,8 @@
} }
else else
{ {
<div class="profile-image-placeholder mb-3 mx-auto d-flex align-items-center justify-content-center"> <div class="profile-image-placeholder mb-3 mx-auto">
<i class="fs-1">👤</i> 👤
</div> </div>
} }
@ -40,7 +48,7 @@
<p class="profile-bio">@Model.Bio</p> <p class="profile-bio">@Model.Bio</p>
} }
<!-- Links --> <!-- Links Container -->
<div class="links-container"> <div class="links-container">
@if (Model.Links?.Any(l => l.IsActive) == true) @if (Model.Links?.Any(l => l.IsActive) == true)
{ {
@ -49,76 +57,122 @@
var link = Model.Links[i]; var link = Model.Links[i];
if (link.IsActive) if (link.IsActive)
{ {
@if (link.Type == BCards.Web.Models.LinkType.Product) var hasExpandableContent = (!string.IsNullOrEmpty(link.Description) ||
{ (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductDescription)));
<!-- Card de Produto -->
<!-- Universal Link Style (TODOS OS LINKS IGUAIS) -->
<div class="universal-link" data-link-id="@i">
<!-- Header clicável (vai para o link) -->
<a href="@link.Url" <a href="@link.Url"
class="universal-link-header"
onclick="recordClick('@Model.Id', @i)"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer">
class="text-decoration-none mb-3 d-block product-link"
data-link-index="@i" <div class="universal-link-content">
onclick="recordClick('@Model.Id', @i)"> @if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductImage))
<div class="card product-link-card">
<div class="row g-0">
@if (!string.IsNullOrEmpty(link.ProductImage))
{ {
<div class="col-md-4"> <!-- Thumbnail para produtos -->
<img src="@link.ProductImage" <img src="@link.ProductImage"
class="img-fluid product-image"
alt="@(link.ProductTitle ?? link.Title)" alt="@(link.ProductTitle ?? link.Title)"
class="link-thumbnail"
loading="lazy" loading="lazy"
onerror="this.style.display='none'"> onerror="this.style.display='none'">
</div>
} }
<div class="@(string.IsNullOrEmpty(link.ProductImage) ? "col-12" : "col-md-8")"> else if (!string.IsNullOrEmpty(link.Icon))
<div class="card-body">
<h6 class="card-title product-title">
@(!string.IsNullOrEmpty(link.ProductTitle) ? link.ProductTitle : link.Title)
</h6>
@if (!string.IsNullOrEmpty(link.ProductDescription))
{ {
<p class="card-text small text-muted product-description"> <!-- Ícone para links normais -->
@link.ProductDescription <div class="link-icon">
</p> <i class="@link.Icon"></i>
}
@if (!string.IsNullOrEmpty(link.ProductPrice))
{
<p class="card-text">
<strong class="text-success product-price">@link.ProductPrice</strong>
</p>
}
<small class="text-muted">
<i class="fas fa-external-link-alt me-1"></i>
Ver produto
</small>
</div> </div>
</div>
</div>
</div>
</a>
} }
else else
{ {
<!-- Link Normal --> <!-- Ícone padrão se não tiver -->
<a href="@link.Url" <div class="link-icon">
target="_blank" <i class="fas fa-link"></i>
rel="noopener noreferrer" </div>
class="link-button"
data-link-index="@i"
onclick="recordClick('@Model.Id', @i)">
@if (!string.IsNullOrEmpty(link.Icon))
{
<i class="@link.Icon"></i>
} }
<div>
<div class="link-title">@link.Title</div> <div class="link-text-container">
@if (!string.IsNullOrEmpty(link.Description)) <div class="link-title">
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductTitle))
{ {
<div class="link-description">@link.Description</div> @link.ProductTitle
}
else
{
@link.Title
} }
</div> </div>
</a>
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductPrice))
{
<div class="link-subtitle">@link.ProductPrice</div>
} }
else if (!string.IsNullOrEmpty(link.Description) && link.Description.Length > 50)
{
<div class="link-subtitle">@(link.Description.Substring(0, 50))...</div>
}
</div>
</div>
@if (hasExpandableContent)
{
<!-- Seta de expansão (só aparece se tem conteúdo expandível) -->
<button class="expand-arrow"
type="button"
onclick="event.preventDefault(); event.stopPropagation(); toggleLinkDetails(@i)">
<i class="fas fa-chevron-down"></i>
</button>
}
</a>
@if (hasExpandableContent)
{
<!-- Conteúdo expandível -->
<div class="universal-link-details" id="details-@i">
@if (link.Type == BCards.Web.Models.LinkType.Product)
{
<!-- Conteúdo expandido para produtos -->
@if (!string.IsNullOrEmpty(link.ProductImage))
{
<img src="@link.ProductImage"
alt="@(link.ProductTitle ?? link.Title)"
class="expanded-image"
loading="lazy">
}
@if (!string.IsNullOrEmpty(link.ProductPrice))
{
<div class="expanded-price">@link.ProductPrice</div>
}
@if (!string.IsNullOrEmpty(link.ProductDescription))
{
<div class="expanded-description">
@link.ProductDescription
</div>
}
}
else
{
<!-- Conteúdo expandido para links normais -->
@if (!string.IsNullOrEmpty(link.Description))
{
<div class="expanded-description">
@link.Description
</div>
}
}
<div class="expanded-action">
<i class="fas fa-external-link-alt"></i>
Clique no título acima para abrir
</div>
</div>
}
</div>
} }
} }
} }
@ -131,10 +185,29 @@
</div> </div>
<!-- Footer --> <!-- Footer -->
<div class="profile-footer mt-4 pt-3 border-top"> <div class="profile-footer">
<small class="text-muted">
Criado com <a href="@Url.Action("Index", "Home")" class="text-decoration-none">BCards</a> <!-- Promoção BCards -->
</small> <div class="footer-promo" onclick="togglePromo(this)">
<div class="footer-promo-header">
<span>💡 Gostou desta página?</span>
<i class="fas fa-chevron-down"></i>
</div>
<div class="footer-promo-content">
Crie a sua própria página personalizada com <strong>BCards</strong>!
É rápido, fácil e profissional. Compartilhe todos os seus links em um só lugar.
<div class="mt-2">
<a href="@Url.Action("Index", "Home")" class="footer-promo-button">
<i class="fas fa-rocket"></i>
Criar Minha Página
</a>
</div>
</div>
</div>
<div class="footer-credits">
Criado com <a href="@Url.Action("Index", "Home")">BCards</a>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -151,8 +224,8 @@
@section Scripts { @section Scripts {
<script> <script>
// Função original de rastreamento de cliques
function recordClick(pageId, linkIndex) { function recordClick(pageId, linkIndex) {
// Record click asynchronously
fetch('/click/' + pageId, { fetch('/click/' + pageId, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -163,5 +236,82 @@
console.log('Error recording click:', error); console.log('Error recording click:', error);
}); });
} }
// Toggle link details (função universal para todos os links)
function toggleLinkDetails(linkIndex) {
const currentDetails = document.getElementById('details-' + linkIndex);
const currentArrow = document.querySelector('[data-link-id="' + linkIndex + '"] .expand-arrow');
if (!currentDetails || !currentArrow) return;
const isCurrentlyExpanded = currentDetails.classList.contains('show');
// Fechar todos os outros links primeiro (auto-close)
const allDetails = document.querySelectorAll('.universal-link-details');
const allArrows = document.querySelectorAll('.expand-arrow');
allDetails.forEach(details => {
details.classList.remove('show');
});
allArrows.forEach(arrow => {
arrow.classList.remove('expanded');
const icon = arrow.querySelector('i');
if (icon) {
icon.style.transform = 'rotate(0deg)';
}
});
// Se não estava expandido, expandir este
if (!isCurrentlyExpanded) {
currentDetails.classList.add('show');
currentArrow.classList.add('expanded');
const icon = currentArrow.querySelector('i');
if (icon) {
icon.style.transform = 'rotate(180deg)';
}
}
}
// Toggle footer promo
function togglePromo(element) {
const content = element.querySelector('.footer-promo-content');
const arrow = element.querySelector('.footer-promo-header i');
if (content.classList.contains('show')) {
content.classList.remove('show');
arrow.style.transform = 'rotate(0deg)';
element.querySelector('.footer-promo-header').classList.remove('expanded');
} else {
content.classList.add('show');
arrow.style.transform = 'rotate(180deg)';
element.querySelector('.footer-promo-header').classList.add('expanded');
}
}
// Initialize page
document.addEventListener('DOMContentLoaded', function() {
// Garantir que todos os accordions comecem fechados
const allDetails = document.querySelectorAll('.universal-link-details, .footer-promo-content');
allDetails.forEach(detail => {
detail.classList.remove('show');
});
const allArrows = document.querySelectorAll('.expand-arrow i, .footer-promo-header i');
allArrows.forEach(arrow => {
arrow.style.transform = 'rotate(0deg)';
});
// Adicionar eventos de teclado para acessibilidade
const expandButtons = document.querySelectorAll('.expand-arrow');
expandButtons.forEach(button => {
button.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
button.click();
}
});
});
});
</script> </script>
} }