feat: opacidade enquanto não selecionar o tipo.
This commit is contained in:
parent
8ab0b913e2
commit
70fbdaa3c2
@ -121,7 +121,7 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
|
|||||||
// ADICIONE ESTAS LINHAS:
|
// ADICIONE ESTAS LINHAS:
|
||||||
options.Events.OnRedirectToAuthorizationEndpoint = context =>
|
options.Events.OnRedirectToAuthorizationEndpoint = context =>
|
||||||
{
|
{
|
||||||
context.Response.Redirect(context.RedirectUri + "&prompt=select_account");
|
context.Response.Redirect(context.RedirectUri);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\images\" />
|
<Folder Include="wwwroot\images\" />
|
||||||
<Folder Include="wwwroot\css\" />
|
<Folder Include="wwwroot\css\" />
|
||||||
<Folder Include="wwwroot\js\" />
|
|
||||||
<Folder Include="Data\" />
|
<Folder Include="Data\" />
|
||||||
<Folder Include="Services\" />
|
<Folder Include="Services\" />
|
||||||
<Folder Include="Models\" />
|
<Folder Include="Models\" />
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
- 👑 **Sistema Premium**: Stripe integrado com recursos avançados
|
- 👑 **Sistema Premium**: Stripe integrado com recursos avançados
|
||||||
- 📱 **PWA Ready**: Funciona como aplicativo móvel
|
- 📱 **PWA Ready**: Funciona como aplicativo móvel
|
||||||
- 🎨 **UI Moderna**: Bootstrap 5 com design focado em velocidade
|
- 🎨 **UI Moderna**: Bootstrap 5 com design focado em velocidade
|
||||||
- 📊 **Analytics**: Google Analytics 4 integrado
|
|
||||||
- 🏗️ **Escalável**: MongoDB + Redis para alta performance
|
- 🏗️ **Escalável**: MongoDB + Redis para alta performance
|
||||||
|
|
||||||
## 🎯 Funcionalidades por Usuário
|
## 🎯 Funcionalidades por Usuário
|
||||||
@ -36,7 +35,6 @@
|
|||||||
- ✅ **Sem anúncios permanentemente**
|
- ✅ **Sem anúncios permanentemente**
|
||||||
- ✅ Geração prioritária (0.4s)
|
- ✅ Geração prioritária (0.4s)
|
||||||
- ✅ QR codes dinâmicos (editáveis)
|
- ✅ QR codes dinâmicos (editáveis)
|
||||||
- ✅ Analytics avançados
|
|
||||||
- ✅ Suporte prioritário
|
- ✅ Suporte prioritário
|
||||||
- ✅ API access
|
- ✅ API access
|
||||||
|
|
||||||
|
|||||||
2
Resources/SharedResource.Designer.cs
generated
2
Resources/SharedResource.Designer.cs
generated
@ -304,7 +304,7 @@ namespace QRRapidoApp.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Remove ads, access detailed analytics and much more for only $12.90/month or $129.00/year. Login and subscribe now!.
|
/// Looks up a localized string similar to Remove ads, access advanced customization and much more for only $12.90/month or $129.00/year. Login and subscribe now!.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LoginBenefits {
|
public static string LoginBenefits {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@ -250,7 +250,7 @@
|
|||||||
<value>Premium Offer!</value>
|
<value>Premium Offer!</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LoginBenefits" xml:space="preserve">
|
<data name="LoginBenefits" xml:space="preserve">
|
||||||
<value>Remove ads, access detailed analytics and much more for only $12.90/month or $129.00/year. Login and subscribe now!</value>
|
<value>Remove ads, access advanced customization and much more for only $12.90/month or $129.00/year. Login and subscribe now!</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Privacy" xml:space="preserve">
|
<data name="Privacy" xml:space="preserve">
|
||||||
<value>Privacy Policy</value>
|
<value>Privacy Policy</value>
|
||||||
|
|||||||
262
Views/Account/Profile.cshtml
Normal file
262
Views/Account/Profile.cshtml
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
@model QRRapidoApp.Models.User
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Perfil do Usuário";
|
||||||
|
var isPremium = ViewBag.IsPremium as bool? ?? false;
|
||||||
|
var monthlyQRCount = ViewBag.MonthlyQRCount as int? ?? 0;
|
||||||
|
var qrHistory = ViewBag.QRHistory as List<QRRapidoApp.Models.QRCodeHistory> ?? new List<QRRapidoApp.Models.QRCodeHistory>();
|
||||||
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8 mx-auto">
|
||||||
|
<!-- Header do Perfil -->
|
||||||
|
<div class="card mb-4 border-0 shadow-sm">
|
||||||
|
<div class="card-header bg-primary text-white d-flex align-items-center">
|
||||||
|
<i class="fas fa-user-circle fa-2x me-3"></i>
|
||||||
|
<div>
|
||||||
|
<h4 class="mb-0">@Model.Name</h4>
|
||||||
|
<small class="opacity-75">@Model.Email</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<!-- Status do Plano -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="fas fa-crown me-2 @(isPremium ? "text-warning" : "text-muted")"></i>
|
||||||
|
<strong>Status do Plano:</strong>
|
||||||
|
</div>
|
||||||
|
@if (isPremium)
|
||||||
|
{
|
||||||
|
<span class="badge bg-warning text-dark fs-6">
|
||||||
|
<i class="fas fa-star me-1"></i>Premium
|
||||||
|
</span>
|
||||||
|
@if (Model.PremiumExpiresAt.HasValue)
|
||||||
|
{
|
||||||
|
<p class="text-muted small mt-1 mb-0">
|
||||||
|
Expira em: @Model.PremiumExpiresAt.Value.ToString("dd/MM/yyyy")
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="badge bg-secondary fs-6">
|
||||||
|
<i class="fas fa-user me-1"></i>Gratuito
|
||||||
|
</span>
|
||||||
|
<p class="text-muted small mt-1 mb-0">
|
||||||
|
<a href="/Premium/Upgrade" class="text-decoration-none">
|
||||||
|
<i class="fas fa-arrow-up me-1"></i>Fazer upgrade
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Data de Cadastro -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="fas fa-calendar-alt me-2 text-info"></i>
|
||||||
|
<strong>Membro desde:</strong>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted mb-0">@Model.CreatedAt.ToString("dd/MM/yyyy")</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Provedor de Login -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="fab fa-@(Model.Provider.ToLower()) me-2 text-primary"></i>
|
||||||
|
<strong>Conectado via:</strong>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted mb-0">@Model.Provider</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Último Login -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="fas fa-sign-in-alt me-2 text-success"></i>
|
||||||
|
<strong>Último acesso:</strong>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted mb-0">@Model.LastLoginAt.ToString("dd/MM/yyyy HH:mm")</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Estatísticas de Uso -->
|
||||||
|
<div class="card mb-4 border-0 shadow-sm">
|
||||||
|
<div class="card-header bg-info text-white">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="fas fa-chart-bar me-2"></i>Estatísticas de Uso
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row text-center g-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-3 border rounded bg-light profile-stat">
|
||||||
|
<h3 class="text-primary mb-1">@Model.TotalQRGenerated</h3>
|
||||||
|
<small class="text-muted">QR Codes Criados</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-3 border rounded bg-light profile-stat">
|
||||||
|
<h3 class="text-success mb-1">@monthlyQRCount</h3>
|
||||||
|
<small class="text-muted">Este Mês</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-3 border rounded bg-light profile-stat">
|
||||||
|
<h3 class="text-info mb-1">@Model.DailyQRCount</h3>
|
||||||
|
<small class="text-muted">Hoje</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Histórico Recente -->
|
||||||
|
@if (qrHistory.Any())
|
||||||
|
{
|
||||||
|
<div class="card mb-4 border-0 shadow-sm">
|
||||||
|
<div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="fas fa-history me-2"></i>Histórico Recente
|
||||||
|
</h5>
|
||||||
|
<a href="/Account/History" class="btn btn-light btn-sm">
|
||||||
|
<i class="fas fa-list me-1"></i>Ver Todos
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
@foreach (var qr in qrHistory.Take(5))
|
||||||
|
{
|
||||||
|
<div class="list-group-item d-flex justify-content-between align-items-center px-0">
|
||||||
|
<div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<i class="fas fa-qrcode text-primary me-2"></i>
|
||||||
|
<div>
|
||||||
|
<h6 class="mb-1">@qr.Type.ToUpper()</h6>
|
||||||
|
<p class="mb-0 text-muted small">
|
||||||
|
@(qr.Content.Length > 50 ? qr.Content.Substring(0, 50) + "..." : qr.Content)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">@qr.CreatedAt.ToString("dd/MM HH:mm")</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Ações do Perfil -->
|
||||||
|
<div class="card border-0 shadow-sm">
|
||||||
|
<div class="card-header bg-dark text-white">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="fas fa-cogs me-2"></i>Ações
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
@if (!isPremium)
|
||||||
|
{
|
||||||
|
<div class="col-md-6">
|
||||||
|
<a href="/Premium/Upgrade" class="btn btn-warning w-100">
|
||||||
|
<i class="fas fa-crown me-2"></i>Upgrade para Premium
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<a href="/Account/History" class="btn btn-info w-100">
|
||||||
|
<i class="fas fa-history me-2"></i>Ver Histórico Completo
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<a href="/" class="btn btn-primary w-100">
|
||||||
|
<i class="fas fa-qrcode me-2"></i>Criar Novo QR Code
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<a href="/Account/Logout" class="btn btn-outline-danger w-100">
|
||||||
|
<i class="fas fa-sign-out-alt me-2"></i>Sair
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card {
|
||||||
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
font-size: 0.85em;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-light {
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
padding: 15px 0;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item:hover {
|
||||||
|
background-color: rgba(0,123,255,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stat {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-stat:hover {
|
||||||
|
background-color: #e3f2fd !important;
|
||||||
|
border-color: #2196f3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom: 2px solid rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-md-6 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body .row .col-md-4 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -105,7 +105,7 @@
|
|||||||
<span data-type-guide-text>@Localizer["TypeGuideText"]</span>
|
<span data-type-guide-text>@Localizer["TypeGuideText"]</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3 opacity-controlled disabled-state" id="quick-style-group">
|
||||||
<label class="form-label fw-semibold">
|
<label class="form-label fw-semibold">
|
||||||
<i class="fas fa-palette"></i> @Localizer["QuickStyle"]
|
<i class="fas fa-palette"></i> @Localizer["QuickStyle"]
|
||||||
</label>
|
</label>
|
||||||
@ -122,7 +122,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3" id="content-group">
|
<div class="mb-3 opacity-controlled disabled-state" id="content-group">
|
||||||
<label class="form-label fw-semibold">
|
<label class="form-label fw-semibold">
|
||||||
<i class="fas fa-edit"></i> @Localizer["Content"]
|
<i class="fas fa-edit"></i> @Localizer["Content"]
|
||||||
</label>
|
</label>
|
||||||
@ -138,7 +138,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dynamic QR Section (Premium) -->
|
<!-- Dynamic QR Section (Premium) -->
|
||||||
<div id="dynamic-qr-section" style="display: none;">
|
<div id="dynamic-qr-section" style="display: none;" class="opacity-controlled disabled-state">
|
||||||
<div class="premium-feature-box">
|
<div class="premium-feature-box">
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
@ -146,30 +146,30 @@
|
|||||||
<i class="fas fa-chart-line text-warning"></i> QR Dinâmico - Premium
|
<i class="fas fa-chart-line text-warning"></i> QR Dinâmico - Premium
|
||||||
</h6>
|
</h6>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
Analytics em tempo real: cliques, localização, dispositivos, etc.
|
QR Code com seu logotipo!
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
@if (ViewBag.IsPremium == true)
|
@if (ViewBag.IsPremium == true)
|
||||||
{
|
{
|
||||||
<input class="form-check-input" type="checkbox" id="qr-dynamic-toggle">
|
<input class="form-check-input" type="checkbox" id="qr-dynamic-toggle" style="display: none;">
|
||||||
<label class="form-check-label" for="qr-dynamic-toggle">
|
<label class="form-check-label" for="qr-dynamic-toggle">
|
||||||
Ativar Analytics
|
Adicione o logotivo na Personalização avançada
|
||||||
</label>
|
</label>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="premium-upgrade-prompt">
|
<div class="premium-upgrade-prompt">
|
||||||
<input class="form-check-input" type="checkbox" disabled>
|
<input class="form-check-input" type="checkbox" disabled style="display: none;">
|
||||||
<label class="form-check-label text-muted">
|
<label class="form-check-label" for="qr-dynamic-toggle">
|
||||||
Ativar Analytics
|
Gerar QR Code com logotipo? Assine o plano premium!
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
<small>
|
<small>
|
||||||
<a href="/Pagamento/SelecaoPlano" class="text-warning">
|
<a href="/Pagamento/SelecaoPlano" class="text-warning">
|
||||||
Upgrade Premium
|
Upgrade Premium
|
||||||
</a> para analytics
|
</a> QR Code com logotipo
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- URL Preview -->
|
<!-- URL Preview -->
|
||||||
<div id="url-preview" class="mt-3" style="display: none;">
|
<div id="url-preview" class="mt-3 opacity-controlled disabled-state" style="display: none;">
|
||||||
<h6><i class="fas fa-link"></i> Preview</h6>
|
<h6><i class="fas fa-link"></i> Preview</h6>
|
||||||
<div id="url-preview-content" class="bg-light p-3 rounded">
|
<div id="url-preview-content" class="bg-light p-3 rounded">
|
||||||
<strong>URL Final:</strong> <span id="final-url-display"></span><br>
|
<strong>URL Final:</strong> <span id="final-url-display"></span><br>
|
||||||
@ -188,7 +188,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VCard Interface (dynamic) -->
|
<!-- VCard Interface (dynamic) -->
|
||||||
<div id="vcard-interface" class="mb-3" style="display: none;">
|
<div id="vcard-interface" class="mb-3 opacity-controlled disabled-state" style="display: none;">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<i class="fas fa-address-card"></i>
|
<i class="fas fa-address-card"></i>
|
||||||
<strong>Cartão de Visita Digital</strong> - Este QR Code criará um cartão de visita digital.
|
<strong>Cartão de Visita Digital</strong> - Este QR Code criará um cartão de visita digital.
|
||||||
@ -330,7 +330,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- WiFi Interface (dynamic) -->
|
<!-- WiFi Interface (dynamic) -->
|
||||||
<div id="wifi-interface" class="mb-3" style="display: none;">
|
<div id="wifi-interface" class="mb-3 opacity-controlled disabled-state" style="display: none;">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<i class="fas fa-wifi"></i>
|
<i class="fas fa-wifi"></i>
|
||||||
<strong>@Localizer["WiFiQRTitle"]</strong> - @Localizer["WiFiQRDescription"]
|
<strong>@Localizer["WiFiQRTitle"]</strong> - @Localizer["WiFiQRDescription"]
|
||||||
@ -469,7 +469,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Email Interface (dynamic) -->
|
<!-- Email Interface (dynamic) -->
|
||||||
<div id="email-interface" class="mb-3" style="display: none;">
|
<div id="email-interface" class="mb-3 opacity-controlled disabled-state" style="display: none;">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<strong>QR Code Email:</strong> Permite enviar email automático com destinatário, assunto e mensagem pré-definidos.
|
<strong>QR Code Email:</strong> Permite enviar email automático com destinatário, assunto e mensagem pré-definidos.
|
||||||
Compatível com Android, iOS e dispositivos modernos.
|
Compatível com Android, iOS e dispositivos modernos.
|
||||||
@ -500,7 +500,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Advanced customization (collapsible) -->
|
<!-- Advanced customization (collapsible) -->
|
||||||
<div class="accordion mb-3" id="customization-accordion">
|
<div class="accordion mb-3 opacity-controlled disabled-state" id="customization-accordion">
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h2 class="accordion-header">
|
<h2 class="accordion-header">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#customization-panel">
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#customization-panel">
|
||||||
@ -702,7 +702,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-grid">
|
<div class="d-grid opacity-controlled disabled-state" id="button-gerar-div">
|
||||||
<button type="submit" class="btn btn-primary btn-lg" id="generate-btn">
|
<button type="submit" class="btn btn-primary btn-lg" id="generate-btn">
|
||||||
<i class="fas fa-bolt"></i> @Localizer["GenerateQRCodeQuickly"]
|
<i class="fas fa-bolt"></i> @Localizer["GenerateQRCodeQuickly"]
|
||||||
<div class="spinner-border spinner-border-sm ms-2 d-none" role="status">
|
<div class="spinner-border spinner-border-sm ms-2 d-none" role="status">
|
||||||
@ -961,6 +961,9 @@
|
|||||||
<!-- Ad Space Footer (conditional) -->
|
<!-- Ad Space Footer (conditional) -->
|
||||||
@await Html.PartialAsync("_AdSpace", new { position = "footer" })
|
@await Html.PartialAsync("_AdSpace", new { position = "footer" })
|
||||||
|
|
||||||
|
|
||||||
|
<script src="~/js/simple-opcacity.js"></script>
|
||||||
|
|
||||||
<!-- Script para controles de logo aprimorados -->
|
<!-- Script para controles de logo aprimorados -->
|
||||||
<script>
|
<script>
|
||||||
// JavaScript para controles de logo aprimorados
|
// JavaScript para controles de logo aprimorados
|
||||||
@ -973,8 +976,23 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const logoPreviewImage = document.getElementById('logo-preview-image');
|
const logoPreviewImage = document.getElementById('logo-preview-image');
|
||||||
const previewSizeText = document.getElementById('preview-size-text');
|
const previewSizeText = document.getElementById('preview-size-text');
|
||||||
const previewColorizeText = document.getElementById('preview-colorize-text');
|
const previewColorizeText = document.getElementById('preview-colorize-text');
|
||||||
|
|
||||||
// Controle do slider de tamanho
|
new SimpleOpacityController('#qr-type', '#quick-style-group');
|
||||||
|
new SimpleOpacityController('#qr-type', '#content-group');
|
||||||
|
new SimpleOpacityController('#qr-type', '#dynamic-qr-section');
|
||||||
|
new SimpleOpacityController('#qr-type', '#url-preview');
|
||||||
|
new SimpleOpacityController('#qr-type', '#vcard-interface');
|
||||||
|
new SimpleOpacityController('#qr-type', '#wifi-interface');
|
||||||
|
new SimpleOpacityController('#qr-type', '#sms-interface');
|
||||||
|
new SimpleOpacityController('#qr-type', '#email-interface');
|
||||||
|
new SimpleOpacityController('#qr-type', '#customization-accordion');
|
||||||
|
new SimpleOpacityController('#qr-type', '#button-gerar-div');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Controle do slider de tamanho
|
||||||
logoSizeSlider?.addEventListener('input', function() {
|
logoSizeSlider?.addEventListener('input', function() {
|
||||||
const size = this.value;
|
const size = this.value;
|
||||||
logoSizeDisplay.textContent = size + '%';
|
logoSizeDisplay.textContent = size + '%';
|
||||||
|
|||||||
@ -302,7 +302,7 @@
|
|||||||
<script src="~/js/qr-speed-generator.js" asp-append-version="true"></script>
|
<script src="~/js/qr-speed-generator.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/language-switcher.js" asp-append-version="true"></script>
|
<script src="~/js/language-switcher.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/theme-toggle.js" asp-append-version="true"></script>
|
<script src="~/js/theme-toggle.js" asp-append-version="true"></script>
|
||||||
|
|
||||||
<!-- Fallback inline script for debug -->
|
<!-- Fallback inline script for debug -->
|
||||||
<script>
|
<script>
|
||||||
// Fallback inline para garantir funcionamento
|
// Fallback inline para garantir funcionamento
|
||||||
@ -333,6 +333,7 @@
|
|||||||
} else {
|
} else {
|
||||||
console.error('❌ Botão não encontrado pelo script inline!');
|
console.error('❌ Botão não encontrado pelo script inline!');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
},
|
},
|
||||||
"Authentication": {
|
"Authentication": {
|
||||||
"Google": {
|
"Google": {
|
||||||
"ClientId": "your-google-client-id",
|
"ClientId": "1080447252222-dqjsu999tvrpb69oj5iapckdh9g8rvha.apps.googleusercontent.com",
|
||||||
"ClientSecret": "your-google-client-secret"
|
"ClientSecret": "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"
|
||||||
},
|
},
|
||||||
"Microsoft": {
|
"Microsoft": {
|
||||||
"ClientId": "9bec3835-acdb-4c5a-8668-6b90955c6ad2",
|
"ClientId": "9bec3835-acdb-4c5a-8668-6b90955c6ad2",
|
||||||
|
|||||||
@ -284,3 +284,15 @@ body {
|
|||||||
.text-success {
|
.text-success {
|
||||||
color: #28a745 !important;
|
color: #28a745 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CLASSE PARA CONTROLAR OPACIDADE */
|
||||||
|
.opacity-controlled {
|
||||||
|
transition: opacity 0.3s ease-in-out;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ESTADO OPACO (quando nada selecionado) */
|
||||||
|
.opacity-controlled.disabled-state {
|
||||||
|
opacity: 0.2 !important; /* Bem opaco */
|
||||||
|
pointer-events: none; /* Desabilita interação */
|
||||||
|
}
|
||||||
|
|||||||
@ -108,8 +108,13 @@ class QRRapidoGenerator {
|
|||||||
// Content validation
|
// Content validation
|
||||||
const qrContent = document.getElementById('qr-content');
|
const qrContent = document.getElementById('qr-content');
|
||||||
if (qrContent) {
|
if (qrContent) {
|
||||||
|
let timer;
|
||||||
qrContent.addEventListener('input', (e) => {
|
qrContent.addEventListener('input', (e) => {
|
||||||
this.handleContentChange(e.target.value);
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
this.handleContentChange(e.target.value);
|
||||||
|
this.updateGenerateButton();
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
wwwroot/js/simple-opcacity.js
Normal file
64
wwwroot/js/simple-opcacity.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
class SimpleOpacityController {
|
||||||
|
constructor(controlSelector, targetSelector) {
|
||||||
|
this.controlSelector = controlSelector;
|
||||||
|
this.targetSelector = targetSelector;
|
||||||
|
this.disabledClass = 'disabled-state';
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const controls = document.querySelectorAll(this.controlSelector);
|
||||||
|
const targets = document.querySelectorAll(this.targetSelector);
|
||||||
|
|
||||||
|
// Listener para detectar mudanças
|
||||||
|
controls.forEach(control => {
|
||||||
|
control.addEventListener('change', () => {
|
||||||
|
this.updateOpacity();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Estado inicial
|
||||||
|
this.updateOpacity();
|
||||||
|
|
||||||
|
console.log('✅ Sistema simples de opacidade inicializado');
|
||||||
|
console.log('Controlando:', controls.length, 'controles e', targets.length, 'alvos');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOpacity() {
|
||||||
|
const hasSelection = this.hasSelection();
|
||||||
|
const targets = document.querySelectorAll(this.targetSelector);
|
||||||
|
|
||||||
|
targets.forEach(target => {
|
||||||
|
if (hasSelection) {
|
||||||
|
// TEM seleção = div normal
|
||||||
|
target.classList.remove(this.disabledClass);
|
||||||
|
console.log('🟢 Div ativada - seleção detectada');
|
||||||
|
} else {
|
||||||
|
// NÃO tem seleção = div opaca
|
||||||
|
target.classList.add(this.disabledClass);
|
||||||
|
console.log('🔴 Div desativada - nenhuma seleção');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSelection() {
|
||||||
|
// Para SELECT: verificar se valor não está vazio
|
||||||
|
const selects = document.querySelectorAll(this.controlSelector + '[type=""], ' + this.controlSelector + ':not([type])');
|
||||||
|
for (let select of selects) {
|
||||||
|
if (select.value && select.value.trim() !== '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Para RADIO BUTTONS: verificar se algum está selecionado E não é vazio
|
||||||
|
const radios = document.querySelectorAll(this.controlSelector + '[type="radio"]');
|
||||||
|
for (let radio of radios) {
|
||||||
|
if (radio.checked && radio.value && radio.value.trim() !== '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user