From a8faf0ef2f47b3f1fd35fb1d9ff69ef4e3c65f4e Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Tue, 29 Jul 2025 22:42:39 -0300 Subject: [PATCH] feat: tema claro ou escuro --- Controllers/AccountController.cs | 4 +- Middleware/LanguageRedirectionMiddleware.cs | 4 +- Program.cs | 38 +- Resources/SharedResource.en.resx | 472 ++++++++++++ Resources/SharedResource.es.resx | 424 +++++++++++ Resources/SharedResource.pt-BR.resx | 424 +++++++++++ Services/AdDisplayService.cs | 5 - Views/Account/History.cshtml | 22 +- Views/Account/Login.cshtml | 28 +- Views/Home/Index.cshtml | 106 +-- Views/Pagamento/Cancelar.cshtml | 7 +- Views/Pagamento/SelecaoPlano.cshtml | 47 +- Views/Pagamento/Sucesso.cshtml | 7 +- Views/Premium/Upgrade.cshtml | 89 ++- Views/Shared/_AdSpace.cshtml | 16 +- Views/Shared/_Layout.cshtml | 122 ++-- wwwroot/css/qrrapido-theme.css | 749 ++++++++++++++++++-- wwwroot/js/theme-toggle.js | 96 +++ 18 files changed, 2410 insertions(+), 250 deletions(-) create mode 100644 wwwroot/js/theme-toggle.js diff --git a/Controllers/AccountController.cs b/Controllers/AccountController.cs index d988058..51c032c 100644 --- a/Controllers/AccountController.cs +++ b/Controllers/AccountController.cs @@ -117,8 +117,8 @@ namespace QRRapidoApp.Controllers await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); - var returnUrl = result.Properties?.Items["returnUrl"] ?? "/"; - return Redirect(returnUrl); + var returnUrl = result.Properties?.Items != null && result.Properties.Items.ContainsKey("returnUrl") ? result.Properties?.Items["returnUrl"] : "/"; + return RedirectToAction("Index", "Home"); } catch (Exception ex) { diff --git a/Middleware/LanguageRedirectionMiddleware.cs b/Middleware/LanguageRedirectionMiddleware.cs index 733fc2a..5172bcc 100644 --- a/Middleware/LanguageRedirectionMiddleware.cs +++ b/Middleware/LanguageRedirectionMiddleware.cs @@ -65,7 +65,9 @@ namespace QRRapidoApp.Middleware var specialRoutes = new[] { "api/", "health", "_framework/", "lib/", "css/", "js/", "images/", - "favicon.ico", "robots.txt", "sitemap.xml" + "favicon.ico", "robots.txt", "sitemap.xml", + "signin-microsoft", "signin-google", "signout-callback-oidc", + "Account/ExternalLoginCallback", "Account/Logout" }; return specialRoutes.Any(route => path.StartsWith(route, StringComparison.OrdinalIgnoreCase)); diff --git a/Program.cs b/Program.cs index 85eeb44..65c9839 100644 --- a/Program.cs +++ b/Program.cs @@ -113,15 +113,37 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc options.ExpireTimeSpan = TimeSpan.FromDays(30); options.SlidingExpiration = true; }) - .AddGoogle(GoogleDefaults.AuthenticationScheme, options => + .AddGoogle(options => { options.ClientId = builder.Configuration["Authentication:Google:ClientId"]; options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; - }) - .AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options => + + // ADICIONE ESTAS LINHAS: + options.Events.OnRedirectToAuthorizationEndpoint = context => + { + context.Response.Redirect(context.RedirectUri + "&prompt=select_account"); + return Task.CompletedTask; + }; + + // OU use este método alternativo: + options.Scope.Add("email"); + options.Scope.Add("profile"); + options.SaveTokens = true; + }).AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options => { options.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"]; options.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"]; + + // ADICIONE ESTAS LINHAS: + options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; + options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; + + // Força sempre mostrar a tela de seleção de conta + options.Events.OnRedirectToAuthorizationEndpoint = context => + { + context.Response.Redirect(context.RedirectUri + "&prompt=select_account"); + return Task.CompletedTask; + }; }); // Stripe Configuration @@ -231,6 +253,16 @@ app.UseMiddleware(); // Health check endpoint app.MapHealthChecks("/health"); +//app.MapControllerRoute( +// name: "auth", +// pattern: "signin-{provider}", +// defaults: new { controller = "Account", action = "ExternalLoginCallback" }); + +//app.MapControllerRoute( +// name: "account", +// pattern: "Account/{action}", +// defaults: new { controller = "Account" }); + // Language routes (must be first) app.MapControllerRoute( name: "localized", diff --git a/Resources/SharedResource.en.resx b/Resources/SharedResource.en.resx index c8e1a4c..c2717a9 100644 --- a/Resources/SharedResource.en.resx +++ b/Resources/SharedResource.en.resx @@ -220,4 +220,476 @@ QR Code saved to history! + + Create QR Code Quickly + + + Premium User Active + + + No Ads • History • Unlimited QR + + + Unlimited today + + + QR codes remaining + + + QR Code Type + + + Select type + + + URL/Link + + + Simple Text + + + Business Card + + + Dynamic QR (Premium) + + + Enter your QR code content here... + + + Content hints + + + Classic + + + Modern + + + Colorful + + + + Accelerate your productivity with the world's fastest QR generator + + + 3x faster than the competition + + + Current Status + + + You have + + + days remaining without ads. + + + Upgrade now and have premium access forever! + + + days remaining + + + The most popular plan + + + per month + + + Unlimited QR codes + + + Ultra-fast generation (0.4s) + + + No ads forever + + + Dynamic QR codes + + + Real-time analytics + + + Priority support + + + Developer API + + + Upgrade Now + + + Secure payment via Stripe + + + Cancel anytime + + + Plan Comparison + + + Feature + + + QR codes per day + + + Unlimited + + + Generation speed + + + Ads + + + No ads + + + Detailed analytics + + + Speed Demonstration + + + Competitors + + + Average time + + + 11x faster! + + + Frequently Asked Questions + + + Can I cancel anytime? + + + Yes! You can cancel your subscription at any time. There are no cancellation fees and you'll maintain premium access until the end of the already paid period. + + + What are dynamic QR codes? + + + Dynamic QR codes allow you to change the QR content after it has been created, without needing to generate a new code. Perfect for marketing campaigns and business use. + + + How does priority support work? + + + Premium users receive responses within 2 business hours via email, direct chat access and specialized technical support. + + + Payment processing error: + + + Payment processing error. Please try again. + + + + Advertisement + + + ✨ Premium User - No ads! + + + Upgrade to Premium and remove ads! + + + Premium: No ads + History + Unlimited QR + + + + Login with your account and get: + + + 30 days without ads + + + 50 QR codes/day + + + QR code history + + + Login with Google + + + Login with Microsoft + + + Special Offer! + + + By logging in, you automatically get + + + and can generate up to + + + for free. + + + We don't register you without your permission. + + + Privacy Policy + + + + Payment successful! + + + Back to Home + + + Payment canceled. + + + View Plans + + + Unlock the Full Power of QRRapido + + + Unlimited access, no ads and exclusive features for maximum productivity. + + + Monthly Plan + + + Ideal to start exploring premium features. + + + Subscribe Now + + + Annual Plan + + + Recommended + + + /year + + + Save $ + + + Best value for frequent users. + + + Subscribe to Annual Plan + + + All plans include: + + + Redirecting... + + + An error occurred while initializing payment. Please try again. + + + + Your generated QR codes are saved here for future download + + + Generate New QR Code + + + Type: + + + Created on: + + + Showing the 50 most recent QR codes. Older ones are automatically removed. + + + No QR Code found + + + When you generate QR codes while logged in, they will appear here for future download. + + + Generate First QR Code + + + Error regenerating QR Code. Please try again. + + + + Small (200px) + + + Medium (300px) + + + Large (500px) + + + XL (800px) + + + Minimal + + + Large + + + Logo/Icon + + + PNG, JPG up to 2MB + + + Border Style + + + Square + + + Rounded + + + Circular + + + Leaf + + + Generate QR Code Quickly + + + Generating... + + + Availability + + + QRs generated today + + + Your QR code will appear here in seconds + + + Ultra-fast generation guaranteed + + + Download SVG (Vector) + + + Share QR Code + + + Share (System) + + + to save to history + + + Priority generation (0.4s) + + + Accelerate for $19.90/month + + + Tips for Faster QR + + + Short URLs generate faster + + + Less text = higher speed + + + Solid colors optimize the process + + + Smaller sizes accelerate download + + + Why is QR Rapido faster? + + + Comparison with other popular generators + + + Optimized for speed + + + Competitor A + + + Traditional generator + + + Competitor B + + + Heavy interface + + + Competitor C + + + Many ads + + + + average + + + Generate QR Code + + + Profile + + + History + + + Premium Active + + + Logout + + + Login = 30 days without ads! + + + The fastest QR generator on the web + + + Average of + + + 1.2 seconds + + + per QR code • Free • No registration required + + + The fastest QR code generator on the web. Free, secure and reliable. + + + Useful Links + + + Terms of Use + + + Support + + + Help + + + All rights reserved. + \ No newline at end of file diff --git a/Resources/SharedResource.es.resx b/Resources/SharedResource.es.resx index 982471b..ad3082c 100644 --- a/Resources/SharedResource.es.resx +++ b/Resources/SharedResource.es.resx @@ -268,4 +268,428 @@ Colorido + + + Acelera tu productividad con el generador de QR más rápido del mundo + + + 3x más rápido que la competencia + + + Estado Actual + + + Tienes + + + días restantes sin anuncios. + + + ¡Actualiza ahora y ten acceso premium para siempre! + + + días restantes + + + El plan más popular + + + por mes + + + Códigos QR ilimitados + + + Generación ultra-rápida (0.4s) + + + Sin anuncios para siempre + + + Códigos QR dinámicos + + + Analítica en tiempo real + + + Soporte prioritario + + + API para desarrolladores + + + Actualizar Ahora + + + Pago seguro via Stripe + + + Cancela cuando quieras + + + Comparación de Planes + + + Función + + + Códigos QR por día + + + Ilimitado + + + Velocidad de generación + + + Anuncios + + + Sin anuncios + + + Analítica detallada + + + Demostración de Velocidad + + + Competidores + + + Tiempo promedio + + + ¡11x más rápido! + + + Preguntas Frecuentes + + + ¿Puedo cancelar en cualquier momento? + + + ¡Sí! Puedes cancelar tu suscripción en cualquier momento. No hay tarifas de cancelación y mantendrás el acceso premium hasta el final del período ya pagado. + + + ¿Qué son los códigos QR dinámicos? + + + Los códigos QR dinámicos te permiten cambiar el contenido del QR después de que haya sido creado, sin necesidad de generar un nuevo código. Perfecto para campañas de marketing y uso empresarial. + + + ¿Cómo funciona el soporte prioritario? + + + Los usuarios premium reciben respuesta en hasta 2 horas hábiles por email, acceso al chat directo y soporte técnico especializado. + + + Error al procesar el pago: + + + Error al procesar el pago. Inténtalo de nuevo. + + + + Publicidad + + + ✨ Usuario Premium - ¡Sin anuncios! + + + ¡Actualiza a Premium y elimina los anuncios! + + + Premium: Sin anuncios + Historial + QR ilimitados + + + + Inicia sesión con tu cuenta y obtén: + + + 30 días sin anuncios + + + 50 códigos QR/día + + + Historial de códigos QR + + + Iniciar con Google + + + Iniciar con Microsoft + + + ¡Oferta Especial! + + + Al iniciar sesión, obtienes automáticamente + + + y puedes generar hasta + + + gratuitamente. + + + No te registramos sin tu permiso. + + + Política de Privacidad + + + + ¡Pago exitoso! + + + Volver al Inicio + + + Pago cancelado. + + + Ver Planes + + + Desbloquea el Poder Total de QRRápido + + + Acceso sin límites, sin anuncios y con recursos exclusivos para máxima productividad. + + + Plan Mensual + + + Ideal para comenzar a explorar las funciones premium. + + + Suscribirse Ahora + + + Plan Anual + + + Recomendado + + + /año + + + Ahorra $ + + + La mejor relación calidad-precio para usuarios frecuentes. + + + Suscribirse al Plan Anual + + + Todos los planes incluyen: + + + Redirigiendo... + + + Ocurrió un error al iniciar el pago. Inténtalo de nuevo. + + + + Tus códigos QR generados se guardan aquí para descarga futura + + + Generar Nuevo Código QR + + + Tipo: + + + Creado el: + + + Mostrando los 50 códigos QR más recientes. Los más antiguos se eliminan automáticamente. + + + Ningún Código QR encontrado + + + Cuando generes códigos QR estando conectado, aparecerán aquí para descarga futura. + + + Generar Primer Código QR + + + Error al regenerar el Código QR. Inténtalo de nuevo. + + + + Pequeño (200px) + + + Mediano (300px) + + + Grande (500px) + + + XL (800px) + + + Mínimo + + + Grande + + + Logo/Icono + + + PNG, JPG hasta 2MB + + + Estilo de Bordes + + + Cuadrado + + + Redondeado + + + Circular + + + Hoja + + + Generar Código QR Rápidamente + + + Generando... + + + Disponibilidad + + + QRs generados hoy + + + Tu código QR aparecerá aquí en segundos + + + Generación ultra-rápida garantizada + + + Descargar SVG (Vectorial) + + + Compartir Código QR + + + Compartir (Sistema) + + + para guardar en el historial + + + Generación prioritaria (0.4s) + + + Acelerar por $19.90/mes + + + Consejos para QR Más Rápidos + + + URLs cortas se generan más rápido + + + Menos texto = mayor velocidad + + + Colores sólidos optimizan el proceso + + + Tamaños menores aceleran la descarga + + + ¿Por qué QR Rapido es más rápido? + + + Comparación con otros generadores populares + + + Optimizado para velocidad + + + Competidor A + + + Generador tradicional + + + Competidor B + + + Interfaz pesada + + + Competidor C + + + Muchos anuncios + + + + promedio + + + Generar Código QR + + + Perfil + + + Historial + + + Premium Activo + + + Salir + + + ¡Iniciar sesión = 30 días sin anuncios! + + + El generador de QR más rápido de la web + + + Promedio de + + + 1.2 segundos + + + por código QR • Gratis • Sin registro obligatorio + + + El generador de códigos QR más rápido de la web. Gratis, seguro y confiable. + + + Enlaces Útiles + + + Términos de Uso + + + Soporte + + + Ayuda + + + Todos los derechos reservados. + \ No newline at end of file diff --git a/Resources/SharedResource.pt-BR.resx b/Resources/SharedResource.pt-BR.resx index 564aac3..de19161 100644 --- a/Resources/SharedResource.pt-BR.resx +++ b/Resources/SharedResource.pt-BR.resx @@ -268,4 +268,428 @@ Colorido + + + Acelere sua produtividade com o gerador de QR mais rápido do mundo + + + 3x mais rápido que a concorrência + + + Status Atual + + + Você tem + + + dias restantes sem anúncios. + + + Upgrade agora e tenha acesso premium para sempre! + + + dias restantes + + + O plano mais popular + + + por mês + + + QR codes ilimitados + + + Geração ultra-rápida (0.4s) + + + Sem anúncios para sempre + + + QR codes dinâmicos + + + Analytics em tempo real + + + Suporte prioritário + + + API para desenvolvedores + + + Fazer Upgrade Agora + + + Pagamento seguro via Stripe + + + Cancele quando quiser + + + Comparação de Planos + + + Recurso + + + QR codes por dia + + + Ilimitado + + + Velocidade de geração + + + Anúncios + + + Sem anúncios + + + Analytics detalhados + + + Demonstração de Velocidade + + + Concorrentes + + + Tempo médio + + + 11x mais rápido! + + + Perguntas Frequentes + + + Posso cancelar a qualquer momento? + + + Sim! Você pode cancelar sua assinatura a qualquer momento. Não há taxas de cancelamento e você manterá o acesso premium até o final do período já pago. + + + O que são QR codes dinâmicos? + + + QR codes dinâmicos permitem que você altere o conteúdo do QR após ele ter sido criado, sem precisar gerar um novo código. Perfeito para campanhas de marketing e uso empresarial. + + + Como funciona o suporte prioritário? + + + Usuários premium recebem resposta em até 2 horas úteis por email, acesso ao chat direto e suporte técnico especializado. + + + Erro ao processar pagamento: + + + Erro ao processar pagamento. Tente novamente. + + + + Publicidade + + + ✨ Usuário Premium - Sem anúncios! + + + Faça upgrade para Premium e remova os anúncios! + + + Premium: Sem anúncios + Histórico + QR ilimitados + + + + Entre com sua conta e ganhe: + + + 30 dias sem anúncios + + + 50 QR codes/dia + + + Histórico de QR codes + + + Entrar com Google + + + Entrar com Microsoft + + + Oferta Especial! + + + Ao fazer login, você ganha automaticamente + + + e pode gerar até + + + gratuitamente. + + + Não cadastramos você sem sua permissão. + + + Política de Privacidade + + + + Pagamento bem-sucedido! + + + Voltar ao Início + + + Pagamento cancelado. + + + Ver Planos + + + Desbloqueie o Poder Total do QRRápido + + + Acesso sem limites, sem anúncios e com recursos exclusivos para máxima produtividade. + + + Plano Mensal + + + Ideal para começar a explorar os recursos premium. + + + Assinar Agora + + + Plano Anual + + + Recomendado + + + /ano + + + Economize R$ + + + O melhor custo-benefício para usuários frequentes. + + + Assinar Plano Anual + + + Todos os planos incluem: + + + Redirecionando... + + + Ocorreu um erro ao iniciar o pagamento. Tente novamente. + + + + Seus QR codes gerados ficam salvos aqui para download futuro + + + Gerar Novo QRCode + + + Tipo: + + + Criado em: + + + Mostrando os 50 QR codes mais recentes. Os mais antigos são removidos automaticamente. + + + Nenhum QR Code encontrado + + + Quando você gerar QR codes estando logado, eles aparecerão aqui para download futuro. + + + Gerar Primeiro QRCode + + + Erro ao regenerar QR Code. Tente novamente. + + + + Pequeno (200px) + + + Médio (300px) + + + Grande (500px) + + + XL (800px) + + + Mínima + + + Grande + + + Logo/Ícone + + + PNG, JPG até 2MB + + + Estilo das Bordas + + + Quadrado + + + Arredondado + + + Circular + + + Folha + + + Gerar QR Code Rapidamente + + + Gerando... + + + Disponibilidade + + + QRs gerados hoje + + + Seu QR code aparecerá aqui em segundos + + + Geração ultra-rápida garantida + + + Download SVG (Vetorial) + + + Compartilhar QR Code + + + Compartilhar (Sistema) + + + para salvar no histórico + + + Geração prioritária (0.4s) + + + Acelerar por R$ 19,90/mês + + + Dicas para QR Mais Rápidos + + + URLs curtas geram mais rápido + + + Menos texto = maior velocidade + + + Cores sólidas otimizam o processo + + + Tamanhos menores aceleram o download + + + Por que QR Rapido é mais rápido? + + + Comparação com outros geradores populares + + + Otimizado para velocidade + + + Concorrente A + + + Gerador tradicional + + + Concorrente B + + + Interface pesada + + + Concorrente C + + + Muitos anúncios + + + + médio + + + Gerar QRCode + + + Perfil + + + Histórico + + + Premium Ativo + + + Sair + + + Login = 30 dias sem anúncios! + + + O gerador de QR mais rápido da web + + + Média de + + + 1.2 segundos + + + por QR code • Grátis • Sem cadastro obrigatório + + + O gerador de QR codes mais rápido da web. Grátis, seguro e confiável. + + + Links Úteis + + + Termos de Uso + + + Suporte + + + Ajuda + + + Todos os direitos reservados. + \ No newline at end of file diff --git a/Services/AdDisplayService.cs b/Services/AdDisplayService.cs index 556844a..e629a7c 100644 --- a/Services/AdDisplayService.cs +++ b/Services/AdDisplayService.cs @@ -23,14 +23,12 @@ namespace QRRapidoApp.Services { try { - // Usuários não logados: sempre mostrar anúncios if (string.IsNullOrEmpty(userId)) return true; var user = await _userService.GetUserAsync(userId); if (user == null) return true; - // APENAS Premium users não veem anúncios return !(user.IsPremium && user.PremiumExpiresAt > DateTime.UtcNow); } catch (Exception ex) @@ -40,9 +38,6 @@ namespace QRRapidoApp.Services } } - // MÉTODO REMOVIDO: GetAdFreeTimeRemaining - não é mais necessário - // MÉTODO REMOVIDO: GetActiveAdFreeSessionAsync - não é mais necessário - public async Task HasValidPremiumSubscription(string userId) { try diff --git a/Views/Account/History.cshtml b/Views/Account/History.cshtml index 163eee7..4e51618 100644 --- a/Views/Account/History.cshtml +++ b/Views/Account/History.cshtml @@ -13,12 +13,12 @@
-

Histórico de QR Codes

-

Seus QR codes gerados ficam salvos aqui para download futuro

+

@Localizer["QRCodeHistory"]

+

@Localizer["QRCodesSavedHere"]

@@ -39,12 +39,12 @@
- Tipo: + @Localizer["Type"] @qr.Type
- Conteúdo: + @Localizer["Content"]

@if (qr.Content.Length > 50) { @@ -58,7 +58,7 @@

- Criado em: + @Localizer["CreatedOn"]
@qr.CreatedAt.ToString("dd/MM/yyyy HH:mm")
@@ -98,7 +98,7 @@ {
- Mostrando os 50 QR codes mais recentes. Os mais antigos são removidos automaticamente. + @Localizer["ShowingRecent50QRCodes"]
} } @@ -106,12 +106,12 @@ {
-

Nenhum QR Code encontrado

+

@Localizer["NoQRCodeFound"]

- Quando você gerar QR codes estando logado, eles aparecerão aqui para download futuro. + @Localizer["QRCodesWillAppearHere"]

- Gerar Primeiro QRCode + @Localizer["GenerateFirstQRCode"]
} @@ -143,7 +143,7 @@ function regenerateQR(qrId) { }) .catch(error => { console.error('Error regenerating QR:', error); - alert('Erro ao regenerar QR Code. Tente novamente.'); + alert('@Localizer["ErrorRegeneratingQR"]'); }); } diff --git a/Views/Account/Login.cshtml b/Views/Account/Login.cshtml index fba190f..62f4cc9 100644 --- a/Views/Account/Login.cshtml +++ b/Views/Account/Login.cshtml @@ -1,3 +1,5 @@ +@using Microsoft.Extensions.Localization +@inject IStringLocalizer Localizer @{ ViewData["Title"] = "Login"; var returnUrl = ViewBag.ReturnUrl ?? "/"; @@ -10,26 +12,26 @@

- Entrar + @Localizer["Login"]

-

Entre com sua conta e ganhe:

+

@Localizer["LoginAndGet"]

- 30 dias sem anúncios + @Localizer["ThirtyDaysNoAds"]
- 50 QR codes/dia + @Localizer["FiftyQRCodesPerDay"]
- Histórico de QR codes + @Localizer["QRCodeHistory"]
@@ -37,11 +39,11 @@ @@ -49,18 +51,18 @@
- Oferta Especial! + @Localizer["SpecialOfferLogin"]

- Ao fazer login, você ganha automaticamente 30 dias sem anúncios - e pode gerar até 50 QR codes por dia gratuitamente. + @Localizer["LoginAutomaticallyGain"] @Localizer["ThirtyDaysNoAds"] + @Localizer["AndCanGenerate"] @Localizer["FiftyQRCodesPerDay"] @Localizer["ForFree"]

- Não cadastramos você sem sua permissão.
- Política de Privacidade + @Localizer["NoRegisterWithoutPermission"]
+ @Localizer["PrivacyPolicy"]
@@ -68,7 +70,7 @@
diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index 1d84930..38f35d8 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -139,18 +139,18 @@
- +
@@ -159,17 +159,17 @@ {
- + -
PNG, JPG até 2MB
+
@Localizer["PNGJPGUp2MB"]
- +
@@ -181,9 +181,9 @@
@@ -199,7 +199,7 @@
1.2s
- Tempo médio + @Localizer["AverageTime"] @@ -209,7 +209,7 @@
99.9%
- Disponibilidade + @Localizer["Availability"] @@ -219,7 +219,7 @@
10.5K
- QRs gerados hoje + @Localizer["QRsGeneratedToday"] @@ -247,9 +247,9 @@
-

Seu QR code aparecerá aqui em segundos

+

@Localizer["YourQRCodeWillAppear"]

- Geração ultra-rápida garantida + @Localizer["UltraFastGenerationGuaranteed"]
@@ -257,26 +257,26 @@ @@ -366,15 +366,15 @@
- Dicas para QR Mais Rápidos + @Localizer["TipsFasterQR"]
    -
  • URLs curtas geram mais rápido
  • -
  • Menos texto = maior velocidade
  • -
  • Cores sólidas otimizam o processo
  • -
  • Tamanhos menores aceleram o download
  • +
  • @Localizer["ShortURLsFaster"]
  • +
  • @Localizer["LessTextMoreSpeed"]
  • +
  • @Localizer["SolidColorsOptimize"]
  • +
  • @Localizer["SmallerSizesAccelerate"]
@@ -389,8 +389,8 @@
-

Por que QR Rapido é mais rápido?

-

Comparação com outros geradores populares

+

@Localizer["WhyQRRapidoFaster"]

+

@Localizer["ComparisonOtherGenerators"]

@@ -399,7 +399,7 @@
QR Rapido
1.2s
-

Otimizado para velocidade

+

@Localizer["OptimizedForSpeed"]

@@ -407,27 +407,27 @@
-
Concorrente A
+
@Localizer["CompetitorA"]
3.5s
-

Gerador tradicional

+

@Localizer["TraditionalGenerator"]

-
Concorrente B
+
@Localizer["CompetitorB"]
4.8s
-

Interface pesada

+

@Localizer["HeavyInterface"]

-
Concorrente C
+
@Localizer["CompetitorC"]
6.2s
-

Muitos anúncios

+

@Localizer["ManyAds"]

diff --git a/Views/Pagamento/Cancelar.cshtml b/Views/Pagamento/Cancelar.cshtml index fc5ba33..c8277f3 100644 --- a/Views/Pagamento/Cancelar.cshtml +++ b/Views/Pagamento/Cancelar.cshtml @@ -1,12 +1,13 @@ - +@using Microsoft.Extensions.Localization +@inject IStringLocalizer Localizer @{ ViewData["Title"] = "Pagamento Cancelado"; }
-

Pagamento cancelado.

+

@Localizer["PaymentCanceled"]

@ViewBag.CancelMessage

- Ver Planos + @Localizer["ViewPlans"]
diff --git a/Views/Pagamento/SelecaoPlano.cshtml b/Views/Pagamento/SelecaoPlano.cshtml index 51a7585..850f0f4 100644 --- a/Views/Pagamento/SelecaoPlano.cshtml +++ b/Views/Pagamento/SelecaoPlano.cshtml @@ -1,5 +1,6 @@ - +@using Microsoft.Extensions.Localization @model QRRapidoApp.Models.ViewModels.SelecaoPlanoViewModel +@inject IStringLocalizer Localizer @{ ViewData["Title"] = "Escolha seu Plano Premium"; Layout = "~/Views/Shared/_Layout.cshtml"; @@ -12,8 +13,8 @@
-

Desbloqueie o Poder Total do QRRápido

-

Acesso sem limites, sem anúncios e com recursos exclusivos para máxima produtividade.

+

@Localizer["UnlockFullPowerQRRapido"]

+

@Localizer["UnlimitedAccessNoAdsExclusive"]

@@ -23,13 +24,13 @@
-

Plano Mensal

+

@Localizer["MonthlyPlan"]

R$ @monthlyPrice.ToString("0.00") - /mês + @Localizer["PerMonth"]
-

Ideal para começar a explorar os recursos premium.

- +

@Localizer["IdealToStartExploring"]

+
@@ -41,22 +42,22 @@
-

Plano Anual

-

Recomendado

+

@Localizer["AnnualPlan"]

+

@Localizer["Recommended"]

R$ @yearlyPrice.ToString("0.00") - /ano + @Localizer["PerYear"]
@if (yearlySavings > 0) {
- Economize R$ @yearlySavings.ToString("0.00")! + @Localizer["SaveMoney"] @yearlySavings.ToString("0.00")!
} -

O melhor custo-benefício para usuários frequentes.

- +

@Localizer["BestValueFrequentUsers"]

+
@@ -66,13 +67,13 @@
-

Todos os planos incluem:

+

@Localizer["AllPlansInclude"]

    -
  • QR codes ilimitados
  • -
  • Sem anúncios
  • -
  • QR codes dinâmicos
  • -
  • Analytics em tempo real
  • -
  • Suporte prioritário
  • +
  • @Localizer["UnlimitedQRCodes"]
  • +
  • @Localizer["NoAds"]
  • +
  • @Localizer["DynamicQRCodes"]
  • +
  • @Localizer["RealTimeAnalytics"]
  • +
  • @Localizer["PrioritySupport"]
@@ -84,7 +85,7 @@ button.addEventListener('click', async function() { const planId = this.dataset.planId; this.disabled = true; - this.innerHTML = ' Redirecionando...'; + this.innerHTML = ' @Localizer["Redirecting"]'; try { const response = await fetch('/Pagamento/CreateCheckout', { @@ -100,13 +101,13 @@ if (result.success) { window.location.href = result.url; } else { - alert('Erro: ' + result.error); + alert('@Localizer["Error"] ' + result.error); this.disabled = false; - this.innerHTML = 'Assinar Agora'; // Reset button text + this.innerHTML = '@Localizer["SubscribeNow"]'; // Reset button text } } catch (error) { console.error('Checkout error:', error); - alert('Ocorreu um erro ao iniciar o pagamento. Tente novamente.'); + alert('@Localizer["PaymentInitializationError"]'); this.disabled = false; this.innerHTML = 'Assinar Agora'; // Reset button text } diff --git a/Views/Pagamento/Sucesso.cshtml b/Views/Pagamento/Sucesso.cshtml index 243eccb..5eef1c6 100644 --- a/Views/Pagamento/Sucesso.cshtml +++ b/Views/Pagamento/Sucesso.cshtml @@ -1,12 +1,13 @@ - +@using Microsoft.Extensions.Localization +@inject IStringLocalizer Localizer @{ ViewData["Title"] = "Sucesso"; }
-

Pagamento bem-sucedido!

+

@Localizer["PaymentSuccessful"]

@ViewBag.SuccessMessage

- Voltar ao Início + @Localizer["BackToHome"]
diff --git a/Views/Premium/Upgrade.cshtml b/Views/Premium/Upgrade.cshtml index 06dee8c..10998ff 100644 --- a/Views/Premium/Upgrade.cshtml +++ b/Views/Premium/Upgrade.cshtml @@ -1,4 +1,6 @@ @model QRRapidoApp.Models.ViewModels.UpgradeViewModel +@using Microsoft.Extensions.Localization +@inject IStringLocalizer Localizer @{ ViewData["Title"] = "QR Rapido Premium"; } @@ -12,10 +14,10 @@ QR Rapido Premium

- Acelere sua produtividade com o gerador de QR mais rápido do mundo + @Localizer["PremiumAccelerateProductivity"]

- 3x mais rápido que a concorrência + @Localizer["ThreeTimesFaster"]
@@ -25,15 +27,15 @@
-
Status Atual
+
@Localizer["CurrentStatus"]

- Você tem @Model.DaysUntilAdExpiry dias restantes sem anúncios. - Upgrade agora e tenha acesso premium para sempre! + @Localizer["YouHave"] @Model.DaysUntilAdExpiry @Localizer["DaysRemainingNoAds"] + @Localizer["UpgradeNowForever"]

- @Model.DaysUntilAdExpiry dias restantes + @Model.DaysUntilAdExpiry @Localizer["DaysRemaining"]
@@ -48,54 +50,54 @@

QR Rapido Premium

- O plano mais popular + @Localizer["MostPopularPlan"]
R$ @Model.PremiumPrice.ToString("0.00")
-

por mês

+

@Localizer["PerMonth"]

- QR codes ilimitados + @Localizer["UnlimitedQRCodes"]
- Geração ultra-rápida (0.4s) + @Localizer["UltraFastGeneration04s"]
- Sem anúncios para sempre + @Localizer["NoAdsForever"]
- QR codes dinâmicos + @Localizer["DynamicQRCodes"]
- Analytics em tempo real + @Localizer["RealTimeAnalytics"]
- Suporte prioritário + @Localizer["PrioritySupport"]
- API para desenvolvedores + @Localizer["DeveloperAPI"]
- Pagamento seguro via Stripe + @Localizer["SecurePaymentStripe"]
- Cancele quando quiser + @Localizer["CancelAnytime"]
@@ -106,7 +108,7 @@

- Comparação de Planos + @Localizer["PlanComparison"]

@@ -114,39 +116,39 @@ - + - + - + - + - + - + - + - + - + @@ -165,7 +167,7 @@

- Demonstração de Velocidade + @Localizer["SpeedDemonstration"]

@@ -173,9 +175,9 @@
-
Concorrentes
+
@Localizer["Competitors"]
4.5s
-

Tempo médio

+

@Localizer["AverageTime"]

@@ -184,7 +186,7 @@
QR Rapido Free
1.2s
-

3x mais rápido

+

@Localizer["ThreeTimesFaster"]

@@ -193,7 +195,7 @@
QR Rapido Premium
0.4s
-

11x mais rápido!

+

@Localizer["ElevenTimesFaster"]

@@ -205,7 +207,7 @@

- Perguntas Frequentes + @Localizer["FAQ"]

@@ -213,39 +215,36 @@

- Sim! Você pode cancelar sua assinatura a qualquer momento. Não há taxas de cancelamento - e você manterá o acesso premium até o final do período já pago. + @Localizer["CancelAnytimeAnswer"]

- QR codes dinâmicos permitem que você altere o conteúdo do QR após ele ter sido criado, - sem precisar gerar um novo código. Perfeito para campanhas de marketing e uso empresarial. + @Localizer["DynamicQRAnswer"]

- Usuários premium recebem resposta em até 2 horas úteis por email, - acesso ao chat direto e suporte técnico especializado. + @Localizer["PrioritySupportAnswer"]
@@ -287,11 +286,11 @@ window.location.href = result.url; } else { - alert('Erro ao processar pagamento: ' + result.error); + alert('@Localizer["PaymentProcessingError"]' + result.error); } } catch (error) { console.error('Erro:', error); - alert('Erro ao processar pagamento. Tente novamente.'); + alert('@Localizer["PaymentErrorTryAgain"]'); } finally { btn.disabled = false; spinner.classList.add('d-none'); diff --git a/Views/Shared/_AdSpace.cshtml b/Views/Shared/_AdSpace.cshtml index a4e3085..c9c1e95 100644 --- a/Views/Shared/_AdSpace.cshtml +++ b/Views/Shared/_AdSpace.cshtml @@ -1,6 +1,8 @@ @using QRRapidoApp.Services +@using Microsoft.Extensions.Localization @model dynamic @inject AdDisplayService AdService +@inject IStringLocalizer Localizer @{ var userId = User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; var showAds = await AdService.ShouldShowAds(userId); @@ -13,7 +15,7 @@ { case "header":
-
Publicidade
+
@Localizer["Advertisement"]
-
Publicidade
+
@Localizer["Advertisement"]
-
Publicidade
+
@Localizer["Advertisement"]
-
Publicidade
+
@Localizer["Advertisement"]
- ✨ Usuário Premium - Sem anúncios! + @Localizer["PremiumUserNoAds"]
} else @@ -74,9 +76,9 @@ else if (User.Identity.IsAuthenticated)
- Faça upgrade para Premium e remova os anúncios! + @Localizer["UpgradePremiumRemoveAds"] - Premium: Sem anúncios + Histórico + QR ilimitados + @Localizer["PremiumBenefitsShort"]
} diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 545834e..6005cbd 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -80,40 +80,40 @@ @@ -170,11 +170,19 @@
+ +
+ +
+
- 1.2s médio + 1.2s @Localizer["Average"]
@@ -186,13 +194,13 @@
@@ -293,6 +301,40 @@ + + + + @await RenderSectionAsync("Scripts", required: false) diff --git a/wwwroot/css/qrrapido-theme.css b/wwwroot/css/qrrapido-theme.css index 6a58c48..f8af186 100644 --- a/wwwroot/css/qrrapido-theme.css +++ b/wwwroot/css/qrrapido-theme.css @@ -60,18 +60,7 @@ body { } } -/* QR Preview Placeholder */ -.placeholder-qr { - border: 2px dashed #dee2e6; - border-radius: 8px; - transition: all 0.3s ease; - background: #f8f9fa; -} - -.placeholder-qr:hover { - border-color: var(--qr-primary); - background: #e3f2fd; -} +/* QR Preview Placeholder - REMOVIDO: Substituído por versão com melhor contraste */ /* Logo and Branding */ .navbar-brand svg { @@ -155,25 +144,7 @@ body { animation: slideInRight 0.5s ease-out; } -/* Ad Container Styles */ -.ad-container { - text-align: center; - margin: 20px 0; - padding: 15px; - background: #f8f9fa; - border: 1px solid #dee2e6; - border-radius: 8px; - position: relative; -} - -.ad-label { - font-size: 11px; - color: #6c757d; - margin-bottom: 8px; - text-transform: uppercase; - font-weight: 500; - letter-spacing: 0.5px; -} +/* Ad Container Styles - REMOVIDO: Substituído por versão com melhor contraste */ .ad-free-notice { text-align: center; @@ -330,6 +301,64 @@ footer a:hover { background: #0056b3; } +/* ================================= + THEME TOGGLE - BOTÃO ELEGANTE + ================================= */ + +.theme-toggle-container { + margin-left: 8px; +} + +#theme-toggle { + border-color: #6c757d !important; + color: #6c757d !important; + transition: all 0.3s ease; + min-width: 42px; + display: flex; + align-items: center; + justify-content: center; +} + +#theme-toggle:hover { + background-color: #007bff !important; + border-color: #007bff !important; + color: white !important; + transform: translateY(-1px); +} + +#theme-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +#theme-icon { + font-size: 0.875rem; + transition: transform 0.3s ease; +} + +#theme-toggle:hover #theme-icon { + transform: rotate(180deg); +} + +/* Estados do tema */ +[data-theme="light"] #theme-icon { + color: #ffc107; /* Sol amarelo */ +} + +[data-theme="dark"] #theme-icon { + color: #17a2b8; /* Lua azul */ +} + +/* Responsive - esconder texto em telas pequenas */ +@media (max-width: 768px) { + #theme-text { + display: none !important; + } + + .theme-toggle-container { + margin-left: 4px; + } +} + /* Utility Classes */ .text-gradient { background: linear-gradient(135deg, var(--qr-primary) 0%, var(--qr-accent) 100%); @@ -362,22 +391,660 @@ footer a:hover { } } -/* Dark Mode Support (future enhancement) */ -@media (prefers-color-scheme: dark) { +/* ================================= + CORREÇÕES CRÍTICAS DE CONTRASTE E VISIBILIDADE + QR Rapido - Acessibilidade WCAG 2.1 AA + ================================= */ + +/* ================================= + DICAS PARA QR MAIS RÁPIDOS - CORREÇÃO CRÍTICA + ================================= */ + +.card.bg-light { + background-color: #ffffff !important; + border: 1px solid #dee2e6 !important; + box-shadow: 0 2px 4px rgba(0,0,0,0.08); +} + +.card.bg-light .card-header { + background-color: #f8f9fb !important; + color: #212529 !important; + border-bottom: 1px solid #dee2e6; + font-weight: 600; +} + +.card.bg-light .card-body { + background-color: #ffffff !important; + color: #212529 !important; +} + +.card.bg-light .text-muted { + color: #495057 !important; /* Mais escuro para melhor contraste */ +} + +/* ================================= + CONTENT HINTS - VISIBILIDADE GARANTIDA + ================================= */ + +#content-hints, .form-text { + color: #495057 !important; + font-weight: 500; + background: rgba(0, 123, 255, 0.05); + padding: 6px 12px; + border-radius: 4px; + border-left: 3px solid #007bff; + font-size: 0.875rem; + margin-top: 4px; + display: block !important; +} + +/* ================================= + TEXT MUTED - CONTRASTE GLOBAL + ================================= */ + +.text-muted { + color: #495057 !important; /* Mais escuro que o padrão Bootstrap */ +} + +/* ================================= + CARDS DE ESTATÍSTICAS - VISIBILIDADE + ================================= */ + +.card.border-success, .card.border-primary, .card.border-warning { + background: #ffffff; + border-width: 2px !important; + box-shadow: 0 4px 6px rgba(0,0,0,0.08); +} + +.card.border-success .card-body { + background: linear-gradient(145deg, #ffffff 0%, #f0fff4 100%); +} + +.card.border-primary .card-body { + background: linear-gradient(145deg, #ffffff 0%, #eff6ff 100%); +} + +.card.border-warning .card-body { + background: linear-gradient(145deg, #ffffff 0%, #fffbeb 100%); +} + +.card .text-success, .card .text-primary, .card .text-warning { + font-weight: 700 !important; +} + +/* ================================= + AD CONTAINERS - NUNCA INVISÍVEL + ================================= */ + +.ad-container { + background: #ffffff !important; + border: 1px solid #dee2e6 !important; + padding: 15px; + text-align: center; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.05); + margin: 20px 0; + position: relative; +} + +.ad-label { + color: #495057 !important; + font-size: 0.75rem; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.5px; + margin-bottom: 8px; +} + +/* ================================= + PLACEHOLDER QR - CONTRASTE SUPERIOR + ================================= */ + +.placeholder-qr { + border: 2px dashed #007bff !important; + background: #f8f9fb !important; + padding: 40px 20px; + text-align: center; + border-radius: 8px; + transition: all 0.3s ease; +} + +.placeholder-qr:hover { + border-color: #0056b3; + background: #e7f3ff; +} + +.placeholder-qr .text-muted { + color: #495057 !important; +} + +/* ================================= + BOTÕES - MANTENDO IDENTIDADE AZUL + ================================= */ + +.btn-primary { + background-color: #007bff !important; + border-color: #007bff !important; + font-weight: 600; +} + +.btn-primary:hover { + background-color: #0056b3 !important; + border-color: #0056b3 !important; +} + +.btn-outline-primary { + color: #007bff !important; + border-color: #007bff !important; + font-weight: 600; +} + +.btn-outline-primary:hover { + background-color: #007bff !important; + border-color: #007bff !important; + color: #ffffff !important; +} + +/* ================================= + THEME SYSTEM - BASEADO EM DATA-THEME + Tema escuro ativado via data-theme="dark" OU preferência do sistema + ================================= */ + +html[data-theme="dark"] { + /* Base cards */ .card { - background-color: #2d3748; - color: #e2e8f0; + background-color: #2d3748 !important; + color: #e2e8f0 !important; + border-color: #4a5568 !important; } + /* Card Dicas para QR Mais Rápidos */ + .card.bg-light { + background-color: #2d3748 !important; + border-color: #4a5568 !important; + color: #e2e8f0 !important; + } + + .card.bg-light .card-header { + background-color: #4a5568 !important; + color: #e2e8f0 !important; + border-bottom-color: #718096; + } + + .card.bg-light .card-body { + background-color: #2d3748 !important; + color: #e2e8f0 !important; + } + + .card.bg-light .text-muted { + color: #cbd5e0 !important; + } + + .card.bg-light .list-unstyled li { + color: #e2e8f0 !important; + } + + /* Content Hints - Dark Mode */ + #content-hints, .form-text { + color: #e2e8f0 !important; + background: rgba(66, 153, 225, 0.15); + border-left-color: #4dabf7; + } + + /* Text Muted - Dark Mode */ + .text-muted { + color: #cbd5e0 !important; + } + + .small.text-muted, small.text-muted { + color: #a0aec0 !important; + } + + /* Cards Estatísticas - Dark Mode */ + .card.border-success, .card.border-primary, .card.border-warning { + background-color: #2d3748 !important; + border-color: inherit !important; + color: #e2e8f0 !important; + } + + .card.border-success .card-body, + .card.border-primary .card-body, + .card.border-warning .card-body { + background: #2d3748 !important; + color: #e2e8f0 !important; + } + + .card.border-success { + border-color: #48bb78 !important; + } + + .card.border-primary { + border-color: #4dabf7 !important; + } + + .card.border-warning { + border-color: #ed8936 !important; + } + + /* Ad Containers - Dark Mode */ + .ad-container { + background: #2d3748 !important; + border-color: #4a5568 !important; + color: #e2e8f0 !important; + } + + .ad-label { + color: #cbd5e0 !important; + } + + /* Placeholder QR - Dark Mode */ .placeholder-qr { - background: #4a5568; - border-color: #718096; + background: #4a5568 !important; + border-color: #4dabf7 !important; + color: #e2e8f0 !important; } - .form-control, - .form-select { - background-color: #4a5568; - border-color: #718096; + .placeholder-qr:hover { + background: #2d3748; + border-color: #63b3ed; + } + + .placeholder-qr .text-muted { + color: #cbd5e0 !important; + } + + /* Form Controls - Dark Mode Completo */ + .form-control, .form-select { + background-color: #4a5568 !important; + border-color: #718096 !important; + color: #e2e8f0 !important; + } + + .form-control:focus, .form-select:focus { + background-color: #4a5568 !important; + border-color: #4dabf7 !important; + box-shadow: 0 0 0 0.2rem rgba(77, 171, 247, 0.25) !important; + color: #e2e8f0 !important; + } + + .form-control::placeholder { + color: #a0aec0 !important; + opacity: 1; + } + + .form-label { + color: #e2e8f0 !important; + font-weight: 600; + } + + /* Botões - Dark Mode */ + .btn-primary { + background-color: #4dabf7 !important; + border-color: #4dabf7 !important; + } + + .btn-primary:hover { + background-color: #3182ce !important; + border-color: #3182ce !important; + } + + /* Body e elementos base */ + body { + background-color: #1a202c !important; + color: #e2e8f0 !important; + } + + /* Navbar dark mode */ + .navbar-light { + background-color: #2d3748 !important; + border-bottom-color: #4a5568 !important; + } + + .navbar-light .navbar-brand { + color: #e2e8f0 !important; + } + + /* Dropdown menus escuro */ + .btn-outline-secondary { + background-color: #4a5568 !important; + border-color: #718096 !important; + color: #e2e8f0 !important; + } + + .btn-outline-secondary:hover { + background-color: #4dabf7 !important; + border-color: #4dabf7 !important; + color: #ffffff !important; + } + + /* Links e textos diversos */ + a { + color: #4dabf7 !important; + } + + a:hover { + color: #63b3ed !important; + } + + /* Premium features */ + .premium-feature { + background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%); + border-left-color: #ed8936; color: #e2e8f0; } + + /* Accordion */ + .accordion-button { + background: #4a5568 !important; + color: #e2e8f0 !important; + } + + .accordion-button:not(.collapsed) { + background: #4dabf7 !important; + color: #ffffff !important; + } + + /* Dropdown menus */ + .dropdown-menu { + background-color: #2d3748 !important; + border-color: #4a5568 !important; + } + + .dropdown-item { + color: #e2e8f0 !important; + } + + .dropdown-item:hover { + background-color: #4dabf7 !important; + color: #ffffff !important; + } + + /* Correções adicionais para elementos específicos */ + .small { + color: #a0aec0 !important; + } + + .badge { + background-color: #4a5568 !important; + color: #e2e8f0 !important; + } + + .badge.bg-success { + background-color: #48bb78 !important; + color: #ffffff !important; + } + + .badge.bg-primary { + background-color: #4dabf7 !important; + color: #ffffff !important; + } + + .badge.bg-warning { + background-color: #ed8936 !important; + color: #ffffff !important; + } + + /* Alerts */ + .alert { + background-color: #4a5568 !important; + border-color: #718096 !important; + color: #e2e8f0 !important; + } + + .alert-success { + background-color: #2f855a !important; + border-color: #48bb78 !important; + color: #ffffff !important; + } + + .alert-info { + background-color: #2b6cb0 !important; + border-color: #4dabf7 !important; + color: #ffffff !important; + } + + .alert-warning { + background-color: #c05621 !important; + border-color: #ed8936 !important; + color: #ffffff !important; + } + + /* Tables */ + .table { + background-color: #2d3748 !important; + color: #e2e8f0 !important; + } + + .table th, .table td { + border-color: #4a5568 !important; + color: #e2e8f0 !important; + } + + .table-hover tbody tr:hover { + background-color: #4a5568 !important; + } + + /* List groups */ + .list-group-item { + background-color: #2d3748 !important; + border-color: #4a5568 !important; + color: #e2e8f0 !important; + } + + /* Progress bars */ + .progress { + background-color: #4a5568 !important; + } + + /* Footer */ + footer { + background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%) !important; + color: #e2e8f0 !important; + } + + footer a { + color: #4dabf7 !important; + } + + footer a:hover { + color: #63b3ed !important; + } + + /* Hero section */ + .bg-gradient-primary { + background: linear-gradient(135deg, #4dabf7 0%, #3182ce 100%) !important; + } + + /* Generation timer e speed badge */ + .generation-timer { + background: #4a5568 !important; + border-color: #4dabf7 !important; + color: #e2e8f0 !important; + } + + .generation-timer.active { + background: #4dabf7 !important; + color: #ffffff !important; + } +} + +/* ================================= + TEMA CLARO EXPLÍCITO + Forçar tema claro mesmo se o sistema estiver escuro + ================================= */ + +html[data-theme="light"] { + /* Body e elementos base */ + body { + background-color: #ffffff !important; + color: #212529 !important; + } + + /* Cards */ + .card { + background-color: #ffffff !important; + color: #212529 !important; + border-color: #dee2e6 !important; + } + + .card.bg-light { + background-color: #ffffff !important; + border-color: #dee2e6 !important; + color: #212529 !important; + } + + .card.bg-light .card-header { + background-color: #f8f9fb !important; + color: #212529 !important; + border-bottom-color: #dee2e6; + } + + .card.bg-light .card-body { + background-color: #ffffff !important; + color: #212529 !important; + } + + .card.bg-light .text-muted { + color: #495057 !important; + } + + /* Text muted */ + .text-muted { + color: #495057 !important; + } + + .small.text-muted, small.text-muted { + color: #6c757d !important; + } + + /* Content hints */ + #content-hints, .form-text { + color: #495057 !important; + background: rgba(0, 123, 255, 0.05); + border-left-color: #007bff; + } + + /* Form controls */ + .form-control, .form-select { + background-color: #ffffff !important; + border-color: #ced4da !important; + color: #495057 !important; + } + + .form-control:focus, .form-select:focus { + border-color: #007bff !important; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25) !important; + color: #495057 !important; + } + + .form-control::placeholder { + color: #6c757d !important; + opacity: 1; + } + + .form-label { + color: #212529 !important; + font-weight: 600; + } + + /* Cards de estatísticas */ + .card.border-success, .card.border-primary, .card.border-warning { + background-color: #ffffff !important; + color: #212529 !important; + } + + .card.border-success .card-body, + .card.border-primary .card-body, + .card.border-warning .card-body { + background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%) !important; + color: #212529 !important; + } + + /* Ad containers */ + .ad-container { + background: #ffffff !important; + border-color: #dee2e6 !important; + color: #212529 !important; + } + + .ad-label { + color: #495057 !important; + } + + /* Placeholder QR */ + .placeholder-qr { + background: #f8f9fb !important; + border-color: #007bff !important; + color: #212529 !important; + } + + .placeholder-qr:hover { + background: #e7f3ff !important; + border-color: #0056b3 !important; + } + + .placeholder-qr .text-muted { + color: #495057 !important; + } + + /* Navbar */ + .navbar-light { + background-color: #ffffff !important; + border-bottom-color: #dee2e6 !important; + } + + .navbar-light .navbar-brand { + color: #212529 !important; + } + + /* Hero section */ + .bg-gradient-primary { + background: linear-gradient(135deg, #007BFF 0%, #0056B3 100%) !important; + } + + /* Links */ + a { + color: #007bff !important; + } + + a:hover { + color: #0056b3 !important; + } + + /* Botões */ + .btn-primary { + background-color: #007bff !important; + border-color: #007bff !important; + } + + .btn-primary:hover { + background-color: #0056b3 !important; + border-color: #0056b3 !important; + } + + /* Generation timer */ + .generation-timer { + background: #f8f9fa !important; + border-color: #007bff !important; + color: #212529 !important; + } + + .generation-timer.active { + background: #007bff !important; + color: #ffffff !important; + } + + /* Footer */ + footer { + background: linear-gradient(135deg, #343A40 0%, #2c3e50 100%) !important; + color: #ffffff !important; + } + + footer a { + color: #007bff !important; + } + + footer a:hover { + color: #0056b3 !important; + } } \ No newline at end of file diff --git a/wwwroot/js/theme-toggle.js b/wwwroot/js/theme-toggle.js new file mode 100644 index 0000000..0b4377e --- /dev/null +++ b/wwwroot/js/theme-toggle.js @@ -0,0 +1,96 @@ +console.log('🎯 Theme toggle script iniciando...'); + +// Aguardar DOM estar pronto +document.addEventListener('DOMContentLoaded', function() { + console.log('🎯 DOM carregado, procurando elementos...'); + + const themeToggle = document.getElementById('theme-toggle'); + const themeIcon = document.getElementById('theme-icon'); + const themeText = document.getElementById('theme-text'); + + console.log('🎯 Elementos encontrados:', { + toggle: !!themeToggle, + icon: !!themeIcon, + text: !!themeText + }); + + if (!themeToggle) { + console.error('❌ Botão theme-toggle não encontrado!'); + return; + } + + // Estado inicial - sempre começar claro + let currentTheme = 'light'; + + function applyTheme(theme) { + console.log('🎯 Aplicando tema:', theme); + + const html = document.documentElement; + const body = document.body; + + if (theme === 'dark') { + // Modo escuro + html.setAttribute('data-theme', 'dark'); + body.classList.add('dark-theme'); + + if (themeIcon) { + themeIcon.className = 'fas fa-moon'; + } + if (themeText) { + themeText.textContent = 'Escuro'; + } + + console.log('🌙 Tema escuro aplicado'); + } else { + // Modo claro + html.setAttribute('data-theme', 'light'); + body.classList.remove('dark-theme'); + + if (themeIcon) { + themeIcon.className = 'fas fa-sun'; + } + if (themeText) { + themeText.textContent = 'Claro'; + } + + console.log('☀️ Tema claro aplicado'); + } + + // Salvar no localStorage + try { + localStorage.setItem('qr-rapido-theme', theme); + console.log('💾 Tema salvo no localStorage:', theme); + } catch (e) { + console.warn('⚠️ Não foi possível salvar no localStorage:', e); + } + + currentTheme = theme; + } + + // Função de toggle + function toggleTheme() { + console.log('🔄 Toggle theme clicado. Tema atual:', currentTheme); + const newTheme = currentTheme === 'light' ? 'dark' : 'light'; + applyTheme(newTheme); + } + + // Event listener + themeToggle.addEventListener('click', function(e) { + e.preventDefault(); + console.log('🖱️ Clique detectado no theme toggle'); + toggleTheme(); + }); + + // Aplicar tema inicial (sempre claro por enquanto) + applyTheme('light'); + + console.log('✅ Theme toggle configurado com sucesso!'); +}); + +// Função global para debug +window.debugTheme = function() { + console.log('🔍 Debug do tema:'); + console.log('- currentTheme:', document.documentElement.getAttribute('data-theme')); + console.log('- localStorage:', localStorage.getItem('qr-rapido-theme')); + console.log('- body classes:', document.body.className); +}; \ No newline at end of file
Recurso@Localizer["Feature"] Free Premium
QR codes por dia@Localizer["QRCodesPerDay"] 50 Ilimitado @Localizer["Unlimited"]
Velocidade de geração@Localizer["GenerationSpeed"] 1.2s 0.4s
Anúncios@Localizer["Ads"] Sem anúncios @Localizer["NoAds"]
QR codes dinâmicos@Localizer["DynamicQRCodes"]
Analytics detalhados@Localizer["DetailedAnalytics"]
Suporte prioritário@Localizer["PrioritySupport"]