340 lines
16 KiB
Plaintext
340 lines
16 KiB
Plaintext
@model BCards.Web.Models.IPageDisplay
|
|
@{
|
|
var seo = ViewBag.SeoSettings as BCards.Web.Models.SeoSettings;
|
|
var category = ViewBag.Category as BCards.Web.Models.Category;
|
|
var isPreview = ViewBag.IsPreview as bool? ?? false;
|
|
var isLivePage = ViewBag.IsLivePage as bool? ?? false;
|
|
|
|
ViewData["Title"] = seo?.Title ?? $"{Model.DisplayName} - {category?.Name}";
|
|
Layout = isPreview ? "_Layout" : "_UserPageLayout";
|
|
}
|
|
|
|
@section Head {
|
|
@if (isPreview)
|
|
{
|
|
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet">
|
|
}
|
|
else if (isLivePage)
|
|
{
|
|
<meta name="robots" content="index, follow">
|
|
@if (!string.IsNullOrEmpty(ViewBag.PageUrl as string))
|
|
{
|
|
<link rel="canonical" href="@ViewBag.PageUrl">
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<meta name="robots" content="noindex, nofollow">
|
|
}
|
|
}
|
|
|
|
@section Styles {
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<style>
|
|
@{
|
|
var partialOutput = await Html.PartialAsync("_ThemeStyles", Model.Theme);
|
|
using (var writer = new System.IO.StringWriter())
|
|
{
|
|
partialOutput.WriteTo(writer, HtmlEncoder);
|
|
@Html.Raw(writer.ToString())
|
|
}
|
|
}
|
|
</style>
|
|
}
|
|
|
|
<div class="user-page min-vh-100 d-flex align-items-center py-4">
|
|
<div class="container">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-6 col-md-8">
|
|
<div class="profile-card mx-auto">
|
|
<!-- Profile Image & Info -->
|
|
<div class="profile-header text-center mb-4">
|
|
@if (!string.IsNullOrEmpty(Model.ProfileImageId))
|
|
{
|
|
<img src="@Model.ProfileImageUrl" alt="@Model.DisplayName" class="profile-image-large rounded-circle mb-3">
|
|
}
|
|
else
|
|
{
|
|
<div class="profile-icon-placeholder mb-3">
|
|
<i class="fas fa-id-card"></i>
|
|
</div>
|
|
}
|
|
<h1 class="profile-name mb-0">@Model.DisplayName</h1>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
|
|
@if (!string.IsNullOrEmpty(Model.Bio))
|
|
{
|
|
<p class="profile-bio">@Model.Bio</p>
|
|
}
|
|
|
|
<!-- Links Container -->
|
|
<div class="links-container">
|
|
@if (Model.Links?.Any(l => l.IsActive) == true)
|
|
{
|
|
@for (int i = 0; i < Model.Links.Count; i++)
|
|
{
|
|
var link = Model.Links[i];
|
|
if (link.IsActive)
|
|
{
|
|
var hasExpandableContent = (!string.IsNullOrEmpty(link.Description) ||
|
|
(link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductDescription)));
|
|
|
|
<!-- 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"
|
|
class="universal-link-header"
|
|
onclick="recordClick('@Model.Id', @i)"
|
|
target="_blank"
|
|
rel="noopener noreferrer">
|
|
|
|
<div class="universal-link-content">
|
|
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductImage))
|
|
{
|
|
<!-- Thumbnail para produtos -->
|
|
<img src="@link.ProductImage"
|
|
alt="@(link.ProductTitle ?? link.Title)"
|
|
class="link-thumbnail"
|
|
loading="lazy"
|
|
onerror="this.style.display='none'">
|
|
}
|
|
else if (!string.IsNullOrEmpty(link.Icon))
|
|
{
|
|
<!-- Ícone para links normais -->
|
|
<div class="link-icon">
|
|
<i class="@link.Icon"></i>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<!-- Ícone padrão se não tiver -->
|
|
<div class="link-icon">
|
|
<i class="fas fa-link"></i>
|
|
</div>
|
|
}
|
|
|
|
<div class="link-text-container">
|
|
<div class="link-title">
|
|
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductTitle))
|
|
{
|
|
@link.ProductTitle
|
|
}
|
|
else
|
|
{
|
|
@link.Title
|
|
}
|
|
</div>
|
|
|
|
@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>
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<div class="text-muted">
|
|
<p>Nenhum link disponível no momento.</p>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="profile-footer">
|
|
|
|
<!-- Promoção BCards -->
|
|
<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> <!-- /text-center -->
|
|
</div> <!-- /profile-card -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (isPreview)
|
|
{
|
|
<div class="position-fixed top-0 start-0 w-100 bg-warning text-dark text-center py-2" style="z-index: 9999;">
|
|
<strong>MODO PREVIEW</strong> - Esta é uma prévia da sua página
|
|
</div>
|
|
}
|
|
|
|
@section Scripts {
|
|
<script>
|
|
// Função original de rastreamento de cliques
|
|
function recordClick(pageId, linkIndex) {
|
|
fetch('/click/' + pageId, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ linkIndex: linkIndex })
|
|
}).catch(function(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>
|
|
} |