feat/live-preview #8
@ -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);
|
||||||
|
|||||||
@ -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" />
|
||||||
|
|||||||
@ -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 */
|
.link-title {
|
||||||
@@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 {
|
|
||||||
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;
|
||||||
|
}
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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>
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user