fix: pagina que permite copiar links
All checks were successful
BCards Multi-Tenant Deployment Pipeline / Run Tests (push) Successful in 6s
BCards Multi-Tenant Deployment Pipeline / PR Validation (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Build and Push Image (push) Successful in 8m9s
BCards Multi-Tenant Deployment Pipeline / Deploy to Release Swarm (ARM) (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy bcards.site (push) Successful in 1m3s
BCards Multi-Tenant Deployment Pipeline / Deploy spicylinks.site (push) Successful in 1m3s
BCards Multi-Tenant Deployment Pipeline / Deploy luslinks.site (push) Successful in 1m2s
BCards Multi-Tenant Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deployment Summary (push) Successful in 1s
All checks were successful
BCards Multi-Tenant Deployment Pipeline / Run Tests (push) Successful in 6s
BCards Multi-Tenant Deployment Pipeline / PR Validation (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Build and Push Image (push) Successful in 8m9s
BCards Multi-Tenant Deployment Pipeline / Deploy to Release Swarm (ARM) (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy bcards.site (push) Successful in 1m3s
BCards Multi-Tenant Deployment Pipeline / Deploy spicylinks.site (push) Successful in 1m3s
BCards Multi-Tenant Deployment Pipeline / Deploy luslinks.site (push) Successful in 1m2s
BCards Multi-Tenant Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deployment Summary (push) Successful in 1s
This commit is contained in:
parent
0e7e3d552e
commit
6c2b618b92
@ -14,7 +14,7 @@ public class CreatePageViewModel
|
|||||||
[Required(ErrorMessage = "Tipo de negócio é obrigatório")]
|
[Required(ErrorMessage = "Tipo de negócio é obrigatório")]
|
||||||
public string BusinessType { get; set; } = "individual";
|
public string BusinessType { get; set; } = "individual";
|
||||||
|
|
||||||
[StringLength(200, ErrorMessage = "Bio deve ter no máximo 200 caracteres")]
|
[StringLength(3000, ErrorMessage = "Bio deve ter no máximo 3000 caracteres")]
|
||||||
public string Bio { get; set; } = string.Empty;
|
public string Bio { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Required(ErrorMessage = "Tema é obrigatório")]
|
[Required(ErrorMessage = "Tema é obrigatório")]
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public class ManagePageViewModel
|
|||||||
[Required(ErrorMessage = "Tipo de negócio é obrigatório")]
|
[Required(ErrorMessage = "Tipo de negócio é obrigatório")]
|
||||||
public string BusinessType { get; set; } = "individual";
|
public string BusinessType { get; set; } = "individual";
|
||||||
|
|
||||||
[StringLength(200, ErrorMessage = "Bio deve ter no máximo 200 caracteres")]
|
[StringLength(3000, ErrorMessage = "Bio deve ter no máximo 3000 caracteres")]
|
||||||
public string Bio { get; set; } = string.Empty;
|
public string Bio { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Slug { get; set; } = string.Empty;
|
public string Slug { get; set; } = string.Empty;
|
||||||
|
|||||||
@ -82,8 +82,9 @@
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
||||||
<textarea asp-for="Bio" class="form-control" rows="3" placeholder="Uma breve descrição sobre você ou sua empresa..."></textarea>
|
<textarea asp-for="Bio" class="form-control" rows="8" maxlength="3000" placeholder="Uma breve descrição sobre você ou sua empresa..."></textarea>
|
||||||
<span asp-validation-for="Bio" class="text-danger"></span>
|
<span asp-validation-for="Bio" class="text-danger"></span>
|
||||||
|
<div class="form-text">Máximo 3000 caracteres</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -115,9 +115,9 @@
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
||||||
<textarea asp-for="Bio" class="form-control" rows="3" placeholder="Uma breve descrição sobre você ou sua empresa..."></textarea>
|
<textarea asp-for="Bio" class="form-control" rows="8" maxlength="3000" placeholder="Uma breve descrição sobre você ou sua empresa..."></textarea>
|
||||||
<span asp-validation-for="Bio" class="text-danger"></span>
|
<span asp-validation-for="Bio" class="text-danger"></span>
|
||||||
<div class="form-text">Máximo 200 caracteres</div>
|
<div class="form-text">Máximo 3000 caracteres</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Profile Image Upload -->
|
<!-- Profile Image Upload -->
|
||||||
|
|||||||
@ -176,7 +176,16 @@
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Seta de expansão */
|
/* Seta de expansão e Botão de copiar */
|
||||||
|
.link-actions-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-link-btn,
|
||||||
.expand-arrow {
|
.expand-arrow {
|
||||||
background: rgba(255, 255, 255, 0.2);
|
background: rgba(255, 255, 255, 0.2);
|
||||||
border: none;
|
border: none;
|
||||||
@ -189,15 +198,15 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copy-link-btn:hover,
|
||||||
.expand-arrow:hover {
|
.expand-arrow:hover {
|
||||||
background: rgba(255, 255, 255, 0.3);
|
background: rgba(255, 255, 255, 0.3);
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copy-link-btn i,
|
||||||
.expand-arrow i {
|
.expand-arrow i {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
@ -282,6 +291,20 @@
|
|||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expanded-link {
|
||||||
|
color: var(--primary-color) !important;
|
||||||
|
text-decoration: underline !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded-link:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========== FOOTER ========== */
|
/* ========== FOOTER ========== */
|
||||||
.profile-footer {
|
.profile-footer {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
|
|||||||
@ -376,7 +376,7 @@
|
|||||||
var hasExpandableContent = (!string.IsNullOrEmpty(link.Description) ||
|
var hasExpandableContent = (!string.IsNullOrEmpty(link.Description) ||
|
||||||
(link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductDescription)));
|
(link.Type == BCards.Web.Models.LinkType.Product && !string.IsNullOrEmpty(link.ProductDescription)));
|
||||||
|
|
||||||
<div class="universal-link" data-link-id="@i">
|
<div class="universal-link" id="link-@i" data-link-id="@i">
|
||||||
<a href="@NormalizeSocialUrl(link.Url, link.Icon)"
|
<a href="@NormalizeSocialUrl(link.Url, link.Icon)"
|
||||||
class="universal-link-header"
|
class="universal-link-header"
|
||||||
onclick="recordClick('@Model.Id', @i)"
|
onclick="recordClick('@Model.Id', @i)"
|
||||||
@ -424,6 +424,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="link-actions-container">
|
||||||
|
<button class="copy-link-btn"
|
||||||
|
type="button"
|
||||||
|
title="Copiar link"
|
||||||
|
onclick="event.preventDefault(); event.stopPropagation(); copyAnchorLink('link-@i', this)">
|
||||||
|
<i class="fas fa-copy"></i>
|
||||||
|
</button>
|
||||||
@if (hasExpandableContent)
|
@if (hasExpandableContent)
|
||||||
{
|
{
|
||||||
<button class="expand-arrow"
|
<button class="expand-arrow"
|
||||||
@ -432,6 +439,7 @@
|
|||||||
<i class="fas fa-chevron-down"></i>
|
<i class="fas fa-chevron-down"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@if (hasExpandableContent)
|
@if (hasExpandableContent)
|
||||||
@ -463,8 +471,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
<div class="expanded-action">
|
<div class="expanded-action">
|
||||||
|
<a href="@NormalizeSocialUrl(link.Url, link.Icon)" target="_blank" rel="noopener noreferrer" class="expanded-link">
|
||||||
<i class="fas fa-external-link-alt"></i>
|
<i class="fas fa-external-link-alt"></i>
|
||||||
Clique no título acima para abrir
|
Clique aqui para abrir o link
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -517,8 +527,10 @@
|
|||||||
<div class="universal-link-details" id="details-@uniqueId">
|
<div class="universal-link-details" id="details-@uniqueId">
|
||||||
<div class="expanded-description">@document.Description</div>
|
<div class="expanded-description">@document.Description</div>
|
||||||
<div class="expanded-action">
|
<div class="expanded-action">
|
||||||
|
<a href="/api/document/@document.FileId" target="_blank" rel="noopener noreferrer" class="expanded-link">
|
||||||
<i class="fas fa-external-link-alt"></i>
|
<i class="fas fa-external-link-alt"></i>
|
||||||
Clique no título acima para abrir o PDF
|
Clique aqui para abrir o PDF
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -653,8 +665,53 @@
|
|||||||
|
|
||||||
// Generate QR Code on page load
|
// Generate QR Code on page load
|
||||||
generateQRCode();
|
generateQRCode();
|
||||||
|
|
||||||
|
// Auto-open link from hash
|
||||||
|
if (window.location.hash) {
|
||||||
|
const targetId = window.location.hash.substring(1);
|
||||||
|
const targetElement = document.getElementById(targetId);
|
||||||
|
if (targetElement) {
|
||||||
|
// Small delay to ensure everything is rendered
|
||||||
|
setTimeout(() => {
|
||||||
|
targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
|
||||||
|
// If it has a link-id, try to open the details
|
||||||
|
const linkId = targetElement.getAttribute('data-link-id');
|
||||||
|
const docId = targetElement.getAttribute('data-document-id');
|
||||||
|
|
||||||
|
if (linkId !== null) {
|
||||||
|
toggleLinkDetails(linkId);
|
||||||
|
} else if (docId !== null) {
|
||||||
|
toggleLinkDetails(docId);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function copyAnchorLink(id, btn) {
|
||||||
|
// Preserva a URL completa incluindo query strings (importante para o preview token)
|
||||||
|
// e apenas substitui/adiciona o hash
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.hash = id;
|
||||||
|
const fullUrl = url.toString();
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(fullUrl).then(() => {
|
||||||
|
const icon = btn.querySelector('i');
|
||||||
|
const originalClass = icon.className;
|
||||||
|
|
||||||
|
icon.className = 'fas fa-check text-success';
|
||||||
|
btn.classList.add('copied');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
icon.className = originalClass;
|
||||||
|
btn.classList.remove('copied');
|
||||||
|
}, 2000);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Erro ao copiar link:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// QR Code Functions
|
// QR Code Functions
|
||||||
let qrCodeGenerated = false;
|
let qrCodeGenerated = false;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user