feat/live-preview #8
@ -24,7 +24,8 @@ public class UserPageController : Controller
|
||||
}
|
||||
|
||||
//[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)
|
||||
{
|
||||
var userPage = await _userPageService.GetPageAsync(category, slug);
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
<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="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="icon" type="image/x-icon" href="~/favicon.ico" />
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@model BCards.Web.Models.PageTheme
|
||||
|
||||
@{
|
||||
var theme = Model ?? new BCards.Web.Models.PageTheme
|
||||
{
|
||||
@ -8,9 +9,6 @@
|
||||
BackgroundColor = "#ffffff",
|
||||
TextColor = "#1f2937"
|
||||
};
|
||||
|
||||
// Debug - vamos ver o que está chegando
|
||||
// Console.WriteLine($"Theme recebido: {Model?.Name ?? "NULL"} - Primary: {Model?.PrimaryColor ?? "NULL"}");
|
||||
}
|
||||
|
||||
:root {
|
||||
@ -18,28 +16,27 @@
|
||||
--secondary-color: @theme.SecondaryColor;
|
||||
--background-color: @theme.BackgroundColor;
|
||||
--text-color: @theme.TextColor;
|
||||
--card-bg: rgba(255, 255, 255, 0.95);
|
||||
--border-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.user-page {
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
@if (!string.IsNullOrEmpty(theme.BackgroundImage))
|
||||
{
|
||||
@:background-image: url('@theme.BackgroundImage');
|
||||
@:background-size: cover;
|
||||
@:background-position: center;
|
||||
@:background-attachment: fixed;
|
||||
}
|
||||
min-height: 100vh;
|
||||
padding: 2rem 0;
|
||||
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
background-color: var(--card-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
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;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.profile-image {
|
||||
@ -56,15 +53,20 @@
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
border: 4px solid var(--primary-color);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-color: var(--card-bg);
|
||||
color: var(--primary-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 3rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
color: var(--primary-color);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
margin: 1rem 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.profile-bio {
|
||||
@ -74,76 +76,309 @@
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* ========== LINKS CONTAINER ========== */
|
||||
.links-container {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
background-color: var(--primary-color);
|
||||
color: white !important;
|
||||
border: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
/* ========== UNIVERSAL LINK STYLE (TODOS OS LINKS IGUAIS) ========== */
|
||||
.universal-link {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
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;
|
||||
max-width: 100%;
|
||||
font-size: 0.95rem;
|
||||
background-color: var(--card-bg);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.link-button:hover {
|
||||
background-color: var(--secondary-color);
|
||||
.universal-link:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link-button:active {
|
||||
transform: translateY(0);
|
||||
.universal-link-header {
|
||||
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 {
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
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;
|
||||
opacity: 0.9;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.link-icon {
|
||||
font-size: 1.2rem;
|
||||
margin-right: 0.5rem;
|
||||
.expand-arrow.expanded i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.profile-footer {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding-top: 1rem;
|
||||
/* Conteúdo expandido */
|
||||
.universal-link-details {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
.profile-footer a:hover {
|
||||
.footer-credits a:hover {
|
||||
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) {
|
||||
.user-page {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
padding: 1.5rem;
|
||||
margin: 1rem;
|
||||
margin: 0 1rem;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
@ -157,21 +392,31 @@
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
.profile-bio {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
padding: 0.65rem 1.25rem;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.6rem;
|
||||
.universal-link-header {
|
||||
padding: 0.65rem 0.8rem;
|
||||
}
|
||||
|
||||
.link-title {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -179,7 +424,7 @@
|
||||
@@media (max-width: 480px) {
|
||||
.profile-card {
|
||||
padding: 1rem;
|
||||
margin: 0.5rem;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.profile-image,
|
||||
@ -192,137 +437,57 @@
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
padding: 0.6rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.universal-link-header {
|
||||
padding: 0.6rem 0.8rem;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
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 {
|
||||
.link-title {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.product-description {
|
||||
.link-subtitle {
|
||||
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;
|
||||
}
|
||||
@ -42,7 +42,9 @@
|
||||
}
|
||||
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.min.css" />
|
||||
|
||||
<link rel="stylesheet" href="~/css/userpage.css" asp-append-version="true" />
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="~/favicon.ico" />
|
||||
|
||||
@await RenderSectionAsync("Styles", required: false)
|
||||
|
||||
@ -11,7 +11,15 @@
|
||||
@section Styles {
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<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>
|
||||
}
|
||||
|
||||
@ -27,8 +35,8 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="profile-image-placeholder mb-3 mx-auto d-flex align-items-center justify-content-center">
|
||||
<i class="fs-1">👤</i>
|
||||
<div class="profile-image-placeholder mb-3 mx-auto">
|
||||
👤
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -40,7 +48,7 @@
|
||||
<p class="profile-bio">@Model.Bio</p>
|
||||
}
|
||||
|
||||
<!-- Links -->
|
||||
<!-- Links Container -->
|
||||
<div class="links-container">
|
||||
@if (Model.Links?.Any(l => l.IsActive) == true)
|
||||
{
|
||||
@ -49,76 +57,122 @@
|
||||
var link = Model.Links[i];
|
||||
if (link.IsActive)
|
||||
{
|
||||
@if (link.Type == BCards.Web.Models.LinkType.Product)
|
||||
{
|
||||
<!-- Card de Produto -->
|
||||
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"
|
||||
class="text-decoration-none mb-3 d-block product-link"
|
||||
data-link-index="@i"
|
||||
onclick="recordClick('@Model.Id', @i)">
|
||||
<div class="card product-link-card">
|
||||
<div class="row g-0">
|
||||
@if (!string.IsNullOrEmpty(link.ProductImage))
|
||||
rel="noopener noreferrer">
|
||||
|
||||
<div class="universal-link-content">
|
||||
@if (link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductImage))
|
||||
{
|
||||
<div class="col-md-4">
|
||||
<!-- Thumbnail para produtos -->
|
||||
<img src="@link.ProductImage"
|
||||
class="img-fluid product-image"
|
||||
alt="@(link.ProductTitle ?? link.Title)"
|
||||
class="link-thumbnail"
|
||||
loading="lazy"
|
||||
onerror="this.style.display='none'">
|
||||
</div>
|
||||
}
|
||||
<div class="@(string.IsNullOrEmpty(link.ProductImage) ? "col-12" : "col-md-8")">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title product-title">
|
||||
@(!string.IsNullOrEmpty(link.ProductTitle) ? link.ProductTitle : link.Title)
|
||||
</h6>
|
||||
@if (!string.IsNullOrEmpty(link.ProductDescription))
|
||||
else if (!string.IsNullOrEmpty(link.Icon))
|
||||
{
|
||||
<p class="card-text small text-muted product-description">
|
||||
@link.ProductDescription
|
||||
</p>
|
||||
}
|
||||
@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>
|
||||
<!-- Ícone para links normais -->
|
||||
<div class="link-icon">
|
||||
<i class="@link.Icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Link Normal -->
|
||||
<a href="@link.Url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link-button"
|
||||
data-link-index="@i"
|
||||
onclick="recordClick('@Model.Id', @i)">
|
||||
@if (!string.IsNullOrEmpty(link.Icon))
|
||||
{
|
||||
<i class="@link.Icon"></i>
|
||||
<!-- Ícone padrão se não tiver -->
|
||||
<div class="link-icon">
|
||||
<i class="fas fa-link"></i>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<div class="link-title">@link.Title</div>
|
||||
@if (!string.IsNullOrEmpty(link.Description))
|
||||
|
||||
<div class="link-text-container">
|
||||
<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>
|
||||
</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>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="profile-footer mt-4 pt-3 border-top">
|
||||
<small class="text-muted">
|
||||
Criado com <a href="@Url.Action("Index", "Home")" class="text-decoration-none">BCards</a>
|
||||
</small>
|
||||
<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>
|
||||
</div>
|
||||
@ -151,8 +224,8 @@
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
// Função original de rastreamento de cliques
|
||||
function recordClick(pageId, linkIndex) {
|
||||
// Record click asynchronously
|
||||
fetch('/click/' + pageId, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -163,5 +236,82 @@
|
||||
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>
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user